kryptools 0.9__tar.gz → 0.9.2__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 → kryptools-0.9.2}/PKG-INFO +1 -1
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/__init__.py +3 -3
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/factor.py +35 -4
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/la.py +7 -7
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/lat.py +4 -2
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/nt.py +22 -3
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/primes.py +18 -6
- {kryptools-0.9 → kryptools-0.9.2}/kryptools.egg-info/PKG-INFO +1 -1
- {kryptools-0.9 → kryptools-0.9.2}/pyproject.toml +1 -1
- {kryptools-0.9 → kryptools-0.9.2}/LICENSE +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/README.md +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/Zmod.py +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/dlp.py +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/dlp_bsgs.py +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/dlp_ic.py +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/dlp_qs.py +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/dlp_rho.py +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/ec.py +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/factor_dix.py +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/factor_ecm.py +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/factor_fmt.py +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/factor_pm1.py +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/factor_qs.py +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools/poly.py +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools.egg-info/SOURCES.txt +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools.egg-info/dependency_links.txt +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/kryptools.egg-info/top_level.txt +0 -0
- {kryptools-0.9 → kryptools-0.9.2}/setup.cfg +0 -0
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Implemenation of same basic algorithms used in cryptography.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from .nt import egcd, cf, convergents, legendre_symbol, jacobi_symbol, sqrt_mod, euler_phi, carmichael_lambda, order, crt
|
|
6
|
-
from .primes import sieve_eratosthenes, is_prime, next_prime, random_prime, random_strongprime, is_safeprime, random_safeprime
|
|
7
|
-
from .factor import factorint
|
|
5
|
+
from .nt import egcd, cf, convergents, legendre_symbol, jacobi_symbol, sqrt_mod, euler_phi, carmichael_lambda, moebius_mu, order, crt
|
|
6
|
+
from .primes import sieve_eratosthenes, is_prime, next_prime, previous_prime, random_prime, random_strongprime, is_safeprime, random_safeprime
|
|
7
|
+
from .factor import factorint, divisors
|
|
8
8
|
from .dlp import dlog
|
|
9
9
|
from .ec import EC_Weierstrass
|
|
10
10
|
from .la import Matrix, zeros, eye
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Factorization of integers:
|
|
3
3
|
factorint(n) factorize the integer n into prime factors
|
|
4
|
+
divisors(n) unsorted list of all divisors of the integer n
|
|
4
5
|
"""
|
|
5
6
|
|
|
6
|
-
from math import isqrt, gcd
|
|
7
|
+
from math import isqrt, gcd, prod
|
|
7
8
|
from .primes import sieve_eratosthenes, is_prime
|
|
8
9
|
from .factor_pm1 import _pm1_parameters, factor_pm1
|
|
9
10
|
from .factor_ecm import _ecm_parameters, factor_ecm
|
|
@@ -13,7 +14,6 @@ from .factor_ecm import _ecm_parameters, factor_ecm
|
|
|
13
14
|
# Factoring
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
|
|
17
17
|
def _factor_fermat(n: int, steps: int = 10) -> list:
|
|
18
18
|
"Fermat method"
|
|
19
19
|
parameters = {11: (12, 6), 23: (12, 0),
|
|
@@ -29,12 +29,12 @@ def _factor_fermat(n: int, steps: int = 10) -> list:
|
|
|
29
29
|
return a - b
|
|
30
30
|
|
|
31
31
|
def factorint(n: int, verbose: int = 0) -> dict:
|
|
32
|
-
"Factor
|
|
32
|
+
"Factor an ineger `n` into prime factors."
|
|
33
33
|
prime_factors = {}
|
|
34
34
|
if not isinstance(n, int):
|
|
35
35
|
raise ValueError("Number to be factored must be an integer!")
|
|
36
36
|
if n == 0:
|
|
37
|
-
return
|
|
37
|
+
return {0: 1}
|
|
38
38
|
if n < 0:
|
|
39
39
|
n *= -1
|
|
40
40
|
prime_factors[-1] = 1
|
|
@@ -140,3 +140,34 @@ def factorint(n: int, verbose: int = 0) -> dict:
|
|
|
140
140
|
return prime_factors
|
|
141
141
|
|
|
142
142
|
raise ValueError("Incomplete factorization:", prime_factors, remaining_factors, new_factors)
|
|
143
|
+
|
|
144
|
+
# Divisors
|
|
145
|
+
|
|
146
|
+
def divisors(n:int, proper:bool = False) -> int:
|
|
147
|
+
"""Returns an unsorted list of all divisors of an integer `n`."""
|
|
148
|
+
facctordict= factorint(n)
|
|
149
|
+
primes = [p for p in facctordict]
|
|
150
|
+
nprimes = len(primes)
|
|
151
|
+
multiplicites = [facctordict[p] for p in primes]
|
|
152
|
+
|
|
153
|
+
exponents = [0] * nprimes
|
|
154
|
+
if proper:
|
|
155
|
+
divisors = []
|
|
156
|
+
else:
|
|
157
|
+
divisors = [1]
|
|
158
|
+
i = 0
|
|
159
|
+
while True:
|
|
160
|
+
exponents[i] += 1
|
|
161
|
+
if exponents[i] > multiplicites[i]:
|
|
162
|
+
while exponents[i] > multiplicites[i]:
|
|
163
|
+
exponents[i] = 0
|
|
164
|
+
i += 1
|
|
165
|
+
exponents[i] += 1
|
|
166
|
+
i = 0
|
|
167
|
+
d = prod(primes[i] ** exponents[i] for i in range(nprimes))
|
|
168
|
+
if d == n:
|
|
169
|
+
if proper:
|
|
170
|
+
return divisors
|
|
171
|
+
divisors.append(n)
|
|
172
|
+
return divisors
|
|
173
|
+
divisors.append(d)
|
|
@@ -211,7 +211,7 @@ class Matrix:
|
|
|
211
211
|
|
|
212
212
|
def det(self) -> int:
|
|
213
213
|
"Compute the determinant of a matrix M."
|
|
214
|
-
if self.rows != self.
|
|
214
|
+
if self.rows != self.cols:
|
|
215
215
|
raise ValueError("Matrix must be square!")
|
|
216
216
|
n, m = self.cols, self.rows
|
|
217
217
|
R = self[:, :]
|
|
@@ -239,7 +239,7 @@ class Matrix:
|
|
|
239
239
|
|
|
240
240
|
def inv(self) -> "Matrix":
|
|
241
241
|
"Compute the inverse of a square matrix M."
|
|
242
|
-
if self.rows != self.
|
|
242
|
+
if self.rows != self.cols:
|
|
243
243
|
raise ValueError("Matrix must be square!")
|
|
244
244
|
n = self.cols
|
|
245
245
|
MM = Matrix([[0 for _ in range(2*n)] for _ in range(n)])
|
|
@@ -253,7 +253,7 @@ class Matrix:
|
|
|
253
253
|
|
|
254
254
|
def is_unimodular(self) -> bool:
|
|
255
255
|
"Test if the matrix is unimodular."
|
|
256
|
-
if self.rows != self.
|
|
256
|
+
if self.rows != self.cols:
|
|
257
257
|
return False
|
|
258
258
|
def is_integer(i):
|
|
259
259
|
if isinstance(i, int) or (isinstance(i, Fraction) and i.denominator == 1):
|
|
@@ -262,7 +262,7 @@ class Matrix:
|
|
|
262
262
|
return all([is_integer(i) for i in self]) and self.det()**2 == 1
|
|
263
263
|
|
|
264
264
|
def zeros(self, m: int = None, n: int = None):
|
|
265
|
-
"Returns a zero matrix of the same dimension"
|
|
265
|
+
"Returns a zero matrix of the same dimension."
|
|
266
266
|
if not m and not n:
|
|
267
267
|
n, m = self.cols, self.rows
|
|
268
268
|
elif not n:
|
|
@@ -274,7 +274,7 @@ class Matrix:
|
|
|
274
274
|
return Matrix([[ zero for j in range(n) ] for i in range(m) ])
|
|
275
275
|
|
|
276
276
|
def eye(self, m: int = None, n: int = None):
|
|
277
|
-
"Returns an identity matrix of the same dimension"
|
|
277
|
+
"Returns an identity matrix of the same dimension."
|
|
278
278
|
def delta(i, j):
|
|
279
279
|
if i == j:
|
|
280
280
|
return one
|
|
@@ -292,13 +292,13 @@ class Matrix:
|
|
|
292
292
|
|
|
293
293
|
|
|
294
294
|
def zeros(m: int, n: int = None, zero = 0) -> "Matrix":
|
|
295
|
-
"Returns a zero matrix of the given dimension"
|
|
295
|
+
"Returns a zero matrix of the given dimension."
|
|
296
296
|
if not n:
|
|
297
297
|
n = m
|
|
298
298
|
return Matrix([[ zero for j in range(n) ] for i in range(m) ])
|
|
299
299
|
|
|
300
300
|
def eye(m:int, n: int = None) -> "Matrix":
|
|
301
|
-
"Returns an identity matrix of the given dimension"
|
|
301
|
+
"Returns an identity matrix of the given dimension."
|
|
302
302
|
def delta(i, j):
|
|
303
303
|
if i == j:
|
|
304
304
|
return 1
|
|
@@ -42,6 +42,8 @@ def hermite_nf(M: Matrix) -> Matrix:
|
|
|
42
42
|
H[:, jj] -= tmp * H[:, j]
|
|
43
43
|
#print(H)
|
|
44
44
|
j -= 1
|
|
45
|
+
if j < 0:
|
|
46
|
+
break
|
|
45
47
|
while H.cols> 1 and all(not H[i, 0] for i in range(m)): # remove zero columns
|
|
46
48
|
H = H[:,1:]
|
|
47
49
|
return H
|
|
@@ -79,7 +81,7 @@ def babai_round_cvp(x: Matrix, U: Matrix) -> Matrix:
|
|
|
79
81
|
return U * k
|
|
80
82
|
|
|
81
83
|
def babai_round_bnd(U: Matrix) -> float:
|
|
82
|
-
"Bound for Babai's rounding algorithm for solving the
|
|
84
|
+
"Bound for Babai's rounding algorithm for solving the CVPwith respect to the sup norm."
|
|
83
85
|
return floor(1 / (2 * max([ U.inv()[i,:].norm(1) for i in range(U.rows)])))
|
|
84
86
|
|
|
85
87
|
def babai_plane_cvp(x: Matrix, U: Matrix) -> Matrix:
|
|
@@ -91,7 +93,7 @@ def babai_plane_cvp(x: Matrix, U: Matrix) -> Matrix:
|
|
|
91
93
|
return (x - y).applyfunc(round)
|
|
92
94
|
|
|
93
95
|
def babai_plane_bnd(U: Matrix, p = 2) -> float:
|
|
94
|
-
"Bound for Babai's closest plane algorithm for solving the CVP."
|
|
96
|
+
"Bound for Babai's closest plane algorithm for solving the CVP with respect to the Euclidean norm (p=2) or sup norm (p=inf)."
|
|
95
97
|
Us = gram_schmidt(U)[0]
|
|
96
98
|
return float(0.5 * min([Us[:, i].norm(p) for i in range(Us.rows)]))
|
|
97
99
|
|
|
@@ -8,6 +8,7 @@ Number theory tools:
|
|
|
8
8
|
sqrt_mod(n, p) square root of n modulo a prime p
|
|
9
9
|
euler_phi(n) Euler phi function of n
|
|
10
10
|
carmichael_lambda(n) Carmichael lambda function of n
|
|
11
|
+
moebius_mu(n) Moebius function of n
|
|
11
12
|
order(a, n) oder of a in the multiplicative group Z_n^*
|
|
12
13
|
crt([a1, a2, ...],[m1, m2, ...]) Chinese Remainder Theorem
|
|
13
14
|
"""
|
|
@@ -99,7 +100,7 @@ def jacobi_symbol(a: int, n: int) -> int:
|
|
|
99
100
|
return 0
|
|
100
101
|
|
|
101
102
|
def sqrt_mod(a: int, p: int) -> int:
|
|
102
|
-
"Compute a square root of `a` modulo `p` unsing Cipolla's algorithm."
|
|
103
|
+
"""Compute a square root of `a` modulo `p` unsing Cipolla's algorithm."""
|
|
103
104
|
a %= p
|
|
104
105
|
if a == 0 or a == 1:
|
|
105
106
|
return a
|
|
@@ -125,19 +126,23 @@ def sqrt_mod(a: int, p: int) -> int:
|
|
|
125
126
|
i = i >> 1 # i= i/2
|
|
126
127
|
return y1
|
|
127
128
|
|
|
128
|
-
# Euler phi
|
|
129
|
+
# Euler phi, Carmichael function, Moebius function
|
|
129
130
|
|
|
130
131
|
from .factor import factorint
|
|
131
132
|
|
|
132
133
|
|
|
133
134
|
def euler_phi(n: int) -> int:
|
|
134
135
|
"""Euler's phi function of `n`."""
|
|
136
|
+
if not isinstance(n, int) or n < 1:
|
|
137
|
+
raise ValueError(f"{n} is not a positive integer")
|
|
135
138
|
k = factorint(n)
|
|
136
139
|
return prod([(p - 1) * p ** (k[p] - 1) for p in k])
|
|
137
140
|
|
|
138
141
|
|
|
139
142
|
def carmichael_lambda(n: int) -> int:
|
|
140
143
|
"""Carmichael's lambda function of `n`."""
|
|
144
|
+
if not isinstance(n, int) or n < 1:
|
|
145
|
+
raise ValueError(f"{n} is not a positive integer")
|
|
141
146
|
k = factorint(n)
|
|
142
147
|
lam_all = [] # values corresponding to the prime factors
|
|
143
148
|
for p in k:
|
|
@@ -150,12 +155,26 @@ def carmichael_lambda(n: int) -> int:
|
|
|
150
155
|
lam = lcm(lam, l)
|
|
151
156
|
return lam
|
|
152
157
|
|
|
158
|
+
def moebius_mu(n: int) -> int:
|
|
159
|
+
"""Moebius' mu function of `n`."""
|
|
160
|
+
if not isinstance(n, int) or n < 0:
|
|
161
|
+
raise ValueError(f"{n} is not a nonegative integer")
|
|
162
|
+
if n == 0:
|
|
163
|
+
return 0
|
|
164
|
+
factors = factorint(n)
|
|
165
|
+
if any(i > 1 for i in factors.values()):
|
|
166
|
+
return 0
|
|
167
|
+
if len(factors) % 2 == 1:
|
|
168
|
+
return -1
|
|
169
|
+
return 1
|
|
170
|
+
|
|
153
171
|
# Order in Z_p^*
|
|
154
172
|
|
|
155
173
|
def order(a: int, n: int, factor=False) -> int:
|
|
156
174
|
"""Compute the order of `a` in the group Z_n^*."""
|
|
157
175
|
a %= n
|
|
158
|
-
|
|
176
|
+
if a == 0 or gcd(a, n) != 1:
|
|
177
|
+
raise ValueError(f"{a} and {n} are not coprime!")
|
|
159
178
|
factors = {} # We compute euler_phi(n) and its factorization in one pass
|
|
160
179
|
for p, k in factorint(n).items(): # first factorize n
|
|
161
180
|
for pm, km in factorint(p - 1).items(): # factor p-1 and add the factors
|
|
@@ -3,6 +3,7 @@ Tools for prime numbers:
|
|
|
3
3
|
sieve_eratosthenes(B) a tuple of all primes up to including B
|
|
4
4
|
is_prime(n) test if n is probably prime
|
|
5
5
|
next_prime(n) find the next prime larger or equal n
|
|
6
|
+
previous_prime(n) find the previous prime smaller or equal n
|
|
6
7
|
random_prime(l) find a pseudorandom prime with bit length at least l
|
|
7
8
|
random_strongprime(l) find a pseudorandom strong prime with bit length at least l
|
|
8
9
|
is_safeprime(n) test if n is a safe prime
|
|
@@ -17,14 +18,14 @@ from .nt import jacobi_symbol
|
|
|
17
18
|
|
|
18
19
|
def sieve_eratosthenes(B: int) -> tuple:
|
|
19
20
|
"""Returns a tuple of all primes up to (including) `B`."""
|
|
20
|
-
B1 = (isqrt(B) -1)//2
|
|
21
|
+
B1 = (isqrt(B) - 1)//2
|
|
21
22
|
B = (B - 1)//2
|
|
22
|
-
isprime = [True] * (B + 1) # to begin with, all numbers are potentially prime
|
|
23
|
-
# sieve out the primes p=2*q+1 starting at
|
|
23
|
+
isprime = [True] * (B + 1) # to begin with, all odd numbers are potentially prime
|
|
24
|
+
# sieve out the primes p=2*q+1 starting at q = 1
|
|
24
25
|
for q in range(1, B1 + 1):
|
|
25
|
-
if isprime[q]: # sieve out all multiples; numbers p*
|
|
26
|
-
qq =
|
|
27
|
-
p =
|
|
26
|
+
if isprime[q]: # sieve out all multiples; numbers p*r with r<p were already sieved out previously
|
|
27
|
+
qq = 2 * q * (q + 1)
|
|
28
|
+
p = 2 * q + 1
|
|
28
29
|
isprime[qq :: p] = [False] * ((B - qq) // p + 1)
|
|
29
30
|
|
|
30
31
|
return tuple([2] + [2 * q + 1 for q in range(1, B + 1) if isprime[q]])
|
|
@@ -67,11 +68,22 @@ def is_prime(n: int) -> bool:
|
|
|
67
68
|
|
|
68
69
|
def next_prime(n: int) -> int:
|
|
69
70
|
"""Find the next prime larger or equal `n`."""
|
|
71
|
+
if n < 3:
|
|
72
|
+
return 2
|
|
70
73
|
n |= 1 # make sure n is odd
|
|
71
74
|
while not is_prime(n):
|
|
72
75
|
n += 2
|
|
73
76
|
return n
|
|
74
77
|
|
|
78
|
+
def previous_prime(n: int) -> int:
|
|
79
|
+
"""Find the previous prime smaller or equal `n`."""
|
|
80
|
+
if n < 3:
|
|
81
|
+
return 2
|
|
82
|
+
n += (n & 1) - 1 # make sure n is odd
|
|
83
|
+
while not is_prime(n):
|
|
84
|
+
n -= 2
|
|
85
|
+
return n
|
|
86
|
+
|
|
75
87
|
def random_prime(l: int) -> int:
|
|
76
88
|
"""Find a pseudorandom prime with bit length at least `l`."""
|
|
77
89
|
return next_prime(randint(2 ** (l - 1), 2**l - 1))
|
|
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
|