kryptools 1.5.1__tar.gz → 1.5.2__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-1.5.1 → kryptools-1.5.2}/PKG-INFO +7 -1
- {kryptools-1.5.1 → kryptools-1.5.2}/README.md +7 -1
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/GF2.py +10 -10
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/Zmod.py +2 -1
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/aes.py +4 -4
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/blockcipher.py +5 -5
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/code.py +21 -23
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/des.py +1 -1
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/dlp_ic.py +4 -4
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/dlp_qs.py +4 -4
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/dlp_rho.py +1 -1
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/factor.py +27 -24
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/factor_qs.py +1 -1
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/keccak.py +3 -3
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/la.py +5 -5
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/nt.py +11 -13
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/poly.py +21 -31
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/sha1.py +1 -2
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools.egg-info/PKG-INFO +7 -1
- {kryptools-1.5.1 → kryptools-1.5.2}/pyproject.toml +1 -1
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_GF2.py +7 -6
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_Zmod.py +7 -7
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_aes.py +2 -1
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_code.py +3 -2
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_des.py +2 -1
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_dlog.py +3 -2
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_ec.py +4 -3
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_factor.py +3 -2
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_factor_fmt.py +3 -2
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_factor_pm1.py +2 -1
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_factor_qs.py +2 -1
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_intfuncs.py +7 -6
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_keccak.py +19 -18
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_la.py +4 -3
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_lat.py +3 -2
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_nt.py +8 -7
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_poly.py +10 -10
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_primes.py +5 -4
- {kryptools-1.5.1 → kryptools-1.5.2}/tests/test_sha1.py +2 -1
- {kryptools-1.5.1 → kryptools-1.5.2}/LICENSE +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/__init__.py +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/conway_polynomials.py +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/dlp.py +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/dlp_bsgs.py +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/ec.py +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/factor_dix.py +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/factor_ecm.py +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/factor_fmt.py +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/factor_pm1.py +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/factor_rho.py +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/intfuncs.py +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/lat.py +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools/primes.py +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools.egg-info/SOURCES.txt +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools.egg-info/dependency_links.txt +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/kryptools.egg-info/top_level.txt +0 -0
- {kryptools-1.5.1 → kryptools-1.5.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kryptools
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.2
|
|
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
|
|
@@ -16,6 +16,12 @@ Description-Content-Type: text/markdown
|
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Dynamic: license-file
|
|
18
18
|
|
|
19
|
+
[](https://pypi.org/project/kryptools)
|
|
20
|
+
[](https://www.python.org)
|
|
21
|
+
[](https://github.com/teschlg/kryptools/blob/main/LICENSE)
|
|
22
|
+
[](https://github.com/teschlg/kryptools/actions/workflows/pylint.yml)
|
|
23
|
+
[](https://github.com/teschlg/kryptools/actions/workflows/run_test.yml)
|
|
24
|
+
|
|
19
25
|
# kryptools
|
|
20
26
|
Gerald Teschl <Gerald.Teschl@univie.ac.at>
|
|
21
27
|
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
[](https://pypi.org/project/kryptools)
|
|
2
|
+
[](https://www.python.org)
|
|
3
|
+
[](https://github.com/teschlg/kryptools/blob/main/LICENSE)
|
|
4
|
+
[](https://github.com/teschlg/kryptools/actions/workflows/pylint.yml)
|
|
5
|
+
[](https://github.com/teschlg/kryptools/actions/workflows/run_test.yml)
|
|
6
|
+
|
|
1
7
|
# kryptools
|
|
2
8
|
Gerald Teschl <Gerald.Teschl@univie.ac.at>
|
|
3
9
|
|
|
@@ -39,4 +45,4 @@ The tools contained are:
|
|
|
39
45
|
* Keccak: individual sponge operations, SHA3, SHAKE
|
|
40
46
|
|
|
41
47
|
Documentation can be found in the jupyter notebook
|
|
42
|
-
(mostly done, but might not contain everything: use the force, read the source).
|
|
48
|
+
(mostly done, but might not contain everything: use the force, read the source).
|
|
@@ -135,7 +135,7 @@ class GF2:
|
|
|
135
135
|
class GF2nPoint:
|
|
136
136
|
"Represents a point in the Galois field GF(2^n)."
|
|
137
137
|
|
|
138
|
-
def __init__(self, x: int, field: "
|
|
138
|
+
def __init__(self, x: int, field: "GF2"):
|
|
139
139
|
if isinstance(x, bytes | bytearray):
|
|
140
140
|
x = int.from_bytes(x, byteorder=field.byteorder)
|
|
141
141
|
self.x = int(x) % field.order
|
|
@@ -278,16 +278,16 @@ class GF2nPoint:
|
|
|
278
278
|
x *= x
|
|
279
279
|
return res
|
|
280
280
|
|
|
281
|
-
def __lshift__(self,
|
|
281
|
+
def __lshift__(self, j: int) -> "GF2nPoint":
|
|
282
282
|
"Cyclic rotation to the left."
|
|
283
|
-
x = self.x <<
|
|
283
|
+
x = self.x << j
|
|
284
284
|
x = (x % self.field.order) + (x // self.field.order)
|
|
285
285
|
return self.field(x)
|
|
286
286
|
|
|
287
|
-
def __rshift__(self,
|
|
287
|
+
def __rshift__(self, j: int) -> "GF2nPoint":
|
|
288
288
|
"Cyclic rotation to the right."
|
|
289
|
-
x = self.x >>
|
|
290
|
-
x += (self.field.order >>
|
|
289
|
+
x = self.x >> j
|
|
290
|
+
x += (self.field.order >> j) * (self.x % 2**j)
|
|
291
291
|
return self.field(x)
|
|
292
292
|
|
|
293
293
|
def sqrt(self) -> "GF2nPoint":
|
|
@@ -298,7 +298,7 @@ class GF2nPoint:
|
|
|
298
298
|
|
|
299
299
|
def order(self) -> int:
|
|
300
300
|
"Compute the order of the point in the group GF(2^n)^*."
|
|
301
|
-
self.field._factors()
|
|
301
|
+
self.field._factors() # pylint: disable=W0212
|
|
302
302
|
order = self.field.mult_order # our current guess
|
|
303
303
|
one = self.field.one()
|
|
304
304
|
for p, k in self.field.factors.items():
|
|
@@ -320,7 +320,7 @@ class GF2nPoint:
|
|
|
320
320
|
if inv:
|
|
321
321
|
return aes_sbox_inv[self.x]
|
|
322
322
|
return aes_sbox[self.x]
|
|
323
|
-
|
|
323
|
+
if self.field.degree == 4 and self.field.modulus == 0b10011: # MiniAES
|
|
324
324
|
if inv:
|
|
325
325
|
return miniaes_sbox_inv[self.x]
|
|
326
326
|
return miniaes_sbox[self.x]
|
|
@@ -353,7 +353,7 @@ for i in range(256):
|
|
|
353
353
|
aes_sbox = list(map(GF2_aes, aes_sbox))
|
|
354
354
|
aes_sbox_inv = list(map(GF2_aes, aes_sbox_inv))
|
|
355
355
|
|
|
356
|
-
|
|
356
|
+
|
|
357
357
|
# sbox for Mini-AES
|
|
358
358
|
GF2_miniaes = GF2(4, 0b10011) # x^4 + x + 1 = Mini-AES
|
|
359
359
|
|
|
@@ -369,4 +369,4 @@ miniaes_sbox_inv = list(map(GF2_miniaes, miniaes_sbox_inv))
|
|
|
369
369
|
|
|
370
370
|
#Ghash
|
|
371
371
|
|
|
372
|
-
GF2_ghash = GF2(128, 0b11100001 << 120) # 1 + x + x^2 + x^7 (+ x^128) = Ghash
|
|
372
|
+
GF2_ghash = GF2(128, 0b11100001 << 120) # 1 + x + x^2 + x^7 (+ x^128) = Ghash
|
|
@@ -267,6 +267,7 @@ class ZmodPoint:
|
|
|
267
267
|
return order
|
|
268
268
|
|
|
269
269
|
def sqrt(self) -> "ZmodPoint":
|
|
270
|
+
"Compute a square root of the point."
|
|
270
271
|
if not self.ring.n_factors:
|
|
271
272
|
self.ring.n_factors = factorint(self.ring.n)
|
|
272
273
|
a = int(self)
|
|
@@ -297,7 +298,7 @@ class ZmodPoint:
|
|
|
297
298
|
raise ValueError("No quadratic residue!")
|
|
298
299
|
m = 4 # start at 2^2
|
|
299
300
|
x = ak % m # this is the root mod m
|
|
300
|
-
for
|
|
301
|
+
for _ in range(3, k + 1):
|
|
301
302
|
# test all 4 poosible roots
|
|
302
303
|
if (x**2 - ak) % (m * 2):
|
|
303
304
|
x = m - x
|
|
@@ -144,18 +144,18 @@ class AESKeySchedule:
|
|
|
144
144
|
#RotWord
|
|
145
145
|
tmp = list(self.key[:,3])
|
|
146
146
|
if self.showtmp:
|
|
147
|
-
|
|
147
|
+
print("Start :" + str(tmp))
|
|
148
148
|
tmp = rotate_left(tmp, 1)
|
|
149
149
|
if self.showtmp:
|
|
150
|
-
|
|
150
|
+
print("RotWord :" + str(tmp))
|
|
151
151
|
#SubWord
|
|
152
152
|
tmp = list(map(lambda x: x.sbox(), tmp))
|
|
153
153
|
if self.showtmp:
|
|
154
|
-
|
|
154
|
+
print("SubWord :" + str(tmp))
|
|
155
155
|
#AddRound constant
|
|
156
156
|
tmp[0] += GF2_aes(2)**(self.round - 1)
|
|
157
157
|
if self.showtmp:
|
|
158
|
-
|
|
158
|
+
print("AddConst :" + str(tmp))
|
|
159
159
|
tmp = Matrix(tmp)
|
|
160
160
|
self.key[:,0] += tmp
|
|
161
161
|
self.key[:,1] += self.key[:,0]
|
|
@@ -50,9 +50,9 @@ class BlockCipher:
|
|
|
50
50
|
"Encrypt using the given mode."
|
|
51
51
|
if mode is None:
|
|
52
52
|
mode = self.mode
|
|
53
|
-
|
|
53
|
+
if hasattr(self, "encrypt_" + mode.lower()):
|
|
54
54
|
method = getattr(self, "encrypt_" + mode.lower())
|
|
55
|
-
|
|
55
|
+
else:
|
|
56
56
|
raise ValueError("Unsupported encryption mode: ", mode)
|
|
57
57
|
if key:
|
|
58
58
|
self.set_key(key)
|
|
@@ -62,9 +62,9 @@ class BlockCipher:
|
|
|
62
62
|
"Decrypt using the given mode."
|
|
63
63
|
if mode is None:
|
|
64
64
|
mode = self.mode
|
|
65
|
-
|
|
65
|
+
if hasattr(self, "decrypt_" + mode):
|
|
66
66
|
method = getattr(self, "decrypt_" + mode)
|
|
67
|
-
|
|
67
|
+
else:
|
|
68
68
|
raise ValueError("Unsupported encryption mode: ", mode)
|
|
69
69
|
if key:
|
|
70
70
|
self.set_key(key)
|
|
@@ -218,7 +218,7 @@ class BlockCipher:
|
|
|
218
218
|
key_extra ^= R_b
|
|
219
219
|
|
|
220
220
|
pad = len(text) % self.__class__.blocksize
|
|
221
|
-
if pad or not
|
|
221
|
+
if pad or not text:
|
|
222
222
|
# Compute key K2
|
|
223
223
|
text += b'\x80' + b'\x00' * (self.__class__.blocksize - pad - 1)
|
|
224
224
|
msb = key_extra >> (self.__class__.blocksize * 8 - 1)
|
|
@@ -85,7 +85,7 @@ class Goppa():
|
|
|
85
85
|
|
|
86
86
|
def __init__(self, gf: GF2, g: Poly, alpha: list["GF2Point"]):
|
|
87
87
|
if not all(map(lambda x: x in gf, alpha)):
|
|
88
|
-
raise ValueError(
|
|
88
|
+
raise ValueError("All elements of alpha must be from the Galois field!")
|
|
89
89
|
if not g.rabin_test():
|
|
90
90
|
raise ValueError("The polynomial g must be irreducible!")
|
|
91
91
|
self.gf = gf # underlying Galois field
|
|
@@ -166,16 +166,14 @@ class CyclicCode():
|
|
|
166
166
|
if n < 2:
|
|
167
167
|
raise ValueError(f"Code lenght {n} must be at least 2!")
|
|
168
168
|
zero = 0 * g[0]
|
|
169
|
-
|
|
169
|
+
if hasattr(zero, "ring"):
|
|
170
170
|
order = zero.ring.n # Zmod
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
except:
|
|
178
|
-
raise ValueError("Unknown base filed!")
|
|
171
|
+
elif hasattr(zero, "field"):
|
|
172
|
+
order = zero.field.order # GF2
|
|
173
|
+
elif hasattr(type(zero), "order"):
|
|
174
|
+
order = type(zero).order # galois
|
|
175
|
+
else:
|
|
176
|
+
raise ValueError("Unknown base field!")
|
|
179
177
|
self.order = order # order of the base field
|
|
180
178
|
one = zero**0
|
|
181
179
|
modulus = Poly([-one] + [zero] * (n-1) + [one])
|
|
@@ -189,7 +187,7 @@ class CyclicCode():
|
|
|
189
187
|
|
|
190
188
|
def __repr__(self):
|
|
191
189
|
return f"Cyclic [{self.n}, {self.k}] code over GF({self.order}) with generator polynomial g(x) = {self.g}."
|
|
192
|
-
|
|
190
|
+
|
|
193
191
|
def encode(self, x: list|Poly, gf = None, systematic_form = False):
|
|
194
192
|
"Encode a given list or polynomial."
|
|
195
193
|
as_list = False
|
|
@@ -219,7 +217,7 @@ class CyclicCode():
|
|
|
219
217
|
raise ValueError(f"Degree can be at most {self.n-1}.")
|
|
220
218
|
x, r = y.divmod(self.g)
|
|
221
219
|
if r:
|
|
222
|
-
raise NotImplementedError(
|
|
220
|
+
raise NotImplementedError("Word is no code word! Cannot decode.")
|
|
223
221
|
if systematic_form:
|
|
224
222
|
x.coeff = y.coeff[self.g.degree():]
|
|
225
223
|
if as_list:
|
|
@@ -256,24 +254,24 @@ class ReedSolomonCode(CyclicCode):
|
|
|
256
254
|
[0, 1, 0]
|
|
257
255
|
|
|
258
256
|
"""
|
|
259
|
-
def __init__(self, k:int, gf, alpha = None):
|
|
257
|
+
def __init__(self, k:int, gf, alpha = None): # pylint: disable=W0231
|
|
260
258
|
zero = gf(0)
|
|
261
259
|
one = zero**0
|
|
262
|
-
self.
|
|
263
|
-
|
|
264
|
-
n = gf.
|
|
265
|
-
|
|
266
|
-
n = gf.order - 1
|
|
260
|
+
self.gf = gf
|
|
261
|
+
if hasattr(gf, "n"):
|
|
262
|
+
n = gf.n - 1 # Zmod
|
|
263
|
+
else:
|
|
264
|
+
n = gf.order - 1 # GF2|galois
|
|
267
265
|
self.order = n + 1 # order of the base field
|
|
268
266
|
self.n = n # lenght
|
|
269
267
|
self.k = k # dimension
|
|
270
268
|
self.d = n - k - 1 # minimal distance
|
|
271
269
|
self.modulus = Poly([-one] + [zero] * (n-1) + [one])
|
|
272
270
|
if alpha is None:
|
|
273
|
-
|
|
274
|
-
alpha = gf.generator() # Zmod|GF2
|
|
275
|
-
except:
|
|
271
|
+
if hasattr(gf, "primitive_element"):
|
|
276
272
|
alpha = gf.primitive_element # galois
|
|
273
|
+
else:
|
|
274
|
+
alpha = gf.generator() # Zmod|GF2
|
|
277
275
|
self.alpha = alpha
|
|
278
276
|
self.g = prod([Poly([-alpha**j, one]) for j in range(1,n-k+1)], start = one) # generating polynomial
|
|
279
277
|
self.h = Poly(self.modulus) // self.g # check polynomial
|
|
@@ -283,7 +281,7 @@ class ReedSolomonCode(CyclicCode):
|
|
|
283
281
|
def __repr__(self):
|
|
284
282
|
return f"Reed-Solomon-Code [{self.n}, {self.k}, {self.d}] over GF({self.n+1})."
|
|
285
283
|
|
|
286
|
-
def encode(self, x: list|Poly):
|
|
284
|
+
def encode(self, x: list|Poly): # pylint: disable=W0221
|
|
287
285
|
"Encode a given list or polynomial."
|
|
288
286
|
as_list = False
|
|
289
287
|
zero = 0 * self.g[0]
|
|
@@ -297,7 +295,7 @@ class ReedSolomonCode(CyclicCode):
|
|
|
297
295
|
return y + [zero] * (self.n - len(y))
|
|
298
296
|
return Poly(y)
|
|
299
297
|
|
|
300
|
-
def decode(self, y: list|Poly):
|
|
298
|
+
def decode(self, y: list|Poly): # pylint: disable=W0221
|
|
301
299
|
"Decode a given list or polynomial."
|
|
302
300
|
as_list = False
|
|
303
301
|
zero = 0 * self.g[0]
|
|
@@ -171,7 +171,7 @@ class FeistelCipher:
|
|
|
171
171
|
def printtmp(title: str, a: list) -> None:
|
|
172
172
|
print(f'{title}: {"".join(map(str,a))}')
|
|
173
173
|
else:
|
|
174
|
-
def printtmp(title: str, a: list) -> None:
|
|
174
|
+
def printtmp(title: str, a: list) -> None: # pylint: disable=W0613
|
|
175
175
|
pass
|
|
176
176
|
a = permute(a, self.__class__.E_box) # expansion box
|
|
177
177
|
printtmp("EBox", a)
|
|
@@ -37,7 +37,7 @@ def dlog_ic(a: int, b: int, n: int, m: int, pollard: bool = True, verbose: int =
|
|
|
37
37
|
break
|
|
38
38
|
trys += 1
|
|
39
39
|
else:
|
|
40
|
-
raise
|
|
40
|
+
raise RuntimeWarning(f"Sorry, Index Calculus failed to find a relation after {trys} trys.")
|
|
41
41
|
if verbose > 2:
|
|
42
42
|
if include_b:
|
|
43
43
|
print(f"rel found: b*a^{x}=", b * pow(a, x, n) % n, relation)
|
|
@@ -101,7 +101,7 @@ def dlog_ic(a: int, b: int, n: int, m: int, pollard: bool = True, verbose: int =
|
|
|
101
101
|
x = (m - relations[index][len_relations]) % m
|
|
102
102
|
if pow(a, x, n) == b:
|
|
103
103
|
return x
|
|
104
|
-
raise
|
|
104
|
+
raise RuntimeWarning("Sorry, Index Calculus failed! Either the DLP is not solvable, or the order is not prime or incorrect.")
|
|
105
105
|
|
|
106
106
|
#
|
|
107
107
|
# Determine the parameters
|
|
@@ -111,7 +111,7 @@ def dlog_ic(a: int, b: int, n: int, m: int, pollard: bool = True, verbose: int =
|
|
|
111
111
|
factorbase = tuple(p for p in sieve_eratosthenes(B) if gcd(p,n) == 1) # compute the factorbse
|
|
112
112
|
factorbase_len = len(factorbase) # length of the factorbase
|
|
113
113
|
if factorbase_len == 0:
|
|
114
|
-
raise
|
|
114
|
+
raise RuntimeWarning("Sorry, Index Calculus could not find a factorbase!")
|
|
115
115
|
smallprimes_len, pollard_k = factorbase_len, None
|
|
116
116
|
if pollard: # should we speed up trial division with Pollard p-1
|
|
117
117
|
smallprimes_len, pollard_k = determine_trialdivison_bounds(B // 150, factorbase)
|
|
@@ -137,4 +137,4 @@ def dlog_ic(a: int, b: int, n: int, m: int, pollard: bool = True, verbose: int =
|
|
|
137
137
|
if res:
|
|
138
138
|
return res
|
|
139
139
|
|
|
140
|
-
raise
|
|
140
|
+
raise RuntimeWarning("Sorry, Index Calculus could not find enough relations! ({n_relations} - {n_relations_redundant} = {n_relations - n_relations_redundant} out of {len_relations})")
|
|
@@ -97,7 +97,7 @@ def dlog_qs(a: int, b: int, n: int, m: int, pollard: bool = True, sieve_factor:
|
|
|
97
97
|
break
|
|
98
98
|
trys += 1
|
|
99
99
|
else:
|
|
100
|
-
raise
|
|
100
|
+
raise RuntimeWarning(f"Sorry, Quadratic Sieve failed to find a new relation after {trys} trys.")
|
|
101
101
|
if verbose > 2:
|
|
102
102
|
if include_b:
|
|
103
103
|
print(f"rel found: b*a^{x}=", b * pow(a, x, n) % n, relation)
|
|
@@ -160,7 +160,7 @@ def dlog_qs(a: int, b: int, n: int, m: int, pollard: bool = True, sieve_factor:
|
|
|
160
160
|
x = (m - relations[index][len_relations]) % m
|
|
161
161
|
if pow(a, x, n) == b:
|
|
162
162
|
return x
|
|
163
|
-
raise
|
|
163
|
+
raise RuntimeWarning("Sorry, Quadratic Sieve failed! Either the DLP is not solvable or the order is not prime or incorrect.")
|
|
164
164
|
|
|
165
165
|
#
|
|
166
166
|
# Determine the parameters
|
|
@@ -173,7 +173,7 @@ def dlog_qs(a: int, b: int, n: int, m: int, pollard: bool = True, sieve_factor:
|
|
|
173
173
|
factorbase_log = [log(p) for p in factorbase] # we add these up to test if a number will probably factor
|
|
174
174
|
factorbase_len = len(factorbase) # length of the factorbase
|
|
175
175
|
if factorbase_len == 0:
|
|
176
|
-
raise
|
|
176
|
+
raise RuntimeWarning("Sorry, Index Calculus could not find a factorbase!")
|
|
177
177
|
smallprimes_len, pollard_k = factorbase_len, None
|
|
178
178
|
if pollard: # should we speed up trial division with Pollard p-1
|
|
179
179
|
smallprimes_len, pollard_k = determine_trialdivison_bounds(B // 150, factorbase)
|
|
@@ -300,4 +300,4 @@ def dlog_qs(a: int, b: int, n: int, m: int, pollard: bool = True, sieve_factor:
|
|
|
300
300
|
if res:
|
|
301
301
|
return res
|
|
302
302
|
|
|
303
|
-
raise
|
|
303
|
+
raise RuntimeWarning(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,21 +55,22 @@ def factorint(n: int, trial_bnd: int = 2500, verbose: int = 0) -> dict:
|
|
|
55
55
|
prime_factors[-1] = 1
|
|
56
56
|
|
|
57
57
|
def add_factors(m: int, mm: tuple) -> None:
|
|
58
|
+
"Delete m from remaining factors and add its factors mm to the appropriate dict."
|
|
58
59
|
k = remaining_factors[m]
|
|
59
60
|
del remaining_factors[m]
|
|
60
61
|
|
|
61
|
-
for
|
|
62
|
-
if
|
|
63
|
-
prime_factors[
|
|
64
|
-
elif is_prime(
|
|
65
|
-
prime_factors[
|
|
62
|
+
for m_i in mm:
|
|
63
|
+
if m_i in prime_factors:
|
|
64
|
+
prime_factors[m_i] += k
|
|
65
|
+
elif is_prime(m_i, trialdivision=False):
|
|
66
|
+
prime_factors[m_i] = k
|
|
66
67
|
else:
|
|
67
|
-
if
|
|
68
|
-
remaining_factors[
|
|
69
|
-
elif
|
|
70
|
-
new_factors[
|
|
68
|
+
if m_i in remaining_factors:
|
|
69
|
+
remaining_factors[m_i] += k
|
|
70
|
+
elif m_i in new_factors:
|
|
71
|
+
new_factors[m_i] += k
|
|
71
72
|
else:
|
|
72
|
-
new_factors[
|
|
73
|
+
new_factors[m_i] = k
|
|
73
74
|
|
|
74
75
|
if verbose:
|
|
75
76
|
print(f"Factoring: {n} ({floor(log10(n)) + 1} digits)")
|
|
@@ -92,7 +93,7 @@ def factorint(n: int, trial_bnd: int = 2500, verbose: int = 0) -> dict:
|
|
|
92
93
|
if res:
|
|
93
94
|
n, k = res
|
|
94
95
|
else:
|
|
95
|
-
|
|
96
|
+
k = 1
|
|
96
97
|
if is_prime(n, trialdivision=False):
|
|
97
98
|
prime_factors[n] = k
|
|
98
99
|
return prime_factors
|
|
@@ -114,7 +115,7 @@ def factorint(n: int, trial_bnd: int = 2500, verbose: int = 0) -> dict:
|
|
|
114
115
|
]
|
|
115
116
|
fermat_steps = 10
|
|
116
117
|
|
|
117
|
-
for
|
|
118
|
+
for nr, parameters in enumerate(ECM_PARAMETERS):
|
|
118
119
|
fermat_steps += 10
|
|
119
120
|
B1, B2, num_curves = parameters
|
|
120
121
|
p_max = isqrt(max(remaining_factors))+1
|
|
@@ -126,7 +127,7 @@ def factorint(n: int, trial_bnd: int = 2500, verbose: int = 0) -> dict:
|
|
|
126
127
|
D = isqrt(B2)
|
|
127
128
|
|
|
128
129
|
if verbose:
|
|
129
|
-
print(f"Round {
|
|
130
|
+
print(f"Round {nr+1} (B1={B1})")
|
|
130
131
|
|
|
131
132
|
primes = sieve_eratosthenes(B1 - 1 + ((B2 - B1 + 1) // (2 * D) + 1) * 2 * D)
|
|
132
133
|
pm1_parameters = tuple([10 * B1, B2] + list(_pm1_parameters(10 * B1, B2, primes=primes)))
|
|
@@ -135,14 +136,14 @@ def factorint(n: int, trial_bnd: int = 2500, verbose: int = 0) -> dict:
|
|
|
135
136
|
methods = {_factor_fermat: "fmt", factor_pm1: "pm1", factor_ecm: "ecm"} #, factor_qs: "qs"}
|
|
136
137
|
while remaining_factors:
|
|
137
138
|
new_factors = {}
|
|
138
|
-
for method in methods:
|
|
139
|
-
factors = list(remaining_factors)
|
|
139
|
+
for method, method_name in methods.items():
|
|
140
|
+
factors = list(remaining_factors) # make a copy to avoid a runtime error if the dict changes
|
|
140
141
|
for m in factors:
|
|
141
|
-
if method == _factor_fermat:
|
|
142
|
+
if method == _factor_fermat: # pylint: disable=W0143
|
|
142
143
|
tmp = _factor_fermat(m, maxsteps=fermat_steps, verbose=max(0, verbose - 1))
|
|
143
|
-
elif method == factor_pm1:
|
|
144
|
+
elif method == factor_pm1: # pylint: disable=W0143
|
|
144
145
|
tmp = factor_pm1(m, pm1_parameters=pm1_parameters, verbose=max(0, verbose - 1))
|
|
145
|
-
elif method == factor_ecm:
|
|
146
|
+
elif method == factor_ecm: # pylint: disable=W0143
|
|
146
147
|
tmp = factor_ecm(m, ecm_parameters=ecm_parameters, verbose=max(0, verbose - 1))
|
|
147
148
|
else:
|
|
148
149
|
tmp = method(m, verbose=max(0, verbose - 1))
|
|
@@ -160,16 +161,18 @@ def factorint(n: int, trial_bnd: int = 2500, verbose: int = 0) -> dict:
|
|
|
160
161
|
tmp3.append(x)
|
|
161
162
|
else:
|
|
162
163
|
tmp3 = [tmp, tmp2]
|
|
163
|
-
if verbose > 0:
|
|
164
|
+
if verbose > 0:
|
|
165
|
+
print(f"Factors found ({method_name}): ", tmp3)
|
|
164
166
|
add_factors(m, tmp3)
|
|
165
167
|
if not new_factors:
|
|
166
168
|
break
|
|
167
|
-
for m in new_factors:
|
|
169
|
+
for m, k in new_factors.items():
|
|
168
170
|
if m in remaining_factors:
|
|
169
|
-
remaining_factors[m] +=
|
|
171
|
+
remaining_factors[m] += k
|
|
170
172
|
else:
|
|
171
|
-
remaining_factors[m] =
|
|
172
|
-
if verbose > 1:
|
|
173
|
+
remaining_factors[m] = k
|
|
174
|
+
if verbose > 1:
|
|
175
|
+
print("Remaining: ", remaining_factors)
|
|
173
176
|
|
|
174
177
|
if len(remaining_factors) == 0:
|
|
175
178
|
return prime_factors
|
|
@@ -190,7 +193,7 @@ def divisors(n:int, proper:bool = False) -> int:
|
|
|
190
193
|
if n <= 1:
|
|
191
194
|
return divisor_list
|
|
192
195
|
facctordict= factorint(n)
|
|
193
|
-
primes =
|
|
196
|
+
primes = list(facctordict)
|
|
194
197
|
nprimes = len(primes)
|
|
195
198
|
multiplicites = [facctordict[p] for p in primes]
|
|
196
199
|
|
|
@@ -160,7 +160,7 @@ class SHA3():
|
|
|
160
160
|
|
|
161
161
|
def __init__(self, n: int = 256):
|
|
162
162
|
if n not in (224, 256, 384, 512):
|
|
163
|
-
raise ValueError(
|
|
163
|
+
raise ValueError("n must be one of: 224, 256, 384, 512")
|
|
164
164
|
self.keccak = Keccak(rate = 1600 - 2*n)
|
|
165
165
|
self.keccak.pad = [b'\x86', b'\x06', b'\x80']
|
|
166
166
|
self.digest_size = n // 8 # in bytes
|
|
@@ -175,7 +175,7 @@ class SHA3():
|
|
|
175
175
|
|
|
176
176
|
def __repr__(self):
|
|
177
177
|
return self.name
|
|
178
|
-
|
|
178
|
+
|
|
179
179
|
def update(self, msg: bytes | str) -> None:
|
|
180
180
|
"Absorb the given message into the sponge."
|
|
181
181
|
self.keccak.absorb(msg)
|
|
@@ -206,7 +206,7 @@ class SHAKE():
|
|
|
206
206
|
|
|
207
207
|
def __init__(self, msg: bytes | str, n: int = 128) -> None:
|
|
208
208
|
if n not in (128, 256):
|
|
209
|
-
raise ValueError(
|
|
209
|
+
raise ValueError("n must be one of: 128, 256")
|
|
210
210
|
self.keccak = Keccak(rate=1600-2*n)
|
|
211
211
|
self.keccak.pad = [b'\x9f', b'\x1f', b'\x80']
|
|
212
212
|
self.keccak.absorb(msg)
|
|
@@ -50,7 +50,7 @@ class Matrix:
|
|
|
50
50
|
out[i] += self.__class__.print_post
|
|
51
51
|
return '\n'.join(out)
|
|
52
52
|
|
|
53
|
-
def _repr_mimebundle_(self, **kwargs):
|
|
53
|
+
def _repr_mimebundle_(self, **kwargs): # pylint: disable=W0613
|
|
54
54
|
return {
|
|
55
55
|
"text/plain": repr(self),
|
|
56
56
|
"text/latex": "$\\displaystyle" + self.latex() + "$"
|
|
@@ -137,11 +137,11 @@ class Matrix:
|
|
|
137
137
|
if len(cols) == self.cols:
|
|
138
138
|
self.delete_rows(rows)
|
|
139
139
|
return
|
|
140
|
-
|
|
140
|
+
if len(rows) == self.rows:
|
|
141
141
|
self.delete_columns(cols)
|
|
142
142
|
return
|
|
143
143
|
raise ValueError("Can only delete entire rows or entire columns!")
|
|
144
|
-
|
|
144
|
+
|
|
145
145
|
def delete_rows(self, rows: int|list) -> None:
|
|
146
146
|
"Deletes a row or a list of rows."
|
|
147
147
|
if isinstance(rows, int):
|
|
@@ -153,7 +153,7 @@ class Matrix:
|
|
|
153
153
|
for i in reversed(sorted(rows)):
|
|
154
154
|
del self.matrix[i]
|
|
155
155
|
self.rows -= len(rows)
|
|
156
|
-
|
|
156
|
+
|
|
157
157
|
def delete_columns(self, cols: int|list) -> None:
|
|
158
158
|
"Deletes a column or a list of columns."
|
|
159
159
|
if isinstance(cols, int):
|
|
@@ -166,7 +166,7 @@ class Matrix:
|
|
|
166
166
|
for j in reversed(sorted(cols)):
|
|
167
167
|
del self.matrix[i][j]
|
|
168
168
|
self.cols -= len(cols)
|
|
169
|
-
|
|
169
|
+
|
|
170
170
|
def append_row(self, row: list|tuple, ring = None) -> None:
|
|
171
171
|
"Append a row."
|
|
172
172
|
if not isinstance(row, list|tuple) or len(row) != self.cols:
|
|
@@ -146,28 +146,26 @@ def sqrt_mod(a: int, p: int) -> int|None:
|
|
|
146
146
|
|
|
147
147
|
# Euler phi, Carmichael function, Moebius function
|
|
148
148
|
|
|
149
|
-
from .factor import factorint
|
|
149
|
+
from .factor import factorint # pylint: disable=C0413
|
|
150
150
|
|
|
151
151
|
|
|
152
152
|
def euler_phi(n: int) -> int:
|
|
153
153
|
"""Euler's phi function of `n`."""
|
|
154
154
|
if not isinstance(n, int) or n < 1:
|
|
155
|
-
raise ValueError(f"{n} is not a positive integer")
|
|
156
|
-
k
|
|
157
|
-
return prod([(p - 1) * p ** (k[p] - 1) for p in k])
|
|
155
|
+
raise ValueError(f"{n} is not a positive integer.")
|
|
156
|
+
return prod([(p - 1) * p ** (k - 1) for p, k in factorint(n).items()])
|
|
158
157
|
|
|
159
158
|
|
|
160
159
|
def carmichael_lambda(n: int) -> int:
|
|
161
160
|
"""Carmichael's lambda function of `n`."""
|
|
162
161
|
if not isinstance(n, int) or n < 1:
|
|
163
|
-
raise ValueError(f"{n} is not a positive integer")
|
|
162
|
+
raise ValueError(f"{n} is not a positive integer.")
|
|
164
163
|
if n == 1:
|
|
165
164
|
return 1
|
|
166
|
-
k = factorint(n)
|
|
167
165
|
lam_all = [] # values corresponding to the prime factors
|
|
168
|
-
for p in
|
|
169
|
-
lam = (p - 1) * p ** (k
|
|
170
|
-
if p == 2 and k
|
|
166
|
+
for p, k in factorint(n).items():
|
|
167
|
+
lam = (p - 1) * p ** (k - 1)
|
|
168
|
+
if p == 2 and k > 2:
|
|
171
169
|
lam = lam // 2
|
|
172
170
|
lam_all += [lam]
|
|
173
171
|
lam = lam_all[0] # now take the least common multiple of all values
|
|
@@ -179,7 +177,7 @@ def carmichael_lambda(n: int) -> int:
|
|
|
179
177
|
def moebius_mu(n: int) -> int:
|
|
180
178
|
"""Moebius' mu function of `n`."""
|
|
181
179
|
if not isinstance(n, int) or n < 0:
|
|
182
|
-
raise ValueError(f"{n} is not a nonegative integer")
|
|
180
|
+
raise ValueError(f"{n} is not a nonegative integer.")
|
|
183
181
|
if n == 0:
|
|
184
182
|
return 0
|
|
185
183
|
factors = factorint(n)
|
|
@@ -255,8 +253,8 @@ def crt(a: list[int], m: list[int], coprime=True) -> int:
|
|
|
255
253
|
if not all(isinstance(ai, int) for ai in a):
|
|
256
254
|
raise ValueError("Residues must be integers.")
|
|
257
255
|
# make a copy
|
|
258
|
-
m = [mi for mi in m]
|
|
259
|
-
a = [ai for ai in a]
|
|
256
|
+
m = [mi for mi in m] # pylint: disable=R1721
|
|
257
|
+
a = [ai for ai in a] # pylint: disable=R1721
|
|
260
258
|
for i in range(l):
|
|
261
259
|
for j in range(i + 1, l):
|
|
262
260
|
g = gcd(m[i], m[j])
|
|
@@ -281,4 +279,4 @@ def crt(a: list[int], m: list[int], coprime=True) -> int:
|
|
|
281
279
|
M = prod(m)
|
|
282
280
|
Mi = [M // m[i] for i in range(l)]
|
|
283
281
|
MNi = [Mi[i] * pow(Mi[i], -1, m[i]) % M for i in range(l)]
|
|
284
|
-
return sum(
|
|
282
|
+
return sum( a[i] * MNi[i] % M for i in range(l) ) % M
|