diff --git a/doc/kryptools.ipynb b/doc/kryptools.ipynb index f677c36..ca6d32b 100644 --- a/doc/kryptools.ipynb +++ b/doc/kryptools.ipynb @@ -359,7 +359,6 @@ ], "source": [ "from fractions import Fraction\n", - "\n", "from kryptools import cf, convergents\n", "\n", "cf(Fraction(18, 23))" @@ -411,7 +410,7 @@ { "data": { "text/plain": [ - "-1" + "1" ] }, "execution_count": 13, @@ -422,7 +421,7 @@ "source": [ "from kryptools import jacobi_symbol\n", "\n", - "jacobi_symbol(3, 7)" + "jacobi_symbol(4, 7)" ] }, { @@ -493,7 +492,7 @@ "id": "76fb4f61-d902-4432-92c9-7383c4e068cd", "metadata": {}, "source": [ - "To compute the order of a element of the [multiplicative group of integers modulo $n$](https://en.wikipedia.org/wiki/Multiplicative_group_of_integers_modulo_n), $\\mathbb{Z}_n^*$, use" + "To compute the order of an element of the [multiplicative group of integers modulo $n$](https://en.wikipedia.org/wiki/Multiplicative_group_of_integers_modulo_n), $\\mathbb{Z}_n^*$, use" ] }, { @@ -1558,6 +1557,14 @@ " return Poly(c, ring = gf, modulus = kyber(n))" ] }, + { + "cell_type": "markdown", + "id": "49847633-a975-4537-9ddd-9fc49b898dce", + "metadata": {}, + "source": [ + "The matrix" + ] + }, { "cell_type": "code", "execution_count": 47, @@ -1577,12 +1584,21 @@ } ], "source": [ - "Matrix(\n", + "A = Matrix(\n", " [\n", " [PolyKyber([randint(0, p - 1) for _ in range(n)]) for i in range(k)]\n", " for j in range(k)\n", " ]\n", - ")" + ")\n", + "A" + ] + }, + { + "cell_type": "markdown", + "id": "2fdfe1e9-2cd4-4725-afa7-08b195d3b1c6", + "metadata": {}, + "source": [ + "The small solution" ] }, { @@ -1594,7 +1610,8 @@ { "data": { "text/plain": [ - "[ x^3 + x + 96, 96 x^2 + x + 1 ]" + "[ x^3 + x + 96 ]\n", + "[ 96 x^2 + x + 1 ]" ] }, "execution_count": 48, @@ -1603,7 +1620,16 @@ } ], "source": [ - "Matrix([[PolyKyber([randint(-1, 1) for _ in range(n)]) for i in range(k)]])" + "s = Matrix([ PolyKyber([randint(-1,1) for _ in range(n)]) for i in range(k)])\n", + "s" + ] + }, + { + "cell_type": "markdown", + "id": "ce0eed66-9270-4a04-871b-13578cbde26f", + "metadata": {}, + "source": [ + "The error" ] }, { @@ -1615,7 +1641,8 @@ { "data": { "text/plain": [ - "[ 96 x^3 + x + 95, 2 x ]" + "[ 96 x^3 + x + 95 ]\n", + "[ 2 x ]" ] }, "execution_count": 49, @@ -1625,7 +1652,39 @@ ], "source": [ "q = p // (4 * k * n)\n", - "Matrix([[PolyKyber([binomialvariate(2 * q) - q for _ in range(n)]) for i in range(k)]])" + "e = Matrix([PolyKyber([binomialvariate(2 * q) - q for _ in range(n)]) for i in range(k)])\n", + "e" + ] + }, + { + "cell_type": "markdown", + "id": "684f101f-e79f-4a30-90a5-f5dd3a0557eb", + "metadata": {}, + "source": [ + "The inhomogenous vector" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "fabcbecf-cf96-4211-a1e3-ad0f5a337a09", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[ 47 x^3 + 63 x^2 + 60 x + 38 ]\n", + "[ 47 x^3 + 30 x^2 + 42 x + 47 ]" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b = A * s + e\n", + "b" ] }, { @@ -1646,7 +1705,7 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 51, "id": "9b566550-f23c-4fbc-8b7c-63bbee8e0c72", "metadata": {}, "outputs": [ @@ -1685,7 +1744,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 52, "id": "55c29e0c-e0c2-409a-af23-6590fd9cc545", "metadata": {}, "outputs": [ @@ -1695,7 +1754,7 @@ "(113, 91)" ] }, - "execution_count": 51, + "execution_count": 52, "metadata": {}, "output_type": "execute_result" } @@ -1717,7 +1776,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 53, "id": "2a3d8e7d-71b3-4a93-b6cc-803f00432c56", "metadata": {}, "outputs": [ @@ -1727,7 +1786,7 @@ "129" ] }, - "execution_count": 52, + "execution_count": 53, "metadata": {}, "output_type": "execute_result" } @@ -1747,7 +1806,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 54, "id": "bb93b5fc-99c9-4977-8299-9342b84e143d", "metadata": {}, "outputs": [], @@ -1767,7 +1826,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 55, "id": "41e18357-da42-4cd7-bd4e-1c3355f1c69d", "metadata": {}, "outputs": [], @@ -1790,7 +1849,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 56, "id": "af81d5f2-a524-4555-8e74-06a0c9a7ea08", "metadata": {}, "outputs": [ @@ -1801,7 +1860,7 @@ " 0x02449ef2ed30a8deb96e584a08c329adbf1be87ce40f1a0e7b4e86178682c41a9c)" ] }, - "execution_count": 55, + "execution_count": 56, "metadata": {}, "output_type": "execute_result" } @@ -1837,7 +1896,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.2" + "version": "3.12.1" } }, "nbformat": 4, diff --git a/kryptools/poly.py b/kryptools/poly.py index 1366f3b..d49ae40 100644 --- a/kryptools/poly.py +++ b/kryptools/poly.py @@ -83,7 +83,12 @@ def map(self, func): def __add__(self, other: "Poly") -> "Poly": if not isinstance(other, self.__class__): - raise NotImplementedError(f"Cannot add {self} and {other}.") + try: + tmp = self.coeff[:] + tmp[0] += other + return self.__class__(tmp, modulus=self.modulus) + except: + return NotImplemented ls, lo = len(self.coeff), len(other.coeff) if ls < lo: scoeff = self.coeff + (lo - ls) * [0] @@ -98,12 +103,27 @@ def __add__(self, other: "Poly") -> "Poly": modulus = other.modulus return self.__class__([s + o for s, o in zip(scoeff, ocoeff)], modulus=modulus) + def __radd__(self, other: "Poly") -> "Poly": + if not isinstance(other, self.__class__): + try: + tmp = self.coeff[:] + tmp[0] += other + return self.__class__(tmp, modulus=self.modulus) + except: + pass + return NotImplemented + def __neg__(self) -> "Poly": return Poly([-s for s in self.coeff], modulus=self.modulus) def __sub__(self, other: "Poly") -> "Poly": if not isinstance(other, self.__class__): - raise NotImplementedError(f"Cannot subtract {self} and {other}.") + try: + tmp = self.coeff[:] + tmp[0] -= other + return self.__class__(tmp, modulus=self.modulus) + except: + return NotImplemented ls, lo = len(self.coeff), len(other.coeff) if ls < lo: scoeff = self.coeff + (lo - ls) * [0] @@ -118,11 +138,22 @@ def __sub__(self, other: "Poly") -> "Poly": modulus = other.modulus return self.__class__([s - o for s, o in zip(scoeff, ocoeff)], modulus=modulus) + def __rsub__(self, other: "Poly") -> "Poly": + if not isinstance(other, self.__class__): + try: + tmp = self.coeff[:] + tmp[0] -= other + return self.__class__(tmp, modulus=self.modulus) + except: + pass + return NotImplemented + def __mul__(self, other: "Poly") -> "Poly": - if isinstance(other, int): - return Poly([other * s for s in self.coeff]) if not isinstance(other, self.__class__): - raise NotImplementedError(f"Cannot multiply {self} and {other}.") + try: + return Poly([other * s for s in self.coeff]) + except: + return NotImplemented ls, lo = len(self.coeff), len(other.coeff) coeff = [0] * (ls + lo - 1) for k in range(ls + lo - 1):