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.
Files changed (28) hide show
  1. {kryptools-0.9.3 → kryptools-0.9.5}/PKG-INFO +1 -1
  2. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/__init__.py +1 -1
  3. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/poly.py +19 -4
  4. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/primes.py +142 -77
  5. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools.egg-info/PKG-INFO +1 -1
  6. {kryptools-0.9.3 → kryptools-0.9.5}/pyproject.toml +1 -1
  7. {kryptools-0.9.3 → kryptools-0.9.5}/LICENSE +0 -0
  8. {kryptools-0.9.3 → kryptools-0.9.5}/README.md +0 -0
  9. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/Zmod.py +0 -0
  10. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/dlp.py +0 -0
  11. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/dlp_bsgs.py +0 -0
  12. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/dlp_ic.py +0 -0
  13. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/dlp_qs.py +0 -0
  14. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/dlp_rho.py +0 -0
  15. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/ec.py +0 -0
  16. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/factor.py +0 -0
  17. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/factor_dix.py +0 -0
  18. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/factor_ecm.py +0 -0
  19. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/factor_fmt.py +0 -0
  20. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/factor_pm1.py +0 -0
  21. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/factor_qs.py +0 -0
  22. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/la.py +0 -0
  23. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/lat.py +0 -0
  24. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools/nt.py +0 -0
  25. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools.egg-info/SOURCES.txt +0 -0
  26. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools.egg-info/dependency_links.txt +0 -0
  27. {kryptools-0.9.3 → kryptools-0.9.5}/kryptools.egg-info/top_level.txt +0 -0
  28. {kryptools-0.9.3 → kryptools-0.9.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kryptools
3
- Version: 0.9.3
3
+ Version: 0.9.5
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
@@ -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
- for i in reversed(range(len(self.coeff))):
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) + " " + prx(i)
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) + " " + prx(i)
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
- return True
76
+ continue
66
77
  for _ in range(1, k):
67
78
  b = pow(b, 2, n)
68
- if b == 1:
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
- return True
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 _is_strong_lucas_prp(n) # Baillie–PSW primality test
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kryptools
3
- Version: 0.9.3
3
+ Version: 0.9.5
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kryptools"
3
- version = "0.9.3"
3
+ version = "0.9.5"
4
4
  authors = [
5
5
  { name="Gerald Teschl", email="gerald.teschl@univie.ac.at" },
6
6
  ]
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