kryptools 1.3.4__tar.gz → 1.3.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 (57) hide show
  1. {kryptools-1.3.4 → kryptools-1.3.5}/PKG-INFO +1 -1
  2. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/Zmod.py +57 -3
  3. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/__init__.py +1 -1
  4. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/factor.py +9 -2
  5. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/nt.py +7 -1
  6. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools.egg-info/PKG-INFO +1 -1
  7. {kryptools-1.3.4 → kryptools-1.3.5}/pyproject.toml +1 -1
  8. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_Zmod.py +20 -0
  9. {kryptools-1.3.4 → kryptools-1.3.5}/LICENSE +0 -0
  10. {kryptools-1.3.4 → kryptools-1.3.5}/README.md +0 -0
  11. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/GF2.py +0 -0
  12. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/aes.py +0 -0
  13. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/blockcipher.py +0 -0
  14. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/code.py +0 -0
  15. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/conway_polynomials.py +0 -0
  16. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/des.py +0 -0
  17. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/dlp.py +0 -0
  18. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/dlp_bsgs.py +0 -0
  19. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/dlp_ic.py +0 -0
  20. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/dlp_qs.py +0 -0
  21. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/dlp_rho.py +0 -0
  22. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/ec.py +0 -0
  23. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/factor_dix.py +0 -0
  24. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/factor_ecm.py +0 -0
  25. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/factor_fmt.py +0 -0
  26. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/factor_pm1.py +0 -0
  27. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/factor_qs.py +0 -0
  28. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/factor_rho.py +0 -0
  29. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/intfuncs.py +0 -0
  30. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/keccak.py +0 -0
  31. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/la.py +0 -0
  32. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/lat.py +0 -0
  33. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/poly.py +0 -0
  34. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/primes.py +0 -0
  35. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools/sha1.py +0 -0
  36. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools.egg-info/SOURCES.txt +0 -0
  37. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools.egg-info/dependency_links.txt +0 -0
  38. {kryptools-1.3.4 → kryptools-1.3.5}/kryptools.egg-info/top_level.txt +0 -0
  39. {kryptools-1.3.4 → kryptools-1.3.5}/setup.cfg +0 -0
  40. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_GF2.py +0 -0
  41. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_aes.py +0 -0
  42. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_code.py +0 -0
  43. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_des.py +0 -0
  44. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_dlog.py +0 -0
  45. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_ec.py +0 -0
  46. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_factor.py +0 -0
  47. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_factor_fmt.py +0 -0
  48. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_factor_pm1.py +0 -0
  49. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_factor_qs.py +0 -0
  50. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_intfuncs.py +0 -0
  51. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_keccak.py +0 -0
  52. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_la.py +0 -0
  53. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_lat.py +0 -0
  54. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_nt.py +0 -0
  55. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_poly.py +0 -0
  56. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_primes.py +0 -0
  57. {kryptools-1.3.4 → kryptools-1.3.5}/tests/test_sha1.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kryptools
3
- Version: 1.3.4
3
+ Version: 1.3.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
  License: MIT
@@ -5,6 +5,7 @@ Ring of intergers modulo `n`.
5
5
  from math import gcd
6
6
  from .factor import factorint
7
7
  from .primes import is_prime
8
+ from .nt import sqrt_mod, crt
8
9
  from .intfuncs import prime_power
9
10
 
10
11
 
@@ -30,12 +31,13 @@ class Zmod:
30
31
  if not isinstance(n, int) or n < 1:
31
32
  raise ValueError(f"{n} is not a positive integer.")
32
33
  self.n = n
34
+ self.n_factors = {} # factoring of n
33
35
  self.short = short
34
36
  self.group_order = 0
35
- self.factors = {} # factoring of the group order
37
+ self.factors = {} # factoring of the multiplicative group order
36
38
 
37
39
  def __repr__(self):
38
- return f"Z_{self.n})"
40
+ return f"Z_{self.n}"
39
41
 
40
42
  def __call__(self, x: int | list | tuple):
41
43
  if isinstance(x, list|tuple):
@@ -59,7 +61,9 @@ class Zmod:
59
61
  if self.group_order:
60
62
  return self.group_order
61
63
  # We compute euler_phi(n) and its factorization in one pass
62
- for p, k in factorint(self.n).items(): # first factorize n
64
+ if not self.n_factors:
65
+ self.n_factors = factorint(self.n)
66
+ for p, k in self.n_factors.items(): # first factorize n
63
67
  # factor p-1 and add the factors
64
68
  for pm, km in factorint(p - 1).items():
65
69
  if pm in self.factors:
@@ -243,6 +247,56 @@ class ZmodPoint:
243
247
  break
244
248
  return order
245
249
 
250
+ def sqrt(self) -> "ZmodPoint":
251
+ if not self.ring.n_factors:
252
+ self.ring.n_factors = factorint(self.ring.n)
253
+ a = int(self)
254
+ if a in (0, 1):
255
+ return self.ring(a)
256
+ roots = []
257
+ powers = []
258
+ for p, k in self.ring.n_factors.items():
259
+ q = p**(k-1)
260
+ pk = q * p
261
+ ak = a % pk
262
+ powers.append(pk)
263
+ if ak in (0, 1):
264
+ roots.append(ak)
265
+ continue
266
+ # write ak as p^j * invertible
267
+ j = 0
268
+ while ak % p == 0:
269
+ j += 1
270
+ ak //= p
271
+ if j % 2:
272
+ raise ValueError("No quadratic residue!")
273
+ if ak == 1:
274
+ roots.append(p**(j//2))
275
+ continue
276
+ if p == 2:
277
+ if ak % 8 != 1:
278
+ raise ValueError("No quadratic residue!")
279
+ m = 4 # start at 2^2
280
+ x = ak % m # this is the root mod m
281
+ for i in range(3, k + 1):
282
+ # test all 4 poosible roots
283
+ if (x**2 - ak) % (m * 2):
284
+ x = m - x
285
+ if (x**2 - ak) % (m*2):
286
+ x = (x * (m//2-1)) % m
287
+ if (x**2 - ak) % (m * 2):
288
+ x = m - x
289
+ m *= 2
290
+ else:
291
+ # odd prime: Cipolla's formula
292
+ x = sqrt_mod(ak, p)
293
+ if x is None:
294
+ raise ValueError("No quadratic residue!")
295
+ if k > 1:
296
+ x = pow(x, q, pk) * pow(ak,((p-2)*q+1)//2, pk) % pk
297
+ roots.append((p**(j//2) * x) % pk)
298
+ return self.ring(crt(roots, powers))
299
+
246
300
  def is_generator(self):
247
301
  "Test if the point is a generator of the group Z_n^*."
248
302
  return self.ring.order() == self.order()
@@ -5,7 +5,7 @@ Implemenation of same basic algorithms used in cryptography.
5
5
  __author__ = "Gerald Teschl"
6
6
  __copyright__ = "Copyright 2024-2025, Gerald Teschl"
7
7
  __license__ = "MIT License"
8
- __version__ = "1.3.4"
8
+ __version__ = "1.3.5"
9
9
  __email__ = "Gerald.Teschl@univie.ac.at"
10
10
 
11
11
  from .nt import egcd, cf, convergents, legendre_symbol, jacobi_symbol, sqrt_mod, euler_phi, carmichael_lambda, moebius_mu, is_carmichael_number, order, crt
@@ -6,6 +6,7 @@ Factorization of integers:
6
6
 
7
7
  from math import isqrt, gcd, prod, floor, log10
8
8
  from .primes import sieve_eratosthenes, is_prime
9
+ from .intfuncs import perfect_power
9
10
  from .factor_pm1 import _pm1_parameters, factor_pm1
10
11
  from .factor_ecm import _ecm_parameters, factor_ecm
11
12
  #from .factor_qs import factor_qs
@@ -86,10 +87,16 @@ def factorint(n: int, trial_bnd: int = 2500, verbose: int = 0) -> dict:
86
87
  return prime_factors
87
88
  if verbose:
88
89
  print("Trial division found:", list(prime_factors))
90
+ # check if the remainder is a perfect power
91
+ res = perfect_power(n)
92
+ if res:
93
+ n, k = res
94
+ else:
95
+ n, k = n, 1
89
96
  if is_prime(n, trialdivision=False):
90
- prime_factors[n] = 1
97
+ prime_factors[n] = k
91
98
  return prime_factors
92
- remaining_factors = {n: 1}
99
+ remaining_factors = {n: k}
93
100
 
94
101
  # https://gitlab.inria.fr/zimmerma/ecm/
95
102
  ECM_PARAMETERS = [
@@ -111,7 +111,7 @@ def jacobi_symbol(a: int, n: int) -> int:
111
111
  return 0
112
112
 
113
113
 
114
- def sqrt_mod(a: int, p: int) -> int:
114
+ def sqrt_mod(a: int, p: int) -> int|None:
115
115
  """Compute a square root of `a` modulo `p` unsing Cipolla's algorithm."""
116
116
  a %= p
117
117
  if a in (0, 1):
@@ -120,6 +120,12 @@ def sqrt_mod(a: int, p: int) -> int:
120
120
  return None
121
121
  if p % 4 == 3: # easy case
122
122
  return pow(a, (p + 1) // 4, p)
123
+ if p % 8 == 5:
124
+ x = pow(a, (p + 3)//8, p)
125
+ c = pow(x, 2, p)
126
+ if c % p == a:
127
+ return x
128
+ return (x * pow(2, (p - 1)//4, p)) % p
123
129
  # Cipolla's algorithm
124
130
  for c in range(1, p): # find a field extension
125
131
  tmp = (c * c - a) % p
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kryptools
3
- Version: 1.3.4
3
+ Version: 1.3.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
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kryptools"
3
- version = "1.3.4"
3
+ version = "1.3.5"
4
4
  authors = [
5
5
  { name="Gerald Teschl", email="gerald.teschl@univie.ac.at" },
6
6
  ]
@@ -87,6 +87,26 @@ def test_ZmodP_order():
87
87
  xx *=x
88
88
  assert o == x.order()
89
89
 
90
+ def test_ZmodP_sqrt():
91
+ for n in range(1,100):
92
+ print(n)
93
+ ring = Zmod(n)
94
+ one = ring(1)
95
+ roots = {} # compute a dict of all roots
96
+ for x in ring:
97
+ y = x**2
98
+ if y in roots:
99
+ roots[y].append(x)
100
+ else:
101
+ roots[y] = [ x ]
102
+ for x in ring:
103
+ if x not in roots:
104
+ with pytest.raises(ValueError):
105
+ x.sqrt()
106
+ else:
107
+ y = x.sqrt()
108
+ assert y**2 == x
109
+
90
110
  def test_Zmod_field():
91
111
  for n in range(1, 100):
92
112
  assert Zmod(n).is_field() == is_prime(n)
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes