kryptools 0.9.5__tar.gz → 0.9.6__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 (29) hide show
  1. {kryptools-0.9.5 → kryptools-0.9.6}/PKG-INFO +1 -1
  2. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/factor.py +36 -16
  3. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/factor_ecm.py +40 -8
  4. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/factor_fmt.py +17 -3
  5. kryptools-0.9.6/kryptools/factor_pm1.py +77 -0
  6. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/factor_qs.py +34 -9
  7. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/primes.py +13 -9
  8. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools.egg-info/PKG-INFO +1 -1
  9. {kryptools-0.9.5 → kryptools-0.9.6}/pyproject.toml +1 -1
  10. kryptools-0.9.5/kryptools/factor_pm1.py +0 -58
  11. {kryptools-0.9.5 → kryptools-0.9.6}/LICENSE +0 -0
  12. {kryptools-0.9.5 → kryptools-0.9.6}/README.md +0 -0
  13. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/Zmod.py +0 -0
  14. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/__init__.py +0 -0
  15. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/dlp.py +0 -0
  16. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/dlp_bsgs.py +0 -0
  17. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/dlp_ic.py +0 -0
  18. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/dlp_qs.py +0 -0
  19. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/dlp_rho.py +0 -0
  20. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/ec.py +0 -0
  21. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/factor_dix.py +0 -0
  22. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/la.py +0 -0
  23. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/lat.py +0 -0
  24. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/nt.py +0 -0
  25. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools/poly.py +0 -0
  26. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools.egg-info/SOURCES.txt +0 -0
  27. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools.egg-info/dependency_links.txt +0 -0
  28. {kryptools-0.9.5 → kryptools-0.9.6}/kryptools.egg-info/top_level.txt +0 -0
  29. {kryptools-0.9.5 → kryptools-0.9.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kryptools
3
- Version: 0.9.5
3
+ Version: 0.9.6
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
@@ -4,7 +4,7 @@ Factorization of integers:
4
4
  divisors(n) unsorted list of all divisors of the integer n
5
5
  """
6
6
 
7
- from math import isqrt, gcd, prod
7
+ from math import isqrt, gcd, prod, floor, log10
8
8
  from .primes import sieve_eratosthenes, is_prime
9
9
  from .factor_pm1 import _pm1_parameters, factor_pm1
10
10
  from .factor_ecm import _ecm_parameters, factor_ecm
@@ -14,8 +14,10 @@ from .factor_ecm import _ecm_parameters, factor_ecm
14
14
  # Factoring
15
15
 
16
16
 
17
- def _factor_fermat(n: int, steps: int = 10) -> list:
17
+ def _factor_fermat(n: int, maxsteps: int = 10, verbose: int = 0) -> list:
18
18
  "Fermat method"
19
+ if verbose:
20
+ print(f"Factoring (Fermat, steps={maxsteps}): {n} ({floor(log10(n)) + 1} digits)")
19
21
  parameters = {11: (12, 6), 23: (12, 0),
20
22
  5: (6, 3), 17: (6, 3),
21
23
  19: (4, 2), 7: (4, 0),
@@ -23,12 +25,23 @@ def _factor_fermat(n: int, steps: int = 10) -> list:
23
25
  start = isqrt(n - 1) + 1
24
26
  step, mod = parameters[n % 24]
25
27
  start += (mod - start) % step
26
- for a in range(start, min(start + steps * step,(n + 9) // 6) + 1, step):
28
+ if verbose > 1:
29
+ print("Working ", end= "")
30
+ maxa = (n + 9) // 6 + 1
31
+ if maxsteps:
32
+ maxa = min(maxa, start + maxsteps * step + 1)
33
+ for a in range(start, maxa, step):
34
+ if verbose > 1:
35
+ print(".", end= "")
27
36
  b = isqrt(a * a - n)
28
37
  if b * b == a * a - n:
38
+ if verbose > 1:
39
+ print("")
29
40
  return a - b
41
+ if verbose > 1:
42
+ print("")
30
43
 
31
- def factorint(n: int, verbose: int = 0) -> dict:
44
+ def factorint(n: int, verbose: int = 0, trial_bnd: int = 2500) -> dict:
32
45
  "Factor an ineger `n` into prime factors."
33
46
  prime_factors = {}
34
47
  if not isinstance(n, int):
@@ -46,7 +59,7 @@ def factorint(n: int, verbose: int = 0) -> dict:
46
59
  for m in mm:
47
60
  if m in prime_factors:
48
61
  prime_factors[m] += k
49
- elif is_prime(m):
62
+ elif is_prime(m, trialdivision = False):
50
63
  prime_factors[m] = k
51
64
  else:
52
65
  if m in remaining_factors:
@@ -56,8 +69,10 @@ def factorint(n: int, verbose: int = 0) -> dict:
56
69
  else:
57
70
  new_factors[m] = k
58
71
 
72
+ if verbose:
73
+ print(f"Factoring: {n} ({floor(log10(n)) + 1} digits)")
59
74
  # trial division
60
- B = 2500
75
+ B = max(3, trial_bnd)
61
76
  factorbase = sieve_eratosthenes(B)
62
77
  for p in factorbase:
63
78
  k = 0
@@ -70,13 +85,14 @@ def factorint(n: int, verbose: int = 0) -> dict:
70
85
  return prime_factors
71
86
  if verbose:
72
87
  print("Trial division found:", list(prime_factors))
73
- if is_prime(n):
88
+ if is_prime(n, trialdivision = False):
74
89
  prime_factors[n] = 1
75
90
  return prime_factors
76
91
  remaining_factors = { n: 1 }
77
92
 
78
93
  # https://gitlab.inria.fr/zimmerma/ecm/
79
94
  ECM_PARAMETERS = [
95
+ [ 5000, 130000, 54],
80
96
  [ 11000, 1900000, 74],
81
97
  [ 50000, 13000000, 221],
82
98
  [ 250000, 130000000, 453],
@@ -88,8 +104,12 @@ def factorint(n: int, verbose: int = 0) -> dict:
88
104
  [260000000, 3200000000000, 47173],
89
105
  [850000000, 16000000000000, 77666]
90
106
  ]
107
+ fermat_steps = 10
91
108
 
92
- for parameters in ECM_PARAMETERS:
109
+ for round, parameters in enumerate(ECM_PARAMETERS):
110
+ if verbose:
111
+ print(f"Round {round+1}")
112
+ fermat_steps += 10
93
113
  B1, B2, num_curves = parameters
94
114
  num_curves *= 2
95
115
  D = isqrt(B2)
@@ -97,20 +117,20 @@ def factorint(n: int, verbose: int = 0) -> dict:
97
117
  pm1_parameters = _pm1_parameters(10 * B1, B2, primes = primes)
98
118
  ecm_parameters = tuple([B1, B2, num_curves] + list(_ecm_parameters(B1, B2, D, primes = primes)))
99
119
 
100
- methods = {_factor_fermat: "fm", factor_pm1: "pm1", factor_ecm: "ecm"} #, factor_qs: "qs"}
120
+ methods = {_factor_fermat: "fmt", factor_pm1: "pm1", factor_ecm: "ecm"} #, factor_qs: "qs"}
101
121
  while remaining_factors:
102
122
  new_factors = {}
103
123
  for method in [ _factor_fermat, factor_pm1, factor_ecm ]: # , factor_qs ]:
104
124
  factors = list(remaining_factors)
105
125
  for m in factors:
106
- if verbose > 1:
107
- print("Factoring: ",m, "method", methods[method])
108
- if method == factor_pm1:
109
- tmp = factor_pm1(m, pm1_parameters = pm1_parameters)
126
+ if method == _factor_fermat:
127
+ tmp = _factor_fermat(m, maxsteps = fermat_steps, verbose = max(0, verbose - 1))
128
+ elif method == factor_pm1:
129
+ tmp = factor_pm1(m, pm1_parameters = pm1_parameters, verbose = max(0, verbose - 1))
110
130
  elif method == factor_ecm:
111
- tmp = factor_ecm(m, ecm_parameters = ecm_parameters)
131
+ tmp = factor_ecm(m, ecm_parameters = ecm_parameters, verbose = max(0, verbose - 1))
112
132
  else:
113
- tmp = method(m)
133
+ tmp = method(m, verbose = max(0, verbose - 1))
114
134
  if tmp:
115
135
  tmp2 = m // tmp
116
136
  g = gcd(tmp, tmp2)
@@ -125,7 +145,7 @@ def factorint(n: int, verbose: int = 0) -> dict:
125
145
  tmp3.append(x)
126
146
  else:
127
147
  tmp3 = [tmp, tmp2]
128
- if verbose > 0: print("Factors found (", methods[method] ,"): ", tmp3)
148
+ if verbose > 0: print(f"Factors found ({methods[method]}): ", tmp3)
129
149
  add_factors(m, tmp3)
130
150
  if not new_factors:
131
151
  break
@@ -2,7 +2,7 @@
2
2
  Integer factorization: Lentra's ECM
3
3
  """
4
4
 
5
- from math import gcd, isqrt, log
5
+ from math import gcd, isqrt, log, floor, log10
6
6
  from random import randint, seed
7
7
  from .primes import sieve_eratosthenes
8
8
  seed(0)
@@ -35,19 +35,21 @@ def mult(k, P, c2, p):
35
35
  return dbl(P, c2, p)
36
36
  Q = dbl(P, c2, p)
37
37
  R = P
38
- for i in bin(k)[3:]:
38
+ for i in bin(k)[3:-1]:
39
39
  if i == "1":
40
40
  R = add(Q, R, P, p)
41
41
  Q = dbl(Q, c2, p)
42
42
  else:
43
43
  Q = add(R, Q, P, p)
44
44
  R = dbl(R, c2, p)
45
- return R
45
+ if k % 2:
46
+ return add(Q, R, P, p)
47
+ return dbl(R, c2, p)
46
48
 
47
49
  # Crandall and Pomerance: Primes (doi=10.1007/0-387-28979-8)
48
50
  # Algorithm 7.4.4 (Inversionless ECM)
49
51
 
50
- def _ecm_parameters(B1: int, B2: int = None, D: int = None, primes: tuple = None):
52
+ def _ecm_parameters(B1: int, B2: int|None = None, D: int|None = None, primes: tuple|None = None):
51
53
  "Precompute parameters for the ECM method."
52
54
 
53
55
  # Stage-one/two limits must be even
@@ -84,36 +86,59 @@ def _ecm_parameters(B1: int, B2: int = None, D: int = None, primes: tuple = None
84
86
  return D, stage_one, stage_two_deltas
85
87
 
86
88
 
87
- def factor_ecm(n: int, B1: int = 11000, B2: int = 1900000, curves: int = 74, ecm_parameters: tuple|None = None):
89
+ def factor_ecm(n: int, B1: int|None = None, B2: int|None = None, curves: int = 150, ecm_parameters: tuple|None = None, verbose: int = 0):
88
90
  "Factors a number n using Lentsta's ECM method."
89
91
 
90
92
  if ecm_parameters:
91
93
  B1, B2, curves, D, stage_one, stage_two_deltas = ecm_parameters
92
94
  else:
95
+ if not B1:
96
+ B1 = max(2, isqrt(n//200))
97
+ if not B2:
98
+ B2 = 100 * B1
93
99
  D, stage_one, stage_two_deltas = _ecm_parameters(B1, B2)
94
100
 
101
+ if verbose:
102
+ print(f"Factoring (ECM, B1={B1}, B2={B2}): {n} ({floor(log10(n)) + 1} digits)")
103
+ if verbose > 1:
104
+ print("Working ", end= "")
95
105
  for _ in range(curves):
96
106
  # find a random curve
107
+ if verbose > 1:
108
+ print("C", end= "") # stage one
97
109
  sigma = randint(6, n - 1)
98
110
  u = (sigma**2 - 5) % n
99
111
  v = (4 * sigma) % n
100
112
  try:
101
113
  c = (pow(v - u, 3, n) * (3 * u + v) * pow(4 * u**3 * v, -1, n) - 2) % n
102
114
  except:
103
- m = gcd(4 * u**3 * v, n)
104
- return m
105
- c2 = c - 2 % n
115
+ if verbose > 1:
116
+ print("\nFactor found.")
117
+ m = gcd(u, n)
118
+ if m > 1:
119
+ return m
120
+ m = gcd(v, n)
121
+ if m > 1:
122
+ return m
123
+ return 2
124
+ c2 = (c - 2) % n
106
125
  # and a point on the curve (or its twist)
107
126
  Q = (pow(u, 3, n), pow(v, 3, n))
108
127
  # Stage one
128
+ if verbose > 1:
129
+ print("1", end= "")
109
130
  Q = mult(stage_one, Q, c2, n)
110
131
  if Q[1] == 0:
111
132
  continue
112
133
  g = gcd(Q[1], n)
113
134
  if g > 1:
135
+ if verbose > 1:
136
+ print("\nFactor found.")
114
137
  return g
115
138
 
116
139
  # Stage two
140
+ if verbose > 1:
141
+ print("2", end= "")
117
142
  S = [dbl(Q, c2, n)]
118
143
  S.append(dbl(S[0], c2, n))
119
144
 
@@ -136,9 +161,16 @@ def factor_ecm(n: int, B1: int = 11000, B2: int = 1900000, curves: int = 74, ecm
136
161
  break
137
162
  g =gcd(g,n)
138
163
  if 1 < g:
164
+ if verbose > 1:
165
+ print("\nFactor found.")
139
166
  return g
140
167
  R, T = add(R, S[D - 1], T, n), R
141
168
 
142
169
  g = gcd(g, n)
143
170
  if 1 < g < n:
171
+ if verbose > 1:
172
+ print("\nFactor found.")
144
173
  return g
174
+ if verbose > 1:
175
+ print(f"\nNo factor after trying {curves} curves.")
176
+
@@ -2,11 +2,13 @@
2
2
  Integer factorization: Fermat's method
3
3
  """
4
4
 
5
- from math import isqrt
5
+ from math import isqrt, log10, floor, log10
6
6
 
7
7
 
8
- def factor_fermat(n: int) -> list:
8
+ def factor_fermat(n: int, maxsteps: int|None = None, verbose: int = 0) -> list:
9
9
  """Find factors of n using the method of Fermat."""
10
+ if verbose:
11
+ print(f"Factoring (Fermat): {n} ({floor(log10(n)) + 1} digits)")
10
12
  factors = []
11
13
  parameters = {11: (12, 6), 23: (12, 0),
12
14
  5: (6, 3), 17: (6, 3),
@@ -20,11 +22,23 @@ def factor_fermat(n: int) -> list:
20
22
  start = isqrt(n - 1) + 1
21
23
  step, mod = parameters[n % 24]
22
24
  start += (mod - start) % step
23
- for a in range(start, (n + 9) // 6 + 1, step):
25
+ if verbose > 1:
26
+ print("Working ", end= "")
27
+ maxa = (n + 9) // 6 + 1
28
+ if maxsteps:
29
+ maxsteps = max(1, maxsteps)
30
+ maxa = min(maxa, start + maxsteps * step + 1)
31
+ for a in range(start, maxa, step):
32
+ if verbose > 1:
33
+ print(".", end= "")
24
34
  b = isqrt(a * a - n)
25
35
  if b * b == a * a - n:
26
36
  factors.append(a - b)
27
37
  factors.append(a + b)
38
+ if verbose > 1:
39
+ print("")
28
40
  return factors
29
41
  factors.append(n)
42
+ if verbose > 1:
43
+ print("")
30
44
  return factors
@@ -0,0 +1,77 @@
1
+ """
2
+ Integer factorization: Pollard's p-1 method
3
+ """
4
+
5
+ from math import gcd, log, floor, log10
6
+ from .primes import sieve_eratosthenes
7
+
8
+ def _pm1_parameters(B1: int, B2: int|None = None, primes: tuple = None):
9
+ "Precompute parameters for the p-1 method."
10
+ if not B2:
11
+ B2 = 100 * B1
12
+ if not primes:
13
+ primes = sieve_eratosthenes(B2)
14
+
15
+ stage_one = 1
16
+ stage_two_deltas = []
17
+ pp = 0
18
+ for p in primes:
19
+ if p <= B1:
20
+ stage_one *= p**int(log(B1, p))
21
+ elif p <= B2:
22
+ stage_two_deltas.append(p - pp) # pylint: disable=W0631
23
+ pp = p
24
+ if p > B2:
25
+ break
26
+
27
+ return stage_one, stage_two_deltas
28
+
29
+
30
+ def factor_pm1(n: int, B1: int = 10000, B2: int|None = None, x: int = 2, pm1_parameters: tuple = None, verbose: int = 0):
31
+ "Factors a number n using Pollard's p-1 method."
32
+ if verbose:
33
+ print(f"Factoring (Pollard p-1, B1={B1}, B2={B2}): {n} ({floor(log10(n)) + 1} digits)")
34
+
35
+ if pm1_parameters:
36
+ stage_one, stage_two_deltas = pm1_parameters
37
+ else:
38
+ stage_one, stage_two_deltas = _pm1_parameters(B1, B2)
39
+
40
+ # stage one
41
+ if verbose > 1:
42
+ print("Working 1", end= "")
43
+ x = pow(x, stage_one, n)
44
+ g = gcd(x - 1, n)
45
+ if g == n:
46
+ return None
47
+ if 1 < g:
48
+ return g
49
+
50
+ if verbose > 1:
51
+ print("2", end= "")
52
+ saved = {}
53
+ y = pow(x, stage_two_deltas[0], n)
54
+ D = (y - 1) % n
55
+ for k, d in enumerate(stage_two_deltas[1:]):
56
+ if not d in saved:
57
+ saved[d] = pow(x, d, n)
58
+ y = y * saved[d] % n
59
+ D = D * (y - 1) % n
60
+ if k % 20 == 0:
61
+ g = gcd(D, n)
62
+ if g == n:
63
+ if verbose > 1:
64
+ print("")
65
+ return None
66
+ if 1 < g:
67
+ if verbose > 1:
68
+ print("\nFactor found.")
69
+ return g
70
+ g = gcd(D, n)
71
+ if 1 < g < n:
72
+ if verbose > 1:
73
+ print("\nFactor found.")
74
+ return g
75
+ if verbose > 1:
76
+ print("")
77
+ return None
@@ -2,7 +2,7 @@
2
2
  Integer factorization: Quadratic sieve
3
3
  """
4
4
 
5
- from math import isqrt, gcd, sqrt, log, exp, ceil
5
+ from math import isqrt, gcd, sqrt, log, exp, ceil, floor, log10
6
6
  from .primes import sieve_eratosthenes
7
7
  from .nt import legendre_symbol, sqrt_mod
8
8
 
@@ -24,7 +24,7 @@ def bytetest(a: bytes, i: int) -> bytes:
24
24
  return (a[i1] & 2**i0) != 0
25
25
 
26
26
 
27
- def factor_qs(n: int) -> list:
27
+ def factor_qs(n: int, verbose: int = 0) -> list:
28
28
  """Find factors of n using the quadratic sieve."""
29
29
  # first determine the bound B for the factorbase: Choosing B=p^(1/u) Canfield-Erdös-Pomerance gives us
30
30
  # the expected running time |B|^2 u^u = u^(u+2) p^(2/u)/log(n). There is no explicit expression for the optimum, hence
@@ -37,10 +37,16 @@ def factor_qs(n: int) -> list:
37
37
  B = int(exp(log(n) / u))
38
38
  # B = int(exp(0.5 * sqrt( log(n) * log(log(n)) )*( 1 + 1/log(log(n)) )))
39
39
 
40
+ if verbose:
41
+ print(f"Factoring (QS, B={B}): {n} ({floor(log10(n)) + 1} digits)")
42
+ if verbose > 1:
43
+ print(f"Setting up factorbase: B={B}", end="")
40
44
  factorbase = []
41
45
  for p in sieve_eratosthenes(B): # compute the factorbase
42
46
  ls = legendre_symbol(n, p)
43
47
  if ls == 0: # we already found a factor;-)
48
+ if verbose > 1:
49
+ print("\nFound a small prime factor.")
44
50
  if n == p:
45
51
  return n
46
52
  return p
@@ -49,6 +55,8 @@ def factor_qs(n: int) -> list:
49
55
  lf = len(factorbase) # length of the factorbase (including -1)
50
56
  lfb = ceil((lf+1) / 8) # the number of bytes we need to store a relation
51
57
 
58
+ if verbose > 1:
59
+ print(f" len={lf}", end ="")
52
60
  factorbase_log = [log(p) for p in factorbase] # we add these up to test if a number will probably factor
53
61
  factorbase_root = [0] * lf # compute the roots of n mod p
54
62
  for i, p in enumerate(factorbase):
@@ -66,13 +74,18 @@ def factor_qs(n: int) -> list:
66
74
  return m
67
75
  m2 = 2 * m
68
76
 
77
+ if verbose > 1:
78
+ print(" done.")
79
+
69
80
  relation_no = -1
70
81
  relations = [None] * (lf + 1) # here we will store the relations in case we found a B-smooth number
71
82
  values = [None] * (lf + 1) # here we will store the values leading to the B-smooth numbers
72
83
 
73
84
  # set up the sieve
74
- sieve_step = 100
75
- sieve_bound = sieve_step
85
+ expected_trys = int(exp(u*log(u/2)/2))+1 # expected number of trys to find a relation for sieved values
86
+ sieve_bound = max(100, expected_trys * lf)
87
+ sieve_step = sieve_bound // 10
88
+
76
89
  # start values for the iterators in the positive/negative direction
77
90
  iterator_p = [ [0, 0] for _ in range(lf) ]
78
91
  iterator_m = [ [0, 0] for _ in range(lf) ]
@@ -122,10 +135,10 @@ def factor_qs(n: int) -> list:
122
135
  # print(f'{j:3}', ' '.join(f'{b:08b}' for b in reversed(relation)))
123
136
  if index == lf: # the new relation is linearly dependent: we have found a linear combination of the 0 vector
124
137
  # now we need to determine the factors
125
- u = 1 # product over all values m - j such that f(m-j) is B-smooth
126
- v = 1 # sqrt of the product over all f(m-j) which are B-smooth
138
+ u = 1 # product over all values m + j such that f(m+j) is B-smooth
139
+ v = 1 # sqrt of the product over all f(m+j) which are B-smooth
127
140
  w = 1 # save nonsquare terms for the next round
128
- for i in range(lf):
141
+ for i in range(lf + 1):
129
142
  if bytetest(relation, lfb * 8 + i): # select the relations which sum to the 0 vector
130
143
  ui = m + values[i]
131
144
  u = (u * ui) % n
@@ -137,14 +150,20 @@ def factor_qs(n: int) -> list:
137
150
  res = gcd(u - v, n)
138
151
  if 1 < res < n:
139
152
  return res
153
+ if verbose > 1:
154
+ print("X", end="")
140
155
  relation_no -= 1 # this one did not work, try again
141
156
  else:
142
157
  relations[index] = relation
158
+ if verbose > 1:
159
+ print(".", end="")
143
160
  return None
144
161
 
145
- while True:
162
+ for _ in range(expected_trys * lf * 100):
146
163
  factors = {} # store the index of the primes dividing j
147
164
 
165
+ if verbose > 1:
166
+ print("S", end="")
148
167
  do_sieve()
149
168
 
150
169
  for j in sorted(factors.keys(),key=abs):
@@ -157,7 +176,7 @@ def factor_qs(n: int) -> list:
157
176
  v *= -1
158
177
  for i in primes:
159
178
  p = factorbase[i]
160
- k = 1 # per our sieve we already know that p devides v
179
+ k = 1 # per our sieve we already know that p divides v
161
180
  v //= p
162
181
  while v % p == 0: # divide by p as many times as possible
163
182
  k = (k + 1) % 2 # we only want to know if the exponent is even or odd
@@ -167,8 +186,14 @@ def factor_qs(n: int) -> list:
167
186
  if v == 1:
168
187
  res = process_relation(j, mask)
169
188
  if res:
189
+ if verbose:
190
+ print(f"\nFactor found after {relation_no} relations.")
170
191
  return res
171
192
  del factors[j]
172
193
  else:
173
194
  del factors[j] # the number is unlikely to factor
174
195
  sieve_bound += sieve_step # increase the sieve and continue
196
+ if verbose > 1:
197
+ print("")
198
+ if verbose:
199
+ print("QS failed.")
@@ -125,12 +125,15 @@ def iroot(k: int, n: int) -> int:
125
125
  return n
126
126
  if k == 2:
127
127
  return isqrt(n)
128
- rr = isqrt(n)
128
+ r = isqrt(n)
129
+ while r**k >= n:
130
+ rr = r
131
+ r = isqrt(r)
129
132
  r =rr + 1
130
133
  k1 = k-1
131
134
  while rr < r:
132
135
  r = rr
133
- rr = (k1 * r + n // r ** k1) // k # Newton iteration
136
+ rr = (k1 * rr + n // rr ** k1) // k # Newton iteration
134
137
  return r
135
138
 
136
139
  def perfect_power(n: int) -> tuple|None:
@@ -184,15 +187,16 @@ def lucas_test(n: int) -> bool:
184
187
  Qk = pow(Qk, 2, n)
185
188
  return False
186
189
 
187
- def is_prime(n: int) -> bool:
190
+ def is_prime(n: int, trialdivision: bool = True) -> bool:
188
191
  """Test if an integer `n` if probable prime."""
189
192
  # 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
193
+ if trialdivision:
194
+ 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,
195
+ 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
196
+ 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293,
197
+ 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397):
198
+ if n % p == 0:
199
+ return n == p
196
200
  if n < 18446744073709551616: # https://miller-rabin.appspot.com
197
201
  return miller_rabin_test(n, [2, 325, 9375, 28178, 450775, 9780504, 1795265022])
198
202
  if n < 3317044064679887385961981:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kryptools
3
- Version: 0.9.5
3
+ Version: 0.9.6
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.5"
3
+ version = "0.9.6"
4
4
  authors = [
5
5
  { name="Gerald Teschl", email="gerald.teschl@univie.ac.at" },
6
6
  ]
@@ -1,58 +0,0 @@
1
- """
2
- Integer factorization: Pollard's p-1 method
3
- """
4
-
5
- from math import gcd, log
6
- from .primes import sieve_eratosthenes
7
-
8
- def _pm1_parameters(B1: int, B2: int = None, primes: tuple = None):
9
- "Precompute parameters for the P-1 method."
10
- if not B2:
11
- B2 = 100 * B1
12
- if not primes:
13
- primes = sieve_eratosthenes(B2)
14
-
15
- stage_one = 1
16
- for p in primes:
17
- if p > B1:
18
- break
19
- stage_one *= p**int(log(B1, p))
20
-
21
- stage_two_deltas = []
22
- for q in primes:
23
- if q <= B1:
24
- continue
25
- if q > B2:
26
- break
27
- stage_two_deltas.append(q - p) # pylint: disable=W0631
28
-
29
- return stage_one, stage_two_deltas
30
-
31
-
32
- def factor_pm1(n: int, B1: int = 11000, B2: int = 1900000, x: int = 2, pm1_parameters: tuple = None):
33
- "Factors a number n using Pollard's P-1 method."
34
-
35
- if pm1_parameters:
36
- stage_one, stage_two_deltas = pm1_parameters
37
- else:
38
- stage_one, stage_two_deltas = _pm1_parameters(B1, B2)
39
-
40
- g = gcd(pow(x, stage_one, n) - 1, n)
41
- if 1 < g < n:
42
- return g
43
- k = 0
44
- for d in stage_two_deltas:
45
- saved = {}
46
- if not d in saved:
47
- y = pow(x, d, n)
48
- saved[d] = y
49
- x = (x * saved[d]) % n
50
- k += 1
51
- if k % 20 == 0:
52
- g = gcd(x-1, n)
53
- if 1 < g < n:
54
- return g
55
- g = gcd(x-1, n)
56
- if 1 < g < n:
57
- return g
58
- return None
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