kryptools 0.9.7__tar.gz → 0.9.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {kryptools-0.9.7 → kryptools-0.9.8}/PKG-INFO +3 -3
- {kryptools-0.9.7 → kryptools-0.9.8}/README.md +1 -1
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/Zmod.py +3 -9
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/__init__.py +6 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/la.py +29 -14
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/poly.py +44 -63
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools.egg-info/PKG-INFO +3 -3
- {kryptools-0.9.7 → kryptools-0.9.8}/pyproject.toml +2 -2
- {kryptools-0.9.7 → kryptools-0.9.8}/LICENSE +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/dlp.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/dlp_bsgs.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/dlp_ic.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/dlp_qs.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/dlp_rho.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/ec.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/factor.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/factor_dix.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/factor_ecm.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/factor_fmt.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/factor_pm1.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/factor_qs.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/factor_rho.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/lat.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/nt.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools/primes.py +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools.egg-info/SOURCES.txt +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools.egg-info/dependency_links.txt +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/kryptools.egg-info/top_level.txt +0 -0
- {kryptools-0.9.7 → kryptools-0.9.8}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: kryptools
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.8
|
|
4
4
|
Summary: Implemenation of same basic algorithms used in cryptography.
|
|
5
5
|
Author-email: Gerald Teschl <gerald.teschl@univie.ac.at>
|
|
6
6
|
Project-URL: Homepage, https://github.com/teschlg/kryptools
|
|
@@ -9,7 +9,7 @@ Project-URL: Docs, https://github.com/teschlg/kryptools/tree/main/doc
|
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
10
|
Classifier: License :: OSI Approved :: MIT License
|
|
11
11
|
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
15
|
|
|
@@ -29,7 +29,7 @@ The tools contained are:
|
|
|
29
29
|
* number theory: sqrt modulo primes, Jacobi/Legendre symbol, Chinese Remainder Theorem, continued fractions, etc.
|
|
30
30
|
* primes: Sieve of Erathostenes, primality tests, generation of random safe/strong primes
|
|
31
31
|
* solvers for discrete logarithms (naive, Pollard rho, Shanks baby step/giant step, index calculus, quadratic sieve)
|
|
32
|
-
* integer factorization (Fermat, Pollard p-1, Lenstra's ECM, Dixon, basic quadratic sieve)
|
|
32
|
+
* integer factorization (Fermat, Pollard p-1, Pollard rho, Lenstra's ECM, Dixon, basic quadratic sieve)
|
|
33
33
|
* elliptic curves (Weierstrass form), group operations, order, discrete logarithms
|
|
34
34
|
* linear algebra: Hermite normal form, Gram-Schmidt
|
|
35
35
|
* lattices: Hadamard ratio, Babai rounding/nearest plane algorithm, lattice reduction (Lenstra-Lenstra-Lovaz)
|
|
@@ -14,7 +14,7 @@ The tools contained are:
|
|
|
14
14
|
* number theory: sqrt modulo primes, Jacobi/Legendre symbol, Chinese Remainder Theorem, continued fractions, etc.
|
|
15
15
|
* primes: Sieve of Erathostenes, primality tests, generation of random safe/strong primes
|
|
16
16
|
* solvers for discrete logarithms (naive, Pollard rho, Shanks baby step/giant step, index calculus, quadratic sieve)
|
|
17
|
-
* integer factorization (Fermat, Pollard p-1, Lenstra's ECM, Dixon, basic quadratic sieve)
|
|
17
|
+
* integer factorization (Fermat, Pollard p-1, Pollard rho, Lenstra's ECM, Dixon, basic quadratic sieve)
|
|
18
18
|
* elliptic curves (Weierstrass form), group operations, order, discrete logarithms
|
|
19
19
|
* linear algebra: Hermite normal form, Gram-Schmidt
|
|
20
20
|
* lattices: Hadamard ratio, Babai rounding/nearest plane algorithm, lattice reduction (Lenstra-Lenstra-Lovaz)
|
|
@@ -119,9 +119,7 @@ class ZmodPoint:
|
|
|
119
119
|
return NotImplemented
|
|
120
120
|
|
|
121
121
|
def __radd__(self, scalar: int) -> "ZmodPoint":
|
|
122
|
-
|
|
123
|
-
return self.__class__(scalar + self.x, self.ring)
|
|
124
|
-
return NotImplemented
|
|
122
|
+
return self + scalar
|
|
125
123
|
|
|
126
124
|
def __neg__(self) -> "ZmodPoint":
|
|
127
125
|
return self.__class__(-self.x, self.ring)
|
|
@@ -139,9 +137,7 @@ class ZmodPoint:
|
|
|
139
137
|
return NotImplemented
|
|
140
138
|
|
|
141
139
|
def __rsub__(self, scalar: int) -> "ZmodPoint":
|
|
142
|
-
|
|
143
|
-
return self.__class__(scalar - self.x, self.ring)
|
|
144
|
-
return NotImplemented
|
|
140
|
+
return (- self) + scalar
|
|
145
141
|
|
|
146
142
|
def __mul__(self, other: "ZmodPoint") -> "ZmodPoint":
|
|
147
143
|
if isinstance(other, self.__class__):
|
|
@@ -153,9 +149,7 @@ class ZmodPoint:
|
|
|
153
149
|
return NotImplemented
|
|
154
150
|
|
|
155
151
|
def __rmul__(self, scalar: int) -> "ZmodPoint":
|
|
156
|
-
|
|
157
|
-
return self.__class__(scalar * self.x, self.ring)
|
|
158
|
-
return NotImplemented
|
|
152
|
+
return self * scalar
|
|
159
153
|
|
|
160
154
|
def __truediv__(self, other: "ZmodPoint") -> "ZmodPoint":
|
|
161
155
|
if isinstance(other, self.__class__):
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
Implemenation of same basic algorithms used in cryptography.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
__author__ = "Gerald Teschl"
|
|
6
|
+
__copyright__ = "Copyright 2024, Gerald Teschl"
|
|
7
|
+
__license__ = "MIT License"
|
|
8
|
+
__version__ = "0.9.8"
|
|
9
|
+
__email__ = "Gerald.Teschl@univie.ac.at"
|
|
10
|
+
|
|
5
11
|
from .nt import egcd, cf, convergents, legendre_symbol, jacobi_symbol, sqrt_mod, euler_phi, carmichael_lambda, moebius_mu, order, crt
|
|
6
12
|
from .primes import sieve_eratosthenes, prime_pi, is_prime, next_prime, previous_prime, random_prime, random_strongprime, is_safeprime, random_safeprime, is_blumprime, random_blumprime, miller_rabin_test, lucas_test
|
|
7
13
|
from .factor import factorint, divisors
|
|
@@ -23,6 +23,9 @@ class Matrix:
|
|
|
23
23
|
self.matrix = matrix
|
|
24
24
|
self.cols = len(matrix[0])
|
|
25
25
|
self.rows = len(matrix)
|
|
26
|
+
for i in range(1, self.rows):
|
|
27
|
+
if len(matrix[i]) != self.cols:
|
|
28
|
+
raise ValueError("All matrix rows must have equal length!")
|
|
26
29
|
if ring:
|
|
27
30
|
self.map(ring)
|
|
28
31
|
|
|
@@ -62,11 +65,11 @@ class Matrix:
|
|
|
62
65
|
cols = i
|
|
63
66
|
else:
|
|
64
67
|
cols = range(self.cols)[j]
|
|
65
|
-
return
|
|
68
|
+
return self.__class__([[self.matrix[i][j] for j in cols] for i in rows])
|
|
66
69
|
if isinstance(item, int):
|
|
67
70
|
i, j = divmod(item, self.cols)
|
|
68
71
|
return self.matrix[i][j]
|
|
69
|
-
return
|
|
72
|
+
return self.__class__([self.matrix[k // self.cols][k % self.cols] for k in range(self.cols * self.rows)[item]])
|
|
70
73
|
|
|
71
74
|
def __setitem__(self, item, value):
|
|
72
75
|
if isinstance(item, tuple):
|
|
@@ -89,15 +92,24 @@ class Matrix:
|
|
|
89
92
|
for i, ii in zip(cols,range(len(cols))):
|
|
90
93
|
for j, jj in zip(rows,range(len(rows))):
|
|
91
94
|
self.matrix[j][i] = value[jj,ii]
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
elif isinstance(item, int):
|
|
96
|
+
i, j = divmod(item, self.cols)
|
|
97
|
+
self.matrix[i][j] = value
|
|
98
|
+
else:
|
|
99
|
+
for k in range(self.cols * self.rows)[item]:
|
|
100
|
+
i, j = divmod(k, self.cols)
|
|
101
|
+
self.matrix[i][j] = value[k]
|
|
95
102
|
|
|
96
103
|
def __eq__(self, other):
|
|
97
104
|
if not isinstance(other, self.__class__):
|
|
98
105
|
return False
|
|
99
|
-
|
|
106
|
+
if self.rows != other.rows or self.cols != other.cols:
|
|
107
|
+
return False
|
|
108
|
+
return any([ self[i] == other[i] for i in range(self.rows * self.cols) ])
|
|
100
109
|
|
|
110
|
+
def __bool__(self):
|
|
111
|
+
return any([ bool(self[i]) for i in range(self.rows * self.cols) ])
|
|
112
|
+
|
|
101
113
|
def map(self, func):
|
|
102
114
|
"Apply a function to all elements in place."
|
|
103
115
|
for row in self.matrix:
|
|
@@ -156,14 +168,14 @@ class Matrix:
|
|
|
156
168
|
if isinstance(other, Matrix):
|
|
157
169
|
if other.cols != self.cols or other.rows != self.rows:
|
|
158
170
|
raise NotImplementedError("Matrix dimensions do not match!")
|
|
159
|
-
return
|
|
171
|
+
return self.__class__([ [ x1 + y1 for x1, y1 in zip(x,y)] for x, y in zip(self.matrix, other.matrix)])
|
|
160
172
|
return NotImplemented
|
|
161
173
|
|
|
162
174
|
def __sub__(self, other) -> "Matrix":
|
|
163
175
|
if isinstance(other, Matrix):
|
|
164
176
|
if other.cols != self.cols or other.rows != self.rows:
|
|
165
177
|
raise NotImplementedError("Matrix dimensions do not match!")
|
|
166
|
-
return
|
|
178
|
+
return self.__class__([ [ x1 - y1 for x1, y1 in zip(x,y)] for x, y in zip(self.matrix, other.matrix)])
|
|
167
179
|
return NotImplemented
|
|
168
180
|
|
|
169
181
|
def __neg__(self) -> "Matrix":
|
|
@@ -176,12 +188,12 @@ class Matrix:
|
|
|
176
188
|
if isinstance(other, Matrix):
|
|
177
189
|
return self.multiply(other)
|
|
178
190
|
if isinstance(other, Number) or type(other) == type(self.matrix[0][0]):
|
|
179
|
-
return
|
|
191
|
+
return self.__class__([ [item * other for item in row] for row in self.matrix ])
|
|
180
192
|
return NotImplemented
|
|
181
193
|
|
|
182
194
|
def __rmul__(self, other) -> "Matrix":
|
|
183
195
|
if isinstance(other, Number) or type(other) == type(self.matrix[0][0]):
|
|
184
|
-
return
|
|
196
|
+
return self.__class__([ [item * other for item in row] for row in self.matrix ])
|
|
185
197
|
return NotImplemented
|
|
186
198
|
|
|
187
199
|
def rref(self) -> "Matrix":
|
|
@@ -242,7 +254,7 @@ class Matrix:
|
|
|
242
254
|
if self.rows != self.cols:
|
|
243
255
|
raise ValueError("Matrix must be square!")
|
|
244
256
|
n = self.cols
|
|
245
|
-
MM =
|
|
257
|
+
MM = self.__class__([[0 for _ in range(2*n)] for _ in range(n)])
|
|
246
258
|
for i in range(n):
|
|
247
259
|
MM[i,n+i] = 1
|
|
248
260
|
MM[:,0:n] = self
|
|
@@ -271,7 +283,7 @@ class Matrix:
|
|
|
271
283
|
zero = 0 * self[0]
|
|
272
284
|
except:
|
|
273
285
|
zero = 0
|
|
274
|
-
return
|
|
286
|
+
return self.__class__([[ zero for j in range(n) ] for i in range(m) ])
|
|
275
287
|
|
|
276
288
|
def eye(self, m: int = None, n: int = None):
|
|
277
289
|
"Returns an identity matrix of the same dimension."
|
|
@@ -287,8 +299,11 @@ class Matrix:
|
|
|
287
299
|
zero = 0 * self[0]
|
|
288
300
|
except:
|
|
289
301
|
zero = 0
|
|
290
|
-
|
|
291
|
-
|
|
302
|
+
try:
|
|
303
|
+
one = zero**0
|
|
304
|
+
except:
|
|
305
|
+
one = 1
|
|
306
|
+
return self.__class__([[ delta(i, j) for j in range(n) ] for i in range(m) ])
|
|
292
307
|
|
|
293
308
|
|
|
294
309
|
def zeros(m: int, n: int = None, zero = 0) -> "Matrix":
|
|
@@ -55,8 +55,9 @@ class Poly:
|
|
|
55
55
|
return "x"
|
|
56
56
|
return "x^" + str(i)
|
|
57
57
|
|
|
58
|
-
if
|
|
58
|
+
if not self:
|
|
59
59
|
return str(self.coeff[0])
|
|
60
|
+
one = self.coeff[0]**0
|
|
60
61
|
plus = ""
|
|
61
62
|
tmp = ""
|
|
62
63
|
coef_range = range(len(self.coeff))
|
|
@@ -66,12 +67,12 @@ class Poly:
|
|
|
66
67
|
s = self.coeff[i]
|
|
67
68
|
if not s:
|
|
68
69
|
continue
|
|
69
|
-
if not s -
|
|
70
|
+
if not s - one and i != 0:
|
|
70
71
|
tmp += plus + prx(i)
|
|
71
72
|
plus = " + "
|
|
72
73
|
continue
|
|
73
74
|
try:
|
|
74
|
-
if s
|
|
75
|
+
if not s + one and i != 0:
|
|
75
76
|
if plus:
|
|
76
77
|
plus = " "
|
|
77
78
|
tmp += plus + "- " + prx(i)
|
|
@@ -96,7 +97,7 @@ class Poly:
|
|
|
96
97
|
def __eq__(self, other):
|
|
97
98
|
if not isinstance(other, self.__class__):
|
|
98
99
|
return False
|
|
99
|
-
return self
|
|
100
|
+
return not bool(self - other)
|
|
100
101
|
|
|
101
102
|
def __bool__(self):
|
|
102
103
|
return bool(self.degree()) or bool(self.coeff[0])
|
|
@@ -116,7 +117,18 @@ class Poly:
|
|
|
116
117
|
def _check_type(self, other):
|
|
117
118
|
return isinstance(other, int) or (isinstance(other, Number) and isinstance(self.coeff[0], Number)) or type(other) == type(self.coeff[0])
|
|
118
119
|
|
|
120
|
+
def _guess_ring(self):
|
|
121
|
+
zero = 0 * self.coeff[0]
|
|
122
|
+
try:
|
|
123
|
+
ring = type(zero)
|
|
124
|
+
one = ring(1)
|
|
125
|
+
except:
|
|
126
|
+
ring = None
|
|
127
|
+
one = zero**0 # zero + 1
|
|
128
|
+
return zero, one, ring
|
|
129
|
+
|
|
119
130
|
def __add__(self, other: "Poly") -> "Poly":
|
|
131
|
+
zero = 0 * self.coeff[0]
|
|
120
132
|
if not isinstance(other, self.__class__):
|
|
121
133
|
if self._check_type(other):
|
|
122
134
|
tmp = self.coeff[:]
|
|
@@ -125,11 +137,11 @@ class Poly:
|
|
|
125
137
|
return NotImplemented
|
|
126
138
|
ls, lo = len(self.coeff), len(other.coeff)
|
|
127
139
|
if ls < lo:
|
|
128
|
-
scoeff = self.coeff + (lo - ls) * [
|
|
140
|
+
scoeff = self.coeff + (lo - ls) * [zero]
|
|
129
141
|
else:
|
|
130
142
|
scoeff = self.coeff
|
|
131
143
|
if ls > lo:
|
|
132
|
-
ocoeff = other.coeff + (ls - lo) * [
|
|
144
|
+
ocoeff = other.coeff + (ls - lo) * [zero]
|
|
133
145
|
else:
|
|
134
146
|
ocoeff = other.coeff
|
|
135
147
|
modulus = self.modulus
|
|
@@ -138,12 +150,7 @@ class Poly:
|
|
|
138
150
|
return self.__class__([s + o for s, o in zip(scoeff, ocoeff)], modulus=modulus)
|
|
139
151
|
|
|
140
152
|
def __radd__(self, other: "Poly") -> "Poly":
|
|
141
|
-
|
|
142
|
-
if self._check_type(other):
|
|
143
|
-
tmp = self.coeff[:]
|
|
144
|
-
tmp[0] += other
|
|
145
|
-
return self.__class__(tmp, modulus=self.modulus)
|
|
146
|
-
return NotImplemented
|
|
153
|
+
return self + other
|
|
147
154
|
|
|
148
155
|
def __neg__(self) -> "Poly":
|
|
149
156
|
return Poly([-s for s in self.coeff], modulus=self.modulus)
|
|
@@ -152,57 +159,33 @@ class Poly:
|
|
|
152
159
|
return self
|
|
153
160
|
|
|
154
161
|
def __sub__(self, other: "Poly") -> "Poly":
|
|
155
|
-
|
|
156
|
-
if self._check_type(other):
|
|
157
|
-
tmp = self.coeff[:]
|
|
158
|
-
tmp[0] -= other
|
|
159
|
-
return self.__class__(tmp, modulus=self.modulus)
|
|
160
|
-
return NotImplemented
|
|
161
|
-
ls, lo = len(self.coeff), len(other.coeff)
|
|
162
|
-
if ls < lo:
|
|
163
|
-
scoeff = self.coeff + (lo - ls) * [0]
|
|
164
|
-
else:
|
|
165
|
-
scoeff = self.coeff
|
|
166
|
-
if ls > lo:
|
|
167
|
-
ocoeff = other.coeff + (ls - lo) * [0]
|
|
168
|
-
else:
|
|
169
|
-
ocoeff = other.coeff
|
|
170
|
-
modulus = self.modulus
|
|
171
|
-
if not modulus and other.modulus:
|
|
172
|
-
modulus = other.modulus
|
|
173
|
-
return self.__class__([s - o for s, o in zip(scoeff, ocoeff)], modulus = modulus)
|
|
162
|
+
return self + (- other)
|
|
174
163
|
|
|
175
164
|
def __rsub__(self, other: "Poly") -> "Poly":
|
|
176
|
-
|
|
177
|
-
if self._check_type(other):
|
|
178
|
-
tmp = self.coeff[:]
|
|
179
|
-
tmp[0] -= other
|
|
180
|
-
return self.__class__(tmp, modulus=self.modulus)
|
|
181
|
-
return NotImplemented
|
|
165
|
+
return (- self) + other
|
|
182
166
|
|
|
183
167
|
def __mul__(self, other: "Poly") -> "Poly":
|
|
184
168
|
if not isinstance(other, self.__class__):
|
|
185
169
|
if self._check_type(other):
|
|
186
170
|
return Poly([other * s for s in self.coeff], modulus = self.modulus)
|
|
187
171
|
return NotImplemented
|
|
172
|
+
zero = 0 * self.coeff[0]
|
|
188
173
|
ls, lo = len(self.coeff), len(other.coeff)
|
|
189
|
-
coeff = [
|
|
174
|
+
coeff = [None] * (ls + lo - 1)
|
|
190
175
|
for k in range(ls + lo - 1):
|
|
191
176
|
coeff[k] = sum(
|
|
192
177
|
[
|
|
193
178
|
self.coeff[j] * other.coeff[k - j]
|
|
194
179
|
for j in range(max(0, k - lo + 1), min(ls, k + 1))
|
|
195
180
|
]
|
|
196
|
-
)
|
|
181
|
+
, start = zero)
|
|
197
182
|
modulus = self.modulus
|
|
198
183
|
if not modulus and other.modulus:
|
|
199
184
|
modulus = other.modulus
|
|
200
185
|
return self.__class__(coeff, modulus = modulus)
|
|
201
186
|
|
|
202
187
|
def __rmul__(self, other) -> "Poly":
|
|
203
|
-
|
|
204
|
-
return self.__class__([other * s for s in self.coeff], modulus=self.modulus)
|
|
205
|
-
return NotImplemented
|
|
188
|
+
return self * other
|
|
206
189
|
|
|
207
190
|
def __truediv__(self, other) -> "Poly":
|
|
208
191
|
if self._check_type(other):
|
|
@@ -221,8 +204,7 @@ class Poly:
|
|
|
221
204
|
def __pow__(self, j: int) -> "Poly":
|
|
222
205
|
if not isinstance(j, int):
|
|
223
206
|
return NotImplemented
|
|
224
|
-
|
|
225
|
-
one = zero + 1
|
|
207
|
+
one = self.coeff[0]**0
|
|
226
208
|
res = self.__class__([one], modulus=self.modulus)
|
|
227
209
|
if j < 0:
|
|
228
210
|
if not self.modulus:
|
|
@@ -256,39 +238,39 @@ class Poly:
|
|
|
256
238
|
|
|
257
239
|
def divmod(self, other: "Poly") -> ("Poly", "Poly"):
|
|
258
240
|
"Polynom division with remainder."
|
|
241
|
+
zero, one, ring = self._guess_ring()
|
|
259
242
|
if isinstance(other, list):
|
|
260
|
-
other = self.__class__(other)
|
|
243
|
+
other = self.__class__(other , ring = ring)
|
|
261
244
|
elif not isinstance(other, self.__class__):
|
|
262
245
|
raise NotImplementedError(f"Cannot divide {self} and {other}.")
|
|
263
246
|
if not other:
|
|
264
247
|
raise ValueError(f"{other} must be nonzero.")
|
|
265
248
|
sd, od = self.degree(), other.degree()
|
|
266
249
|
if sd < od:
|
|
267
|
-
return self.__class__([
|
|
268
|
-
div = [
|
|
250
|
+
return self.__class__([zero]), self
|
|
251
|
+
div = [zero] * (sd - od + 1)
|
|
269
252
|
lco = other.coeff[-1]
|
|
270
|
-
if bool(lco -
|
|
271
|
-
tmp =
|
|
253
|
+
if bool(lco - one):
|
|
254
|
+
tmp = one / lco
|
|
272
255
|
oth = [c * tmp for c in other.coeff]
|
|
273
256
|
rem = [c * tmp for c in self.coeff]
|
|
274
257
|
else:
|
|
275
258
|
oth = other.coeff
|
|
276
|
-
rem = [c for c in self.coeff]
|
|
259
|
+
rem = [c * one for c in self.coeff] # "* 1" is here to make sure we get a copy
|
|
277
260
|
for i in range(sd - od + 1):
|
|
278
|
-
tmp = rem[sd - i]
|
|
261
|
+
tmp = rem[sd - i] * one # "* 1" is here to make sure we get a copy
|
|
279
262
|
div[sd - od - i] = tmp
|
|
280
263
|
for j in range(od + 1):
|
|
281
264
|
rem[sd - i - j] -= tmp * oth[od - j]
|
|
282
|
-
if bool(lco -
|
|
265
|
+
if bool(lco - one):
|
|
283
266
|
rem = [c * lco for c in rem]
|
|
284
|
-
return self.__class__(div, modulus=self.modulus), self.__class__(
|
|
285
|
-
rem, modulus=self.modulus
|
|
286
|
-
)
|
|
267
|
+
return self.__class__(div, modulus=self.modulus), self.__class__(rem, modulus=self.modulus)
|
|
287
268
|
|
|
288
269
|
def mod(self, other: "Poly") -> None:
|
|
289
270
|
"Reduce with respect to a given polynomial."
|
|
271
|
+
one, ring = self._guess_ring()[1:]
|
|
290
272
|
if isinstance(other, list):
|
|
291
|
-
other = self.__class__(other)
|
|
273
|
+
other = self.__class__(other , ring = ring)
|
|
292
274
|
elif not isinstance(other, self.__class__):
|
|
293
275
|
raise NotImplementedError(f"Cannot divide {self} and {other}.")
|
|
294
276
|
if not other:
|
|
@@ -297,13 +279,13 @@ class Poly:
|
|
|
297
279
|
if sd < od:
|
|
298
280
|
return self
|
|
299
281
|
lco = other.coeff[-1]
|
|
300
|
-
if bool(lco -
|
|
301
|
-
tmp =
|
|
282
|
+
if bool(lco - one):
|
|
283
|
+
tmp = one / lco
|
|
302
284
|
oth = [c * tmp for c in other.coeff]
|
|
303
285
|
else:
|
|
304
286
|
oth = other.coeff
|
|
305
287
|
for i in range(sd - od + 1):
|
|
306
|
-
tmp = self.coeff[sd - i]
|
|
288
|
+
tmp = self.coeff[sd - i] * one # "* 1" is here to make sure we get a copy
|
|
307
289
|
for j in range(od + 1):
|
|
308
290
|
self.coeff[sd - i - j] -= tmp * oth[od - j]
|
|
309
291
|
for i in range(len(self.coeff) - 1, 0, -1):
|
|
@@ -315,14 +297,13 @@ class Poly:
|
|
|
315
297
|
"Inverse modulo a given polynomial."
|
|
316
298
|
if not other:
|
|
317
299
|
other = self.modulus
|
|
300
|
+
zero, one, ring = self._guess_ring()
|
|
318
301
|
if isinstance(other, list):
|
|
319
|
-
other = self.__class__(other)
|
|
302
|
+
other = self.__class__(other , ring = ring)
|
|
320
303
|
elif not isinstance(other, self.__class__):
|
|
321
304
|
raise NotImplementedError(f"Cannot invert {self} modulo {other}.")
|
|
322
305
|
if not other:
|
|
323
306
|
raise NotImplementedError(f"{other} must be nonzero.")
|
|
324
|
-
zero = 0 * self.coeff[0]
|
|
325
|
-
one = zero +1
|
|
326
307
|
r0, r1 = other, self
|
|
327
308
|
y0, y1 = self.__class__([zero], modulus=self.modulus), self.__class__([one], modulus=self.modulus)
|
|
328
309
|
while r1:
|
|
@@ -331,7 +312,7 @@ class Poly:
|
|
|
331
312
|
y0, y1 = y1, y0 - q * y1
|
|
332
313
|
if r0.degree() != 0:
|
|
333
314
|
raise ValueError(f"{self} is not invertible mod {other}.")
|
|
334
|
-
tmp =
|
|
315
|
+
tmp = one / r0[0]
|
|
335
316
|
for i in range(len(y0)):
|
|
336
317
|
y0.coeff[i] *= tmp
|
|
337
318
|
return y0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: kryptools
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.8
|
|
4
4
|
Summary: Implemenation of same basic algorithms used in cryptography.
|
|
5
5
|
Author-email: Gerald Teschl <gerald.teschl@univie.ac.at>
|
|
6
6
|
Project-URL: Homepage, https://github.com/teschlg/kryptools
|
|
@@ -9,7 +9,7 @@ Project-URL: Docs, https://github.com/teschlg/kryptools/tree/main/doc
|
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
10
|
Classifier: License :: OSI Approved :: MIT License
|
|
11
11
|
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
15
|
|
|
@@ -29,7 +29,7 @@ The tools contained are:
|
|
|
29
29
|
* number theory: sqrt modulo primes, Jacobi/Legendre symbol, Chinese Remainder Theorem, continued fractions, etc.
|
|
30
30
|
* primes: Sieve of Erathostenes, primality tests, generation of random safe/strong primes
|
|
31
31
|
* solvers for discrete logarithms (naive, Pollard rho, Shanks baby step/giant step, index calculus, quadratic sieve)
|
|
32
|
-
* integer factorization (Fermat, Pollard p-1, Lenstra's ECM, Dixon, basic quadratic sieve)
|
|
32
|
+
* integer factorization (Fermat, Pollard p-1, Pollard rho, Lenstra's ECM, Dixon, basic quadratic sieve)
|
|
33
33
|
* elliptic curves (Weierstrass form), group operations, order, discrete logarithms
|
|
34
34
|
* linear algebra: Hermite normal form, Gram-Schmidt
|
|
35
35
|
* lattices: Hadamard ratio, Babai rounding/nearest plane algorithm, lattice reduction (Lenstra-Lenstra-Lovaz)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "kryptools"
|
|
3
|
-
version = "0.9.
|
|
3
|
+
version = "0.9.8"
|
|
4
4
|
authors = [
|
|
5
5
|
{ name="Gerald Teschl", email="gerald.teschl@univie.ac.at" },
|
|
6
6
|
]
|
|
7
7
|
description = "Implemenation of same basic algorithms used in cryptography."
|
|
8
8
|
readme = "README.md"
|
|
9
|
-
requires-python = ">=3.
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
10
|
classifiers = [
|
|
11
11
|
"Programming Language :: Python :: 3",
|
|
12
12
|
"License :: OSI Approved :: MIT License",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|