kryptools 1.5__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 → kryptools-1.5.2}/PKG-INFO +7 -1
- {kryptools-1.5 → kryptools-1.5.2}/README.md +7 -1
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/GF2.py +14 -10
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/Zmod.py +2 -1
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/__init__.py +1 -1
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/aes.py +4 -4
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/blockcipher.py +5 -5
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/code.py +25 -26
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/des.py +1 -1
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/dlp_ic.py +4 -4
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/dlp_qs.py +4 -4
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/dlp_rho.py +1 -1
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/factor.py +27 -24
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/factor_qs.py +1 -1
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/keccak.py +27 -6
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/la.py +5 -5
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/nt.py +11 -13
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/poly.py +89 -73
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/sha1.py +1 -2
- {kryptools-1.5 → kryptools-1.5.2}/kryptools.egg-info/PKG-INFO +7 -1
- {kryptools-1.5 → kryptools-1.5.2}/pyproject.toml +1 -1
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_GF2.py +18 -18
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_Zmod.py +7 -8
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_aes.py +2 -1
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_code.py +3 -2
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_des.py +2 -1
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_dlog.py +3 -2
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_ec.py +4 -3
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_factor.py +3 -2
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_factor_fmt.py +3 -2
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_factor_pm1.py +2 -1
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_factor_qs.py +2 -1
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_intfuncs.py +7 -6
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_keccak.py +19 -18
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_la.py +4 -3
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_lat.py +3 -2
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_nt.py +8 -7
- kryptools-1.5.2/tests/test_poly.py +88 -0
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_primes.py +5 -4
- {kryptools-1.5 → kryptools-1.5.2}/tests/test_sha1.py +2 -1
- kryptools-1.5/tests/test_poly.py +0 -63
- {kryptools-1.5 → kryptools-1.5.2}/LICENSE +0 -0
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/conway_polynomials.py +0 -0
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/dlp.py +0 -0
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/dlp_bsgs.py +0 -0
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/ec.py +0 -0
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/factor_dix.py +0 -0
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/factor_ecm.py +0 -0
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/factor_fmt.py +0 -0
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/factor_pm1.py +0 -0
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/factor_rho.py +0 -0
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/intfuncs.py +0 -0
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/lat.py +0 -0
- {kryptools-1.5 → kryptools-1.5.2}/kryptools/primes.py +0 -0
- {kryptools-1.5 → kryptools-1.5.2}/kryptools.egg-info/SOURCES.txt +0 -0
- {kryptools-1.5 → kryptools-1.5.2}/kryptools.egg-info/dependency_links.txt +0 -0
- {kryptools-1.5 → kryptools-1.5.2}/kryptools.egg-info/top_level.txt +0 -0
- {kryptools-1.5 → 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
|
|
@@ -261,6 +261,8 @@ class GF2nPoint:
|
|
|
261
261
|
return NotImplemented
|
|
262
262
|
if not (self.x) and j < 0:
|
|
263
263
|
raise ValueError("Division by zero.")
|
|
264
|
+
if self.field.order == 2:
|
|
265
|
+
return self
|
|
264
266
|
if self.field.bitreversed:
|
|
265
267
|
res = self.field(self.field.order >> 1)
|
|
266
268
|
else:
|
|
@@ -276,25 +278,27 @@ class GF2nPoint:
|
|
|
276
278
|
x *= x
|
|
277
279
|
return res
|
|
278
280
|
|
|
279
|
-
def __lshift__(self,
|
|
281
|
+
def __lshift__(self, j: int) -> "GF2nPoint":
|
|
280
282
|
"Cyclic rotation to the left."
|
|
281
|
-
x = self.x <<
|
|
283
|
+
x = self.x << j
|
|
282
284
|
x = (x % self.field.order) + (x // self.field.order)
|
|
283
285
|
return self.field(x)
|
|
284
286
|
|
|
285
|
-
def __rshift__(self,
|
|
287
|
+
def __rshift__(self, j: int) -> "GF2nPoint":
|
|
286
288
|
"Cyclic rotation to the right."
|
|
287
|
-
x = self.x >>
|
|
288
|
-
x += (self.field.order >>
|
|
289
|
+
x = self.x >> j
|
|
290
|
+
x += (self.field.order >> j) * (self.x % 2**j)
|
|
289
291
|
return self.field(x)
|
|
290
292
|
|
|
291
293
|
def sqrt(self) -> "GF2nPoint":
|
|
292
294
|
"Compute the square root."
|
|
295
|
+
if self.field.order == 2:
|
|
296
|
+
return self
|
|
293
297
|
return self**(self.field.order//2)
|
|
294
298
|
|
|
295
299
|
def order(self) -> int:
|
|
296
300
|
"Compute the order of the point in the group GF(2^n)^*."
|
|
297
|
-
self.field._factors()
|
|
301
|
+
self.field._factors() # pylint: disable=W0212
|
|
298
302
|
order = self.field.mult_order # our current guess
|
|
299
303
|
one = self.field.one()
|
|
300
304
|
for p, k in self.field.factors.items():
|
|
@@ -316,7 +320,7 @@ class GF2nPoint:
|
|
|
316
320
|
if inv:
|
|
317
321
|
return aes_sbox_inv[self.x]
|
|
318
322
|
return aes_sbox[self.x]
|
|
319
|
-
|
|
323
|
+
if self.field.degree == 4 and self.field.modulus == 0b10011: # MiniAES
|
|
320
324
|
if inv:
|
|
321
325
|
return miniaes_sbox_inv[self.x]
|
|
322
326
|
return miniaes_sbox[self.x]
|
|
@@ -349,7 +353,7 @@ for i in range(256):
|
|
|
349
353
|
aes_sbox = list(map(GF2_aes, aes_sbox))
|
|
350
354
|
aes_sbox_inv = list(map(GF2_aes, aes_sbox_inv))
|
|
351
355
|
|
|
352
|
-
|
|
356
|
+
|
|
353
357
|
# sbox for Mini-AES
|
|
354
358
|
GF2_miniaes = GF2(4, 0b10011) # x^4 + x + 1 = Mini-AES
|
|
355
359
|
|
|
@@ -365,4 +369,4 @@ miniaes_sbox_inv = list(map(GF2_miniaes, miniaes_sbox_inv))
|
|
|
365
369
|
|
|
366
370
|
#Ghash
|
|
367
371
|
|
|
368
|
-
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
|
|
@@ -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.5"
|
|
8
|
+
__version__ = "1.5.1"
|
|
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
|
|
@@ -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]
|
|
@@ -307,11 +305,12 @@ class ReedSolomonCode(CyclicCode):
|
|
|
307
305
|
y = Poly(y, ring = self.gf)
|
|
308
306
|
if y.degree() >= self.n:
|
|
309
307
|
raise ValueError(f"Degree can be at most {self.n-1}.")
|
|
310
|
-
|
|
308
|
+
xx = [ -y(self.alpha**(-j)) for j in range(self.n) ]
|
|
309
|
+
x = Poly(xx)
|
|
311
310
|
if x.degree() >= self.k: # No codewort
|
|
312
311
|
t = (self.n - self.k) // 2
|
|
313
|
-
A = Matrix([[
|
|
314
|
-
b = [ -
|
|
312
|
+
A = Matrix([[ xx[j - l % self.n] for l in range(1, t+1) ] for j in range(self.k+t, self.k+2*t) ])
|
|
313
|
+
b = [ -xx[self.k + t + l ] for l in range(t) ]
|
|
315
314
|
lam = Poly([one] + list(A.solve(b)))
|
|
316
315
|
x_coordinates = []
|
|
317
316
|
y_coordinates = []
|
|
@@ -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,16 +160,21 @@ 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(
|
|
164
|
-
self.keccak = Keccak(rate=1600-2*n)
|
|
163
|
+
raise ValueError("n must be one of: 224, 256, 384, 512")
|
|
164
|
+
self.keccak = Keccak(rate = 1600 - 2*n)
|
|
165
165
|
self.keccak.pad = [b'\x86', b'\x06', b'\x80']
|
|
166
|
-
self.
|
|
166
|
+
self.digest_size = n // 8 # in bytes
|
|
167
|
+
self.block_size = (1600 - 2*n) // 8 # in bytes
|
|
168
|
+
self.name = f"SHA3-{n}"
|
|
167
169
|
|
|
168
170
|
def __call__(self, msg: bytes | str) -> bytes:
|
|
169
171
|
"Compute the hash of the message given or absorbed."
|
|
170
172
|
self.keccak.reset()
|
|
171
173
|
self.keccak.absorb(msg)
|
|
172
|
-
return self.keccak.squeeze(self.
|
|
174
|
+
return self.keccak.squeeze(self.digest_size)
|
|
175
|
+
|
|
176
|
+
def __repr__(self):
|
|
177
|
+
return self.name
|
|
173
178
|
|
|
174
179
|
def update(self, msg: bytes | str) -> None:
|
|
175
180
|
"Absorb the given message into the sponge."
|
|
@@ -179,10 +184,14 @@ class SHA3():
|
|
|
179
184
|
"Compute the hash of the message given or absorbed."
|
|
180
185
|
if msg is not None:
|
|
181
186
|
self.keccak.absorb(msg)
|
|
182
|
-
digest = self.keccak.squeeze(self.
|
|
187
|
+
digest = self.keccak.squeeze(self.digest_size)
|
|
183
188
|
self.keccak.reset()
|
|
184
189
|
return digest
|
|
185
190
|
|
|
191
|
+
def hexdigest(self, msg: bytes | str | None = None) -> bytes:
|
|
192
|
+
"Compute the hash of the message given or absorbed. Return as hex value."
|
|
193
|
+
return self.digest(msg).hex()
|
|
194
|
+
|
|
186
195
|
|
|
187
196
|
class SHAKE():
|
|
188
197
|
"""
|
|
@@ -197,11 +206,23 @@ class SHAKE():
|
|
|
197
206
|
|
|
198
207
|
def __init__(self, msg: bytes | str, n: int = 128) -> None:
|
|
199
208
|
if n not in (128, 256):
|
|
200
|
-
raise ValueError(
|
|
209
|
+
raise ValueError("n must be one of: 128, 256")
|
|
201
210
|
self.keccak = Keccak(rate=1600-2*n)
|
|
202
211
|
self.keccak.pad = [b'\x9f', b'\x1f', b'\x80']
|
|
203
212
|
self.keccak.absorb(msg)
|
|
213
|
+
self.name = f"SHAKE-{n}"
|
|
214
|
+
|
|
215
|
+
def __repr__(self):
|
|
216
|
+
return self.name
|
|
204
217
|
|
|
205
218
|
def __call__(self, r: int) -> bytes:
|
|
206
219
|
"Extract `r` bytes."
|
|
207
220
|
return self.keccak.squeeze(r)
|
|
221
|
+
|
|
222
|
+
def digest(self, r: int) -> bytes:
|
|
223
|
+
"Extract `r` bytes."
|
|
224
|
+
return self(r)
|
|
225
|
+
|
|
226
|
+
def hexdigest(self, r: int) -> bytes:
|
|
227
|
+
"Extract `r` bytes as hex values."
|
|
228
|
+
return self(r).hex()
|
|
@@ -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:
|