kryptools 0.9.3__tar.gz → 0.9.5__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.3 → kryptools-0.9.5}/PKG-INFO +1 -1
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/__init__.py +1 -1
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/poly.py +19 -4
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/primes.py +142 -77
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools.egg-info/PKG-INFO +1 -1
- {kryptools-0.9.3 → kryptools-0.9.5}/pyproject.toml +1 -1
- {kryptools-0.9.3 → kryptools-0.9.5}/LICENSE +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/README.md +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/Zmod.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/dlp.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/dlp_bsgs.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/dlp_ic.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/dlp_qs.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/dlp_rho.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/ec.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/factor.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/factor_dix.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/factor_ecm.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/factor_fmt.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/factor_pm1.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/factor_qs.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/la.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/lat.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/nt.py +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools.egg-info/SOURCES.txt +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools.egg-info/dependency_links.txt +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/kryptools.egg-info/top_level.txt +0 -0
- {kryptools-0.9.3 → kryptools-0.9.5}/setup.cfg +0 -0
|
@@ -3,7 +3,7 @@ Implemenation of same basic algorithms used in cryptography.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
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, prime_pi, is_prime, next_prime, previous_prime, random_prime, random_strongprime, is_safeprime, random_safeprime
|
|
6
|
+
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
7
|
from .factor import factorint, divisors
|
|
8
8
|
from .dlp import dlog
|
|
9
9
|
from .ec import EC_Weierstrass
|
|
@@ -4,6 +4,14 @@ Polynomials
|
|
|
4
4
|
|
|
5
5
|
from numbers import Number
|
|
6
6
|
|
|
7
|
+
display_reversed = True
|
|
8
|
+
|
|
9
|
+
def poly_style_reversed(value: bool = True) -> None:
|
|
10
|
+
"Change the order of the coefficients when displaying polynomials."
|
|
11
|
+
global display_reversed
|
|
12
|
+
display_reversed = value
|
|
13
|
+
|
|
14
|
+
|
|
7
15
|
class Poly:
|
|
8
16
|
"""
|
|
9
17
|
Represents a polynomial as a list of coefficients.
|
|
@@ -40,7 +48,7 @@ class Poly:
|
|
|
40
48
|
return len(self.coeff)
|
|
41
49
|
|
|
42
50
|
def __repr__(self):
|
|
43
|
-
def prx(i: int):
|
|
51
|
+
def prx(i: int) -> str:
|
|
44
52
|
if i == 0:
|
|
45
53
|
return ""
|
|
46
54
|
if i == 1:
|
|
@@ -51,7 +59,10 @@ class Poly:
|
|
|
51
59
|
return str(self.coeff[0])
|
|
52
60
|
plus = ""
|
|
53
61
|
tmp = ""
|
|
54
|
-
|
|
62
|
+
coef_range = range(len(self.coeff))
|
|
63
|
+
if display_reversed:
|
|
64
|
+
coef_range = reversed(coef_range)
|
|
65
|
+
for i in coef_range:
|
|
55
66
|
s = self.coeff[i]
|
|
56
67
|
if not s:
|
|
57
68
|
continue
|
|
@@ -70,11 +81,15 @@ class Poly:
|
|
|
70
81
|
pass
|
|
71
82
|
try:
|
|
72
83
|
if plus and s < 0:
|
|
73
|
-
tmp += " - " + str(-s)
|
|
84
|
+
tmp += " - " + str(-s)
|
|
85
|
+
if i != 0:
|
|
86
|
+
tmp += " " + prx(i)
|
|
74
87
|
continue
|
|
75
88
|
except:
|
|
76
89
|
pass
|
|
77
|
-
tmp += plus + str(s)
|
|
90
|
+
tmp += plus + str(s)
|
|
91
|
+
if i != 0:
|
|
92
|
+
tmp += " " + prx(i)
|
|
78
93
|
plus = " + "
|
|
79
94
|
return tmp.strip()
|
|
80
95
|
|
|
@@ -12,8 +12,12 @@ Tools for prime numbers:
|
|
|
12
12
|
is_blumprime(n) test if n is a Blum prime
|
|
13
13
|
random_blumprime(l) find a pseudorandom Blum prime with bit length at least l
|
|
14
14
|
miller_rabin_test(n, b) Miller-Rabin primality test with base b
|
|
15
|
+
lucas_test(n) strong Lucas test
|
|
16
|
+
perfect_square(n) test if a number is a perfect square
|
|
17
|
+
perfect_power(n) test if a number is a perfect power
|
|
18
|
+
iroot(k, n) integer k'th root of n
|
|
15
19
|
"""
|
|
16
|
-
from math import isqrt, gcd, floor
|
|
20
|
+
from math import isqrt, gcd, floor, ceil
|
|
17
21
|
from random import randint
|
|
18
22
|
from .nt import jacobi_symbol
|
|
19
23
|
|
|
@@ -50,39 +54,168 @@ def miller_rabin_test(n: int, bases: list[int] | int) -> bool:
|
|
|
50
54
|
"""Run a Miller-Rabin test with given bases on `n`."""
|
|
51
55
|
if n < 2:
|
|
52
56
|
return False
|
|
53
|
-
if n % 2 == 0:
|
|
57
|
+
if n % 2 == 0: # make sure n is odd
|
|
54
58
|
return n == 2
|
|
59
|
+
|
|
60
|
+
# write n = m 2^k + 1
|
|
55
61
|
m = (n - 1) // 2
|
|
56
62
|
k = 1
|
|
57
63
|
while m % 2 == 0:
|
|
58
64
|
m //= 2
|
|
59
65
|
k += 1
|
|
66
|
+
|
|
60
67
|
if isinstance(bases, int):
|
|
61
68
|
bases = [bases]
|
|
69
|
+
|
|
62
70
|
for a in bases:
|
|
71
|
+
a %= n
|
|
72
|
+
if a == 0:
|
|
73
|
+
continue
|
|
63
74
|
b = pow(a, m, n)
|
|
64
75
|
if b == 1 or b == n - 1:
|
|
65
|
-
|
|
76
|
+
continue
|
|
66
77
|
for _ in range(1, k):
|
|
67
78
|
b = pow(b, 2, n)
|
|
68
|
-
if b ==
|
|
79
|
+
if b == 0: # n and a are not coprime
|
|
80
|
+
return False
|
|
81
|
+
if b == 1: # 1 before -1
|
|
69
82
|
return False
|
|
70
83
|
if b == n - 1:
|
|
71
|
-
|
|
84
|
+
break
|
|
85
|
+
else: # no -1 found
|
|
86
|
+
return False
|
|
87
|
+
return True
|
|
88
|
+
|
|
89
|
+
def _lucas_sequence(n, D, k):
|
|
90
|
+
"""Evaluate a Lucas sequence."""
|
|
91
|
+
# P = 1
|
|
92
|
+
Q = (1 - D)//4
|
|
93
|
+
U = 1
|
|
94
|
+
V = 1
|
|
95
|
+
Qk = Q
|
|
96
|
+
b = k.bit_length()
|
|
97
|
+
while b > 1:
|
|
98
|
+
U = (U * V) % n
|
|
99
|
+
V = (V * V - 2 * Qk) % n
|
|
100
|
+
Qk *= Qk
|
|
101
|
+
b -= 1
|
|
102
|
+
if (k >> (b - 1)) & 1:
|
|
103
|
+
U, V = U + V, V + U * D
|
|
104
|
+
if U & 1:
|
|
105
|
+
U += n
|
|
106
|
+
if V & 1:
|
|
107
|
+
V += n
|
|
108
|
+
U, V = U >> 1, V >> 1
|
|
109
|
+
Qk *= Q
|
|
110
|
+
Qk %= n
|
|
111
|
+
return U % n, V % n, Qk
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def perfect_square(n: int) -> int|None:
|
|
115
|
+
"""Returns the root if `n` is a perfect square and None else."""
|
|
116
|
+
s = isqrt(n)
|
|
117
|
+
if s*s == n:
|
|
118
|
+
return s
|
|
119
|
+
|
|
120
|
+
def iroot(k: int, n: int) -> int:
|
|
121
|
+
"""Compute the integer k'th root of n."""
|
|
122
|
+
if not isinstance(k, int) or n < 1:
|
|
123
|
+
raise ValueError(f"{k} is not a positive integer")
|
|
124
|
+
if k == 1:
|
|
125
|
+
return n
|
|
126
|
+
if k == 2:
|
|
127
|
+
return isqrt(n)
|
|
128
|
+
rr = isqrt(n)
|
|
129
|
+
r =rr + 1
|
|
130
|
+
k1 = k-1
|
|
131
|
+
while rr < r:
|
|
132
|
+
r = rr
|
|
133
|
+
rr = (k1 * r + n // r ** k1) // k # Newton iteration
|
|
134
|
+
return r
|
|
135
|
+
|
|
136
|
+
def perfect_power(n: int) -> tuple|None:
|
|
137
|
+
"""Returns integers `(m, p)` with `m**p == n` if `n` is a perfect power and None else."""
|
|
138
|
+
for p in sieve_eratosthenes(n.bit_length() - 1):
|
|
139
|
+
m = iroot(p, n)
|
|
140
|
+
if pow(m, p) == n:
|
|
141
|
+
return (m, p)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# https://en.wikipedia.org/wiki/Lucas_pseudoprime#Implementing_a_Lucas_probable_prime_test
|
|
145
|
+
|
|
146
|
+
def lucas_test(n: int) -> bool:
|
|
147
|
+
"""Run a strong Lucas primality test on `n`."""
|
|
148
|
+
if n < 2:
|
|
149
|
+
return False
|
|
150
|
+
if n % 2 == 0:
|
|
151
|
+
return n == 2
|
|
152
|
+
if perfect_square(n) is not None: # the search for D will not succeed in this case
|
|
153
|
+
return False
|
|
154
|
+
|
|
155
|
+
# write n = k 2^s - 1
|
|
156
|
+
k = (n + 1) // 2
|
|
157
|
+
s = 1
|
|
158
|
+
while k % 2 == 0:
|
|
159
|
+
k //= 2
|
|
160
|
+
s += 1
|
|
161
|
+
|
|
162
|
+
# Selfridge method for choosing D
|
|
163
|
+
|
|
164
|
+
D = 5
|
|
165
|
+
while True:
|
|
166
|
+
g = gcd(abs(D), n)
|
|
167
|
+
if 1 < g < n:
|
|
168
|
+
return False
|
|
169
|
+
if jacobi_symbol(D, n) == -1:
|
|
170
|
+
break
|
|
171
|
+
if D > 0:
|
|
172
|
+
D = -D - 2
|
|
173
|
+
else:
|
|
174
|
+
D = -D + 2
|
|
175
|
+
|
|
176
|
+
U, V, Qk = _lucas_sequence(n, D, k)
|
|
177
|
+
|
|
178
|
+
if U == 0 or V == 0:
|
|
179
|
+
return True
|
|
180
|
+
for _ in range(1, s):
|
|
181
|
+
V = (V*V - 2*Qk) % n
|
|
182
|
+
if V == 0:
|
|
183
|
+
return True
|
|
184
|
+
Qk = pow(Qk, 2, n)
|
|
72
185
|
return False
|
|
73
186
|
|
|
74
187
|
def is_prime(n: int) -> bool:
|
|
75
188
|
"""Test if an integer `n` if probable prime."""
|
|
189
|
+
# Test small primes
|
|
190
|
+
for p in (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
|
|
191
|
+
101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
|
|
192
|
+
211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293,
|
|
193
|
+
307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397):
|
|
194
|
+
if n % p == 0:
|
|
195
|
+
return n == p
|
|
76
196
|
if n < 18446744073709551616: # https://miller-rabin.appspot.com
|
|
77
197
|
return miller_rabin_test(n, [2, 325, 9375, 28178, 450775, 9780504, 1795265022])
|
|
78
198
|
if n < 3317044064679887385961981:
|
|
79
199
|
return miller_rabin_test(n, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41])
|
|
80
|
-
return miller_rabin_test(n, [2]) and
|
|
200
|
+
return miller_rabin_test(n, [2]) and lucas_test(n) # Baillie–PSW primality test
|
|
201
|
+
|
|
202
|
+
def is_safeprime(p: int) -> bool:
|
|
203
|
+
"""Tests if a number is a safe prime."""
|
|
204
|
+
return is_prime(p) and is_prime((p - 1) // 2)
|
|
205
|
+
|
|
206
|
+
def is_blumprime(p: int) -> bool:
|
|
207
|
+
"""Tests if a number is a Blum prime."""
|
|
208
|
+
return p % 4 == 3 and is_prime(p)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
# Generation of primes
|
|
212
|
+
|
|
81
213
|
|
|
82
214
|
def next_prime(n: int) -> int:
|
|
83
215
|
"""Find the next prime larger or equal `n`."""
|
|
84
216
|
if n < 3:
|
|
85
217
|
return 2
|
|
218
|
+
n = ceil(n)
|
|
86
219
|
n |= 1 # make sure n is odd
|
|
87
220
|
while not is_prime(n):
|
|
88
221
|
n += 2
|
|
@@ -92,6 +225,7 @@ def previous_prime(n: int) -> int:
|
|
|
92
225
|
"""Find the previous prime smaller or equal `n`."""
|
|
93
226
|
if n < 3:
|
|
94
227
|
return 2
|
|
228
|
+
n = floor(n)
|
|
95
229
|
n += (n & 1) - 1 # make sure n is odd
|
|
96
230
|
while not is_prime(n):
|
|
97
231
|
n -= 2
|
|
@@ -116,87 +250,18 @@ def random_strongprime(l: int) -> int:
|
|
|
116
250
|
uu += u
|
|
117
251
|
return t, s, r, uu
|
|
118
252
|
|
|
119
|
-
def is_safeprime(p: int) -> bool:
|
|
120
|
-
"""Tests if a number is a safe prime."""
|
|
121
|
-
return is_prime(p) and is_prime((p - 1) // 2)
|
|
122
|
-
|
|
123
253
|
def random_safeprime(l: int) -> int:
|
|
124
254
|
"""Find a pseudorandom safe prime with bit length at least `l` and `ord(2)=(p-1)/2`."""
|
|
125
255
|
p = randint(2 ** (l - 1), 2**l - 1)
|
|
126
|
-
p = p - (p % 24) + 23
|
|
256
|
+
p = p - (p % 24) + 23 # make sure p % 24 = 23
|
|
127
257
|
while not is_safeprime(p):
|
|
128
258
|
p += 24
|
|
129
259
|
return p
|
|
130
260
|
|
|
131
|
-
def is_blumprime(p: int) -> bool:
|
|
132
|
-
"""Tests if a number is a Blum prime."""
|
|
133
|
-
return p % 4 == 3 and is_prime(p)
|
|
134
|
-
|
|
135
261
|
def random_blumprime(l: int) -> int:
|
|
136
262
|
"""Find a pseudorandom Blum prime with bit length at least `l`."""
|
|
137
263
|
p = randint(2 ** (l - 1), 2**l - 1)
|
|
138
|
-
p = p - (p % 4) + 3
|
|
264
|
+
p = p - (p % 4) + 3 # make sure p % 4 = 3
|
|
139
265
|
while not is_prime(p):
|
|
140
266
|
p += 4
|
|
141
267
|
return p
|
|
142
|
-
|
|
143
|
-
def _lucas_sequence(n, D, k):
|
|
144
|
-
"""Evaluate a Lucas sequence."""
|
|
145
|
-
# P = 1
|
|
146
|
-
Q = (1 - D)//4
|
|
147
|
-
U = 1
|
|
148
|
-
V = 1
|
|
149
|
-
Qk = Q
|
|
150
|
-
b = k.bit_length()
|
|
151
|
-
while b > 1:
|
|
152
|
-
U = (U * V) % n
|
|
153
|
-
V = (V * V - 2 * Qk) % n
|
|
154
|
-
Qk *= Qk
|
|
155
|
-
b -= 1
|
|
156
|
-
if (k >> (b - 1)) & 1:
|
|
157
|
-
U, V = U + V, V + U * D
|
|
158
|
-
if U & 1:
|
|
159
|
-
U += n
|
|
160
|
-
if V & 1:
|
|
161
|
-
V += n
|
|
162
|
-
U, V = U >> 1, V >> 1
|
|
163
|
-
Qk *= Q
|
|
164
|
-
Qk %= n
|
|
165
|
-
return U % n, V % n, Qk
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
def _is_strong_lucas_prp(n: int) -> bool:
|
|
169
|
-
"""Strong Lucas primality test."""
|
|
170
|
-
|
|
171
|
-
# remove powers of 2 from n+1 (= k * 2**s)
|
|
172
|
-
k = (n + 1) // 2
|
|
173
|
-
s = 1
|
|
174
|
-
while k % 2 == 0:
|
|
175
|
-
k //= 2
|
|
176
|
-
s += 1
|
|
177
|
-
# gernerate parameters
|
|
178
|
-
D = 5
|
|
179
|
-
while True:
|
|
180
|
-
g = gcd(abs(D), n)
|
|
181
|
-
if 1 < g < n:
|
|
182
|
-
return False
|
|
183
|
-
if jacobi_symbol(D, n) == -1:
|
|
184
|
-
break
|
|
185
|
-
if D > 0:
|
|
186
|
-
D = -D - 2
|
|
187
|
-
else:
|
|
188
|
-
D = -D + 2
|
|
189
|
-
|
|
190
|
-
if D == 0:
|
|
191
|
-
return False
|
|
192
|
-
|
|
193
|
-
U, V, Qk = _lucas_sequence(n, D, k)
|
|
194
|
-
|
|
195
|
-
if U == 0 or V == 0:
|
|
196
|
-
return True
|
|
197
|
-
for _ in range(1, s):
|
|
198
|
-
V = (V*V - 2*Qk) % n
|
|
199
|
-
if V == 0:
|
|
200
|
-
return True
|
|
201
|
-
Qk = pow(Qk, 2, n)
|
|
202
|
-
return False
|
|
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
|
|
File without changes
|