kryptools 0.8__tar.gz → 0.9__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.8 → kryptools-0.9}/PKG-INFO +8 -5
  2. {kryptools-0.8 → kryptools-0.9}/README.md +7 -4
  3. {kryptools-0.8 → kryptools-0.9}/kryptools/__init__.py +1 -1
  4. {kryptools-0.8 → kryptools-0.9}/kryptools/dlp.py +2 -6
  5. {kryptools-0.8 → kryptools-0.9}/kryptools/dlp_bsgs.py +1 -1
  6. {kryptools-0.8 → kryptools-0.9}/kryptools/dlp_qs.py +1 -1
  7. {kryptools-0.8 → kryptools-0.9}/kryptools/dlp_rho.py +1 -1
  8. {kryptools-0.8 → kryptools-0.9}/kryptools/ec.py +4 -3
  9. {kryptools-0.8 → kryptools-0.9}/kryptools/factor.py +12 -5
  10. {kryptools-0.8 → kryptools-0.9}/kryptools/la.py +3 -0
  11. {kryptools-0.8 → kryptools-0.9}/kryptools/lat.py +1 -1
  12. {kryptools-0.8 → kryptools-0.9}/kryptools/nt.py +43 -79
  13. {kryptools-0.8 → kryptools-0.9}/kryptools/primes.py +11 -11
  14. {kryptools-0.8 → kryptools-0.9}/kryptools.egg-info/PKG-INFO +8 -5
  15. {kryptools-0.8 → kryptools-0.9}/pyproject.toml +1 -1
  16. {kryptools-0.8 → kryptools-0.9}/LICENSE +0 -0
  17. {kryptools-0.8 → kryptools-0.9}/kryptools/Zmod.py +0 -0
  18. {kryptools-0.8 → kryptools-0.9}/kryptools/dlp_ic.py +0 -0
  19. {kryptools-0.8 → kryptools-0.9}/kryptools/factor_dix.py +0 -0
  20. {kryptools-0.8 → kryptools-0.9}/kryptools/factor_ecm.py +0 -0
  21. {kryptools-0.8 → kryptools-0.9}/kryptools/factor_fmt.py +0 -0
  22. {kryptools-0.8 → kryptools-0.9}/kryptools/factor_pm1.py +0 -0
  23. {kryptools-0.8 → kryptools-0.9}/kryptools/factor_qs.py +0 -0
  24. {kryptools-0.8 → kryptools-0.9}/kryptools/poly.py +0 -0
  25. {kryptools-0.8 → kryptools-0.9}/kryptools.egg-info/SOURCES.txt +0 -0
  26. {kryptools-0.8 → kryptools-0.9}/kryptools.egg-info/dependency_links.txt +0 -0
  27. {kryptools-0.8 → kryptools-0.9}/kryptools.egg-info/top_level.txt +0 -0
  28. {kryptools-0.8 → kryptools-0.9}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kryptools
3
- Version: 0.8
3
+ Version: 0.9
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
@@ -22,18 +22,21 @@ you are welcome to read (and modify) the source. Any suggestions on how to make
22
22
  code more readable or make it better are welcome. However, my main goal is to keep
23
23
  it simple and readability will be preferred over small speed improvements.
24
24
 
25
+ It does not require any external libraries.
26
+
25
27
  The tools contained are:
26
28
 
27
- * number theory: sqrt modulo primes, crt, continued fractions, etc.
28
- * primes: Sieve of Erathostenes, primality tests
29
+ * number theory: sqrt modulo primes, Jacobi/Legendre symbol, Chinese Remainder Theorem, continued fractions, etc.
30
+ * primes: Sieve of Erathostenes, primality tests, generation of random safe/strong primes
29
31
  * solvers for discrete logarithms (naive, Pollard rho, Shanks baby step/giant step, index calculus, quadratic sieve)
30
32
  * integer factorization (Fermat, Pollard p-1, Lenstra's ECM, Dixon, basic quadratic sieve)
33
+ * elliptic curves (Weierstrass form), group operations, order, discrete logarithms
31
34
  * linear algebra: Hermite normal form, Gram-Schmidt
32
- * lattices: Babai rounding/nearest plane, lattice reduction
35
+ * lattices: Hadamard ratio, Babai rounding/nearest plane algorithm, lattice reduction (Lenstra-Lenstra-Lovaz)
33
36
 
34
37
  * Matrix: a class for Matrices (inverse, det, reduced echelon form, etc.)
35
38
  * Poly: a class for polynomials (division, modulo)
36
39
  * Zmod: a class for the ring of integers modulo an integer
37
40
 
38
41
  Documentation can be found in the jupyter notebook
39
- (currently incomplete: use the force, read the source).
42
+ (mostly done, but might not contain everything: use the force, read the source).
@@ -7,18 +7,21 @@ you are welcome to read (and modify) the source. Any suggestions on how to make
7
7
  code more readable or make it better are welcome. However, my main goal is to keep
8
8
  it simple and readability will be preferred over small speed improvements.
9
9
 
10
+ It does not require any external libraries.
11
+
10
12
  The tools contained are:
11
13
 
12
- * number theory: sqrt modulo primes, crt, continued fractions, etc.
13
- * primes: Sieve of Erathostenes, primality tests
14
+ * number theory: sqrt modulo primes, Jacobi/Legendre symbol, Chinese Remainder Theorem, continued fractions, etc.
15
+ * primes: Sieve of Erathostenes, primality tests, generation of random safe/strong primes
14
16
  * solvers for discrete logarithms (naive, Pollard rho, Shanks baby step/giant step, index calculus, quadratic sieve)
15
17
  * integer factorization (Fermat, Pollard p-1, Lenstra's ECM, Dixon, basic quadratic sieve)
18
+ * elliptic curves (Weierstrass form), group operations, order, discrete logarithms
16
19
  * linear algebra: Hermite normal form, Gram-Schmidt
17
- * lattices: Babai rounding/nearest plane, lattice reduction
20
+ * lattices: Hadamard ratio, Babai rounding/nearest plane algorithm, lattice reduction (Lenstra-Lenstra-Lovaz)
18
21
 
19
22
  * Matrix: a class for Matrices (inverse, det, reduced echelon form, etc.)
20
23
  * Poly: a class for polynomials (division, modulo)
21
24
  * Zmod: a class for the ring of integers modulo an integer
22
25
 
23
26
  Documentation can be found in the jupyter notebook
24
- (currently incomplete: use the force, read the source).
27
+ (mostly done, but might not contain everything: use the force, read the source).
@@ -2,7 +2,7 @@
2
2
  Implemenation of same basic algorithms used in cryptography.
3
3
  """
4
4
 
5
- from .nt import egcd, crt, cf, convergents, legendre_symbol, jacobi_symbol, sqrt_mod, euler_phi, order, carmichael_lambda
5
+ from .nt import egcd, cf, convergents, legendre_symbol, jacobi_symbol, sqrt_mod, euler_phi, carmichael_lambda, order, crt
6
6
  from .primes import sieve_eratosthenes, is_prime, next_prime, random_prime, random_strongprime, is_safeprime, random_safeprime
7
7
  from .factor import factorint
8
8
  from .dlp import dlog
@@ -22,7 +22,7 @@ def dlog_naive(a: int, b: int, n: int, m: int = None) -> int|None:
22
22
  aa = (aa * a) % n
23
23
  if aa == b:
24
24
  return i + 1
25
- return None # no solution
25
+ raise ValueError("DLP not solvable.")
26
26
 
27
27
  def _dlog_switch(a: int, b: int, n: int, m: int) -> int:
28
28
  """Compute the discrete log_a(b) in Z_n of an element a of order m choosing an appropriate method."""
@@ -44,14 +44,12 @@ def _dlog_ph(a: int, b: int, n: int, q: int, k: int) -> int:
44
44
  aj = pow(a, q ** (k - j), n)
45
45
  bj = pow(b, q ** (k - j), n)
46
46
  yj = _dlog_switch(a1, bj * pow(aj, -xj, n) % n, n, q) # pylint: disable=E1130
47
- if yj is None:
48
- return None
49
47
  xj = xj + q ** (j - 1) * yj % q**j
50
48
  return xj
51
49
 
52
50
 
53
51
  def dlog(a: int, b: int, n: int, m: int|None = None) -> int:
54
- """Compute the discrete log_a(b) in Z_n of an element a of order m using Pohlig-Hellman reduction."""
52
+ """Compute the discrete log_a(b) in Z_n of an element `a` of order `m` using Pohlig-Hellman reduction."""
55
53
  a %= n
56
54
  b %= n
57
55
  assert gcd(a, n) == 1, "a and n must be coprime."
@@ -69,8 +67,6 @@ def dlog(a: int, b: int, n: int, m: int|None = None) -> int:
69
67
  aj = pow(a, m // pj**kj, n)
70
68
  bj = pow(b, m // pj**kj, n)
71
69
  l = _dlog_ph(aj, bj, n, pj, kj)
72
- if l is None:
73
- return None
74
70
  mm += [pj**kj]
75
71
  ll += [l]
76
72
  return crt(ll, mm)
@@ -26,4 +26,4 @@ def dlog_bsgs(a: int, b: int, n: int, m: int = None) -> int:
26
26
  if giant_step in baby_steps:
27
27
  return l * mm + baby_steps[giant_step]
28
28
  giant_step = giant_step * giant_stride % n
29
- return None # no solution
29
+ raise ValueError("DLP not solvable.")
@@ -292,6 +292,6 @@ def dlog_qs(a: int, b: int, n: int, m: int, pollard: bool = True, sieve_factor:
292
292
  relation[x + j] = 1
293
293
  res = process_relation(relation)
294
294
  if res:
295
- return(res)
295
+ return res
296
296
 
297
297
  raise Exception(f"Sorry, Quadratic sieve could not find enough relations! ({n_relations} - {n_relations_redundant} = {n_relations - n_relations_redundant} out of {len_relations}). Try to increase sieve_factor={sieve_factor}")
@@ -55,7 +55,7 @@ def dlog_rho(a: int, b: int, n: int, m: int = None, brent=0) -> int:
55
55
  l = (((alpha_x - alpha_y) // d) * pow((beta_y - beta_x) // d, -1, mm)) % mm
56
56
  while pow(a, l, n) != b:
57
57
  if l >= m:
58
- return None
58
+ raise ValueError("DLP not solvable.")
59
59
  l += mm
60
60
  return l
61
61
  trys -= 1
@@ -1,5 +1,6 @@
1
1
  """
2
- Elliptic curves
2
+ Elliptic curves:
3
+ EC_Weierstrass() constructor for a Weierstrass curve y^2 = x^3 + ax + b mod p
3
4
  """
4
5
 
5
6
  from math import isqrt, floor, sqrt
@@ -11,11 +12,11 @@ from .poly import Poly
11
12
 
12
13
  class EC_Weierstrass():
13
14
  """
14
- Elliptic curve in Weierstrass normal form y^2 = x^3 + ax + b mod p.
15
+ Elliptic curve in Weierstrass normal form `y^2 = x^3 + ax + b mod p`.
15
16
 
16
17
  Example:
17
18
 
18
- To define an elliptic curve use
19
+ To define an elliptic curve y^2 = x^3 + 3x + 1 mod 239 use
19
20
  >>> ec = EC_Weierstrass(239, 3, 1)
20
21
 
21
22
  To declare a point on the elliptic curve use
@@ -28,9 +28,16 @@ def _factor_fermat(n: int, steps: int = 10) -> list:
28
28
  if b * b == a * a - n:
29
29
  return a - b
30
30
 
31
- def factorint(n: int, verbose: int = 0) -> list:
32
- "Factor a number."
31
+ def factorint(n: int, verbose: int = 0) -> dict:
32
+ "Factor a the ineger `n`."
33
33
  prime_factors = {}
34
+ if not isinstance(n, int):
35
+ raise ValueError("Number to be factored must be an integer!")
36
+ if n == 0:
37
+ return prime_factors
38
+ if n < 0:
39
+ n *= -1
40
+ prime_factors[-1] = 1
34
41
 
35
42
  def add_factors(m: int, mm: tuple) -> None:
36
43
  k = remaining_factors[m]
@@ -96,7 +103,8 @@ def factorint(n: int, verbose: int = 0) -> list:
96
103
  for method in [ _factor_fermat, factor_pm1, factor_ecm ]: # , factor_qs ]:
97
104
  factors = list(remaining_factors)
98
105
  for m in factors:
99
- if verbose > 1: print("Factoring: ",m, "method", methods[method])
106
+ if verbose > 1:
107
+ print("Factoring: ",m, "method", methods[method])
100
108
  if method == factor_pm1:
101
109
  tmp = factor_pm1(m, pm1_parameters = pm1_parameters)
102
110
  elif method == factor_ecm:
@@ -131,5 +139,4 @@ def factorint(n: int, verbose: int = 0) -> list:
131
139
  if len(remaining_factors) == 0:
132
140
  return prime_factors
133
141
 
134
- print("Incomplete factorization!")
135
- return prime_factors, remaining_factors, new_factors
142
+ raise ValueError("Incomplete factorization:", prime_factors, remaining_factors, new_factors)
@@ -169,6 +169,9 @@ class Matrix:
169
169
  def __neg__(self) -> "Matrix":
170
170
  return -1 * self
171
171
 
172
+ def __pos__(self) -> "Matrix":
173
+ return self
174
+
172
175
  def __mul__(self, other) -> "Matrix":
173
176
  if isinstance(other, Matrix):
174
177
  return self.multiply(other)
@@ -173,7 +173,7 @@ def lll(V: Matrix, delta: float = 0.75, sort: bool = True) -> Matrix:
173
173
  return U
174
174
 
175
175
  def random_unimodular_matrix(n: int, iterations: int = 50, max_val: int = None) -> Matrix:
176
- "Create a random unimodular matrix of dimension n."
176
+ "Create a pseudorandom unimodular matrix of dimension n."
177
177
  W = zeros(n)
178
178
  for i in range(n):
179
179
  for j in range(i, n):
@@ -1,13 +1,15 @@
1
1
  """
2
2
  Number theory tools:
3
3
  egcd(a,b) extended Euclidean agorithm
4
- crt([a1, a2, ...],[m1, m2, ...]) Chinese Remainder Theorem
5
4
  cf(Fraction(m,n)) continued fraction expansions
6
5
  convergents() convergents of a continued fraction
7
6
  legendre_symbol(a, p) compute the Legendre symbol of a with respect to the prime p
8
7
  jacobi_symbol(a, n) compute the Jacobi symbol of a with respect to n
9
8
  sqrt_mod(n, p) square root of n modulo a prime p
9
+ euler_phi(n) Euler phi function of n
10
+ carmichael_lambda(n) Carmichael lambda function of n
10
11
  order(a, n) oder of a in the multiplicative group Z_n^*
12
+ crt([a1, a2, ...],[m1, m2, ...]) Chinese Remainder Theorem
11
13
  """
12
14
  from math import gcd, lcm, prod
13
15
  from fractions import Fraction
@@ -26,83 +28,8 @@ def egcd(a: int, b: int) -> (int, int, int):
26
28
  return r0, x0, y0
27
29
 
28
30
 
29
- # Chinese remainder theorem
30
-
31
- def crt(a: list[int], m: list[int]) -> int:
32
- """Solve given linear congruences x % m[j] == a[j] using the Chinese Remainder Theorem."""
33
- l = len(a)
34
- assert len(m) == l, "The lists of numbers and modules must have equal length."
35
- M = prod(m)
36
- Mi = [M // m[i] for i in range(l)]
37
- MNi = [Mi[i] * pow(Mi[i], -1, m[i]) % M for i in range(l)]
38
- return sum([a[i] * MNi[i] % M for i in range(l)]) % M
39
-
40
31
  # Continued fractions
41
32
 
42
- # class Fraction:
43
- # "Rationl number"
44
- #
45
- # def __init__(self, numerator: int, denominator: int = 1):
46
- # assert denominator, "Denominator must be nozero."
47
- # tmp = gcd(denominator, numerator)
48
- # if tmp != 1:
49
- # denominator //= tmp
50
- # numerator //= tmp
51
- # self.numerator = numerator
52
- # self.denominator = denominator
53
- #
54
- # def __repr__(self):
55
- # if self.denominator == 1:
56
- # return str(self.numerator)
57
- # else:
58
- # return str(self.numerator) + "/" + str(self.denominator)
59
- #
60
- # def __eq__(self, other):
61
- # if not isinstance(other, self.__class__):
62
- # return False
63
- # return self.denominator == other.denominator and self.numerator == other.numerator
64
- #
65
- # def __bool__(self):
66
- # return self.numerator != 0
67
- #
68
- # def __add__(self, other: "Fraction") -> "Fraction":
69
- # if isinstance(other, self.__class__):
70
- # return Rational(self.numerator * other.denominator + other.numerator * self.denominator, self.denominator * other.denominator)
71
- # if isinstance(other, int):
72
- # return Rational(self.numerator + other * self.denominator, self.denominator)
73
- # raise ValueError(f"Cannot add {self} and {other}.")
74
- #
75
- # def __neg__(self) -> "Fraction":
76
- # return Rational(- self.numerator, self.denominator)
77
- #
78
- # def __sub__(self, other: "Fraction") -> "Fraction":
79
- # if isinstance(other, self.__class__):
80
- # return Rational(self.numerator * other.denominator - other.numerator * self.denominator, self.denominator * other.denominator)
81
- # if isinstance(other, int):
82
- # return Rational(self.numerator - other * self.denominator, self.denominator)
83
- # raise ValueError(f"Cannot subtract {self} and {other}.")
84
- #
85
- # def __mul__(self, other: "Fraction") -> "Fraction":
86
- # if isinstance(other, self.__class__):
87
- # return Rational(self.numerator * other.numerator, self.denominator * other.denominator)
88
- # if isinstance(other, int):
89
- # return Rational(self.numerator * other, self.denominator)
90
- # raise ValueError(f"Cannot multiply {self} and {other}.")
91
- #
92
- # def __rmul__(self, other: int) -> "Fraction":
93
- # return Rational(self.denominator * other, self.numerator)
94
- #
95
- # def __truediv__(self, other: "Fraction") -> "Fraction":
96
- # if isinstance(other, self.__class__):
97
- # return Rational(self.numerator * other.denominator, self.denominator * other.numerator)
98
- # if isinstance(other, int):
99
- # return Rational(self.numerator, self.denominator * other)
100
- # raise ValueError(f"Cannot divide {self} and {other}.")
101
- #
102
- # def __pow__(self, scalar: int) -> "Fraction":
103
- # return Rational(self.numerator**scalar, self.denominator**scalar)
104
-
105
-
106
33
  def fraction_repr(self):
107
34
  "Representation of a fraction."
108
35
  if self.denominator == 1:
@@ -113,7 +40,7 @@ Fraction.__repr__ = fraction_repr
113
40
 
114
41
 
115
42
  def cf(x: Fraction) -> list[int]:
116
- "Compute the continued fraction expansion of the rational number m/n."
43
+ "Compute the continued fraction expansion of the rational fraction `x`."
117
44
  res = []
118
45
  m = x.numerator
119
46
  n = x.denominator
@@ -144,7 +71,7 @@ def convergents(cont_frac: list[int]) -> float:
144
71
  # Legendre symbol
145
72
 
146
73
  def legendre_symbol(a: int, p: int) -> int:
147
- """Compute the Legendre symbol of a with respect to the prime p."""
74
+ """Compute the Legendre symbol of `a` with respect to the prime `p`."""
148
75
  a = a % p
149
76
  if a == 0:
150
77
  return 0
@@ -153,7 +80,7 @@ def legendre_symbol(a: int, p: int) -> int:
153
80
  return -1
154
81
 
155
82
  def jacobi_symbol(a: int, n: int) -> int:
156
- """Compute the Jacobi symbol of a with respect to the integer n."""
83
+ """Compute the Jacobi symbol of `a` with respect to the integer `n`."""
157
84
  # Crandall/Pomerance Algorithm 2.3.5
158
85
  a = a % n
159
86
  t = 1
@@ -260,3 +187,40 @@ def order(a: int, n: int, factor=False) -> int:
260
187
  if factor:
261
188
  return order_a, factors_order
262
189
  return order_a
190
+
191
+ # Chinese remainder theorem
192
+
193
+ def crt(a: list[int], m: list[int], coprime = True) -> int:
194
+ """Solve given linear congruences `x % m[j] == a[j]` using the Chinese Remainder Theorem."""
195
+ l = len(m)
196
+ if l != len(a):
197
+ raise ValueError("The lists of numbers and modules must have equal length.")
198
+
199
+ if not coprime: # make a copy
200
+ m = [ mi for mi in m ]
201
+ a = [ ai for ai in a ]
202
+ for i in range(l):
203
+ for j in range(i + 1,l):
204
+ g = gcd(m[i], m[j])
205
+ if g == 1: # moduli are coprime, nothing to be done
206
+ continue
207
+ if (a[i] - a[j]) % g:
208
+ raise ValueError(f"Congruences not solvable!")
209
+ for p, k in factorint(g).items():
210
+ p = p**k # remove this factor from one of the equations
211
+ if gcd(m[i] // p, p) == 1:
212
+ m[i] //= p
213
+ a[i] %= m[i]
214
+ else:
215
+ m[j] //= p
216
+ a[j] %= m[j]
217
+ for i in reversed(range(l)):
218
+ if m[i] == 1:
219
+ del m[i]
220
+ del a[i]
221
+ l =len(m)
222
+
223
+ M = prod(m)
224
+ Mi = [M // m[i] for i in range(l)]
225
+ MNi = [Mi[i] * pow(Mi[i], -1, m[i]) % M for i in range(l)]
226
+ return sum([a[i] * MNi[i] % M for i in range(l)]) % M
@@ -3,10 +3,10 @@ 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
- random_prime(l) find a random prime with bit length at least l
7
- random_strongprime(l) find a random strong prime with bit length at least l
6
+ random_prime(l) find a pseudorandom prime with bit length at least l
7
+ random_strongprime(l) find a pseudorandom strong prime with bit length at least l
8
8
  is_safeprime(n) test if n is a safe prime
9
- random_safeprime(n) find a random safe prime with bit length at least l and ord(2)=(p-1)/2
9
+ random_safeprime(n) find a pseudorandom safe prime with bit length at least l and ord(2)=(p-1)/2
10
10
  miller_rabin_test(n, b) Miller-Rabin primality test with base b
11
11
  """
12
12
  from math import isqrt, gcd
@@ -15,8 +15,8 @@ from .nt import jacobi_symbol
15
15
 
16
16
  # Erathostenes
17
17
 
18
- def sieve_eratosthenes(B: int) -> list:
19
- """ "Returns a list of all primes up to (including) max."""
18
+ def sieve_eratosthenes(B: int) -> tuple:
19
+ """Returns a tuple of all primes up to (including) `B`."""
20
20
  B1 = (isqrt(B) -1)//2
21
21
  B = (B - 1)//2
22
22
  isprime = [True] * (B + 1) # to begin with, all numbers are potentially prime
@@ -33,7 +33,7 @@ def sieve_eratosthenes(B: int) -> list:
33
33
 
34
34
 
35
35
  def miller_rabin_test(n: int, bases: list[int] | int) -> bool:
36
- """Run a Miller-Rabin test with given bases on n."""
36
+ """Run a Miller-Rabin test with given bases on `n`."""
37
37
  if n < 2:
38
38
  return False
39
39
  if n % 2 == 0:
@@ -58,7 +58,7 @@ def miller_rabin_test(n: int, bases: list[int] | int) -> bool:
58
58
  return False
59
59
 
60
60
  def is_prime(n: int) -> bool:
61
- """Test if an integer n if probable prime."""
61
+ """Test if an integer `n` if probable prime."""
62
62
  if n < 18446744073709551616: # https://miller-rabin.appspot.com
63
63
  return miller_rabin_test(n, [2, 325, 9375, 28178, 450775, 9780504, 1795265022])
64
64
  if n < 3317044064679887385961981:
@@ -66,18 +66,18 @@ def is_prime(n: int) -> bool:
66
66
  return miller_rabin_test(n, [2]) and _is_strong_lucas_prp(n) # Baillie–PSW primality test
67
67
 
68
68
  def next_prime(n: int) -> int:
69
- """Find the next prime larger or equal n."""
69
+ """Find the next prime larger or equal `n`."""
70
70
  n |= 1 # make sure n is odd
71
71
  while not is_prime(n):
72
72
  n += 2
73
73
  return n
74
74
 
75
75
  def random_prime(l: int) -> int:
76
- """Find a random prime with bit length at least l."""
76
+ """Find a pseudorandom prime with bit length at least `l`."""
77
77
  return next_prime(randint(2 ** (l - 1), 2**l - 1))
78
78
 
79
79
  def random_strongprime(l: int) -> int:
80
- """Find a random strong prime with bit length at least l using Gordon's algorithm."""
80
+ """Find a pseudorandom strong prime with bit length at least `l` using Gordon's algorithm."""
81
81
  t = random_prime(l)
82
82
  s = random_prime(l)
83
83
  u = 2 * t
@@ -96,7 +96,7 @@ def is_safeprime(p: int) -> bool:
96
96
  return is_prime(p) and is_prime((p - 1) // 2)
97
97
 
98
98
  def random_safeprime(l: int) -> int:
99
- """Find a random safe prime with bit length at least l and ord(2)=(p-1)/2."""
99
+ """Find a pseudorandom safe prime with bit length at least `l` and `ord(2)=(p-1)/2`."""
100
100
  p = randint(2 ** (l - 1), 2**l - 1)
101
101
  p = p - (p % 24) + 23
102
102
  while not is_safeprime(p):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kryptools
3
- Version: 0.8
3
+ Version: 0.9
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
@@ -22,18 +22,21 @@ you are welcome to read (and modify) the source. Any suggestions on how to make
22
22
  code more readable or make it better are welcome. However, my main goal is to keep
23
23
  it simple and readability will be preferred over small speed improvements.
24
24
 
25
+ It does not require any external libraries.
26
+
25
27
  The tools contained are:
26
28
 
27
- * number theory: sqrt modulo primes, crt, continued fractions, etc.
28
- * primes: Sieve of Erathostenes, primality tests
29
+ * number theory: sqrt modulo primes, Jacobi/Legendre symbol, Chinese Remainder Theorem, continued fractions, etc.
30
+ * primes: Sieve of Erathostenes, primality tests, generation of random safe/strong primes
29
31
  * solvers for discrete logarithms (naive, Pollard rho, Shanks baby step/giant step, index calculus, quadratic sieve)
30
32
  * integer factorization (Fermat, Pollard p-1, Lenstra's ECM, Dixon, basic quadratic sieve)
33
+ * elliptic curves (Weierstrass form), group operations, order, discrete logarithms
31
34
  * linear algebra: Hermite normal form, Gram-Schmidt
32
- * lattices: Babai rounding/nearest plane, lattice reduction
35
+ * lattices: Hadamard ratio, Babai rounding/nearest plane algorithm, lattice reduction (Lenstra-Lenstra-Lovaz)
33
36
 
34
37
  * Matrix: a class for Matrices (inverse, det, reduced echelon form, etc.)
35
38
  * Poly: a class for polynomials (division, modulo)
36
39
  * Zmod: a class for the ring of integers modulo an integer
37
40
 
38
41
  Documentation can be found in the jupyter notebook
39
- (currently incomplete: use the force, read the source).
42
+ (mostly done, but might not contain everything: use the force, read the source).
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kryptools"
3
- version = "0.8"
3
+ version = "0.9"
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