kryptools 1.8.2__tar.gz → 1.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.
- {kryptools-1.8.2 → kryptools-1.9}/PKG-INFO +3 -2
- {kryptools-1.8.2 → kryptools-1.9}/README.md +2 -1
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/Zmod.py +9 -2
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/__init__.py +3 -3
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/code.py +1 -1
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/la.py +56 -31
- kryptools-1.9/kryptools/lat.py +631 -0
- kryptools-1.8.2/kryptools/lat.py → kryptools-1.9/kryptools/lat2.py +20 -147
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/poly.py +201 -62
- {kryptools-1.8.2 → kryptools-1.9}/kryptools.egg-info/PKG-INFO +3 -2
- {kryptools-1.8.2 → kryptools-1.9}/kryptools.egg-info/SOURCES.txt +1 -0
- {kryptools-1.8.2 → kryptools-1.9}/pyproject.toml +1 -1
- kryptools-1.9/tests/test_lat.py +117 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_poly.py +4 -0
- kryptools-1.8.2/tests/test_lat.py +0 -49
- {kryptools-1.8.2 → kryptools-1.9}/LICENSE +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/GF2.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/aes.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/blockcipher.py +2 -2
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/conway_polynomials.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/des.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/dlp.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/dlp_bsgs.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/dlp_ic.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/dlp_qs.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/dlp_rho.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/ec.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/factor.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/factor_dix.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/factor_ecm.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/factor_fmt.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/factor_pm1.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/factor_qs.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/factor_rho.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/intfuncs.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/keccak.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/nt.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/primes.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools/sha1.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools.egg-info/dependency_links.txt +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/kryptools.egg-info/top_level.txt +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/setup.cfg +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_GF2.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_Zmod.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_aes.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_code.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_des.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_dlog.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_ec.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_factor.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_factor_fmt.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_factor_pm1.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_factor_qs.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_intfuncs.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_keccak.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_la.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_nt.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_primes.py +0 -0
- {kryptools-1.8.2 → kryptools-1.9}/tests/test_sha1.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kryptools
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.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
|
License: MIT
|
|
@@ -44,11 +44,12 @@ The tools contained are:
|
|
|
44
44
|
* integer factorization (Fermat, Pollard p-1, Pollard rho, Lenstra's ECM, Dixon, basic quadratic sieve)
|
|
45
45
|
* elliptic curves (Weierstrass form), group operations, order, discrete logarithms
|
|
46
46
|
* linear algebra: Hermite normal form, Smith normal form, Gram-Schmidt
|
|
47
|
-
* lattices: Hadamard ratio, Babai rounding/nearest plane algorithm, lattice reduction (Lenstra-Lenstra-Lovaz), SIS, ISIS, LWE
|
|
47
|
+
* lattices: Hadamard ratio, Babai rounding/nearest plane algorithm, lattice reduction (Hermite, Lenstra-Lenstra-Lovaz, BKZ), SIS, ISIS, LWE
|
|
48
48
|
* linear codes: Hamming distance, left standard form, parity check matrix
|
|
49
49
|
|
|
50
50
|
* Matrix: a class for Matrices (inverse, det, reduced echelon form, kernel, solving linear systems, etc.)
|
|
51
51
|
* BinaryMatrix: a class for Matrices with binary entries (for much faster row operations)
|
|
52
|
+
* Lattice: a class for lattices (SVP, CPV, LLL, BKZ, HKZ)
|
|
52
53
|
* Poly: a class for polynomials (division, modulo, factoring and irreducibility test over finite fields, Lagrange interpolation)
|
|
53
54
|
* Zmod: a class for the ring of integers modulo an integer
|
|
54
55
|
* GF2: a class for Galois fields GF(2^n)
|
|
@@ -26,11 +26,12 @@ The tools contained are:
|
|
|
26
26
|
* integer factorization (Fermat, Pollard p-1, Pollard rho, Lenstra's ECM, Dixon, basic quadratic sieve)
|
|
27
27
|
* elliptic curves (Weierstrass form), group operations, order, discrete logarithms
|
|
28
28
|
* linear algebra: Hermite normal form, Smith normal form, Gram-Schmidt
|
|
29
|
-
* lattices: Hadamard ratio, Babai rounding/nearest plane algorithm, lattice reduction (Lenstra-Lenstra-Lovaz), SIS, ISIS, LWE
|
|
29
|
+
* lattices: Hadamard ratio, Babai rounding/nearest plane algorithm, lattice reduction (Hermite, Lenstra-Lenstra-Lovaz, BKZ), SIS, ISIS, LWE
|
|
30
30
|
* linear codes: Hamming distance, left standard form, parity check matrix
|
|
31
31
|
|
|
32
32
|
* Matrix: a class for Matrices (inverse, det, reduced echelon form, kernel, solving linear systems, etc.)
|
|
33
33
|
* BinaryMatrix: a class for Matrices with binary entries (for much faster row operations)
|
|
34
|
+
* Lattice: a class for lattices (SVP, CPV, LLL, BKZ, HKZ)
|
|
34
35
|
* Poly: a class for polynomials (division, modulo, factoring and irreducibility test over finite fields, Lagrange interpolation)
|
|
35
36
|
* Zmod: a class for the ring of integers modulo an integer
|
|
36
37
|
* GF2: a class for Galois fields GF(2^n)
|
|
@@ -63,8 +63,8 @@ class Zmod:
|
|
|
63
63
|
def random(self, num: int = 0) -> "ZmodPoint":
|
|
64
64
|
"Return a single random point or a list of random points."
|
|
65
65
|
if num:
|
|
66
|
-
return([self(randint(0,self.n-1)) for _ in range(num)])
|
|
67
|
-
return self(randint(0,self.n-1))
|
|
66
|
+
return([self(randint(0, self.n-1)) for _ in range(num)])
|
|
67
|
+
return self(randint(0, self.n-1))
|
|
68
68
|
|
|
69
69
|
def order(self) -> int:
|
|
70
70
|
"Compute the order of the group Z_n^*."
|
|
@@ -91,6 +91,12 @@ class Zmod:
|
|
|
91
91
|
self.group_order *= p**k
|
|
92
92
|
return self.group_order
|
|
93
93
|
|
|
94
|
+
def factor_n(self) -> bool:
|
|
95
|
+
"Returns the factorization of n and stores it."
|
|
96
|
+
if not self.n_factors:
|
|
97
|
+
self.n_factors = factorint(self.n)
|
|
98
|
+
return self.n_factors
|
|
99
|
+
|
|
94
100
|
def is_cyclic(self) -> bool:
|
|
95
101
|
"Test if the group Z_n^* is cyclic."
|
|
96
102
|
n = self.n
|
|
@@ -260,6 +266,7 @@ class ZmodPoint:
|
|
|
260
266
|
return self.x - self.ring.n
|
|
261
267
|
|
|
262
268
|
mods = sharp
|
|
269
|
+
lift_centered = sharp
|
|
263
270
|
|
|
264
271
|
def order(self) -> int:
|
|
265
272
|
"Compute the order of the point in the group Z_n^*."
|
|
@@ -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.
|
|
8
|
+
__version__ = "1.9"
|
|
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
|
|
@@ -15,8 +15,8 @@ from .factor import factorint, divisors
|
|
|
15
15
|
from .dlp import dlog
|
|
16
16
|
from .ec import EC_Weierstrass
|
|
17
17
|
from .la import Matrix, zeros, eye, circulant, BinaryMatrix
|
|
18
|
-
from .lat import
|
|
19
|
-
from .
|
|
18
|
+
from .lat import Lattice, random_unimodular_matrix
|
|
19
|
+
from .lat2 import q_ary_lattice, gram_det, hadamard_ratio, hermite_nf, gram_schmidt, babai_round_cvp, babai_round_bnd, babai_plane_cvp, babai_plane_bnd, lll, svp, cvp, sis, isis, sis_search, isis_search
|
|
20
20
|
from .poly import Poly, PolyBinMult, lagrange_interpolation
|
|
21
21
|
from .Zmod import Zmod
|
|
22
22
|
from .GF2 import GF2, GF2_aes, GF2_miniaes, GF2_ghash
|
|
@@ -414,7 +414,7 @@ class CyclicCode():
|
|
|
414
414
|
>>> cc = CyclicCode(n, g)
|
|
415
415
|
|
|
416
416
|
To encode a list of letters (the length must be equal to the dimension k of the code):
|
|
417
|
-
>>> cc.encode([0,1,0])
|
|
417
|
+
>>> cc.encode([0, 1, 0])
|
|
418
418
|
[0, 1, 1, 0]
|
|
419
419
|
|
|
420
420
|
Decoding is only implemented for code words:
|
|
@@ -25,22 +25,26 @@ class Matrix:
|
|
|
25
25
|
print_post = " ]"
|
|
26
26
|
print_sep = ", "
|
|
27
27
|
|
|
28
|
-
def __init__(self, matrix: list
|
|
28
|
+
def __init__(self, matrix: list, ring = None):
|
|
29
29
|
if isinstance(matrix, BinaryMatrix):
|
|
30
30
|
matrix = matrix.bitmatrix()
|
|
31
31
|
ring = Zmod(2)
|
|
32
|
-
elif not
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
elif not isinstance(matrix, list):
|
|
33
|
+
try:
|
|
34
|
+
matrix = list(matrix)
|
|
35
|
+
except Exception as exc:
|
|
36
|
+
raise ValueError("The given `matrix` cannot be converted to a list.") from exc
|
|
37
|
+
if not isinstance(matrix[0], list):
|
|
35
38
|
matrix = [[x] for x in matrix]
|
|
36
39
|
self.matrix = matrix # the matrix as a list (rows) of lists (column entries)
|
|
37
40
|
self.cols = len(matrix[0]) # number of columns
|
|
38
41
|
self.rows = len(matrix) # number of rows
|
|
42
|
+
if not self.cols or not self.cols:
|
|
43
|
+
raise ValueError("Both the number of rows and the number of columns must be nonzero.")
|
|
44
|
+
if any( len(row) != self.cols for row in self.matrix ):
|
|
45
|
+
raise ValueError("All matrix rows must have equal length!")
|
|
39
46
|
self.nonpivotcols = None # set during rref
|
|
40
47
|
self.pivotcols = None # set during rref
|
|
41
|
-
for i in range(1, self.rows):
|
|
42
|
-
if len(matrix[i]) != self.cols:
|
|
43
|
-
raise ValueError("All matrix rows must have equal length!")
|
|
44
48
|
if ring:
|
|
45
49
|
self.map(ring)
|
|
46
50
|
|
|
@@ -281,10 +285,10 @@ class Matrix:
|
|
|
281
285
|
return False
|
|
282
286
|
if self.rows != other.rows or self.cols != other.cols:
|
|
283
287
|
return False
|
|
284
|
-
return all(self[i] == other[i] for i in range(self.rows
|
|
288
|
+
return all(self.matrix[i][j] == other.matrix[i][j] for i in range(self.rows) for j in range(self.cols))
|
|
285
289
|
|
|
286
290
|
def __bool__(self):
|
|
287
|
-
return any(bool(
|
|
291
|
+
return any( bool(x) for row in self.matrix for x in row)
|
|
288
292
|
|
|
289
293
|
def map(self, func) -> None:
|
|
290
294
|
"Apply a function to all elements in place."
|
|
@@ -293,9 +297,7 @@ class Matrix:
|
|
|
293
297
|
|
|
294
298
|
def applyfunc(self, func) -> "Matrix":
|
|
295
299
|
"Apply a function to all elements."
|
|
296
|
-
|
|
297
|
-
tmp.map(func)
|
|
298
|
-
return tmp
|
|
300
|
+
return self.__class__([ list(map(func, row)) for row in self.matrix ])
|
|
299
301
|
|
|
300
302
|
def _guess_zero(self):
|
|
301
303
|
"Guess zero and one in the ring of the coefficients."
|
|
@@ -303,6 +305,22 @@ class Matrix:
|
|
|
303
305
|
one = zero**0
|
|
304
306
|
return zero, one
|
|
305
307
|
|
|
308
|
+
def is_integer(self, convert: bool = False):
|
|
309
|
+
"Test if all coefficients are integers and convert integer valued fractions if requested."
|
|
310
|
+
if all( isinstance(x, int) or (isinstance(x, Fraction) and x.denominator == 1) for row in self.matrix for x in row):
|
|
311
|
+
if convert:
|
|
312
|
+
self.map(int)
|
|
313
|
+
return True
|
|
314
|
+
return False
|
|
315
|
+
|
|
316
|
+
def is_rational(self, convert: bool = False):
|
|
317
|
+
"Test if all coefficients are rational and convert to fractions if requested."
|
|
318
|
+
if all( isinstance(x, (Fraction, int)) for row in self.matrix for x in row):
|
|
319
|
+
if convert:
|
|
320
|
+
self.map(Fraction)
|
|
321
|
+
return True
|
|
322
|
+
return False
|
|
323
|
+
|
|
306
324
|
def norm2(self) -> float:
|
|
307
325
|
"Squared Frobenius/Euclidean norm."
|
|
308
326
|
return sum(sum(abs(x)**2 for x in row) for row in self.matrix)
|
|
@@ -318,7 +336,7 @@ class Matrix:
|
|
|
318
336
|
tmp = sum(sum(abs(x)**p for x in row) for row in self.matrix)
|
|
319
337
|
return tmp**(1/p)
|
|
320
338
|
|
|
321
|
-
def dot(self, other) ->
|
|
339
|
+
def dot(self, other) -> Number:
|
|
322
340
|
"Dot product of two vectors."
|
|
323
341
|
if self.rows == 1 and other.rows == 1 and self.cols == other.cols:
|
|
324
342
|
return sum(x * y for x, y in zip(self.matrix[0], other.matrix[0]))
|
|
@@ -382,9 +400,12 @@ class Matrix:
|
|
|
382
400
|
if hasattr(self.matrix[0][0], "ring") and not self.matrix[0][0].ring.is_field():
|
|
383
401
|
# the matrix is over a ring (not a field)
|
|
384
402
|
return self._rref_ring(start = start, drop_zero_rows = drop_zero_rows)
|
|
385
|
-
one = self._guess_zero()[1]
|
|
386
403
|
n, m = self.cols, self.rows
|
|
387
|
-
|
|
404
|
+
if self.is_rational():
|
|
405
|
+
R = [ list(map(Fraction, row)) for row in self.matrix ]
|
|
406
|
+
else:
|
|
407
|
+
R = [ row[:] for row in self.matrix ]
|
|
408
|
+
one = self._guess_zero()[1]
|
|
388
409
|
pivotcols = []
|
|
389
410
|
nonpivotcols = []
|
|
390
411
|
i = 0
|
|
@@ -428,15 +449,15 @@ class Matrix:
|
|
|
428
449
|
def _rref_ring(self, start: int = 0, drop_zero_rows: bool = False) -> "Matrix":
|
|
429
450
|
"Compute the reduced echelon form if the base ring is Z_n and no field."
|
|
430
451
|
ring = self.matrix[0][0].ring
|
|
431
|
-
|
|
452
|
+
R = self.applyfunc(int)
|
|
432
453
|
done = start
|
|
433
|
-
while done <
|
|
434
|
-
|
|
435
|
-
done =
|
|
436
|
-
for i, j in enumerate(
|
|
454
|
+
while done < R.cols:
|
|
455
|
+
R = R.hrnf(start = start, drop_zero_rows = drop_zero_rows)
|
|
456
|
+
done = R.cols
|
|
457
|
+
for i, j in enumerate(R.pivotcols):
|
|
437
458
|
if j < start:
|
|
438
459
|
continue
|
|
439
|
-
pivot =
|
|
460
|
+
pivot = R.matrix[i][j]
|
|
440
461
|
if pivot >= ring.n:
|
|
441
462
|
done = min(j, done)
|
|
442
463
|
pivot %= ring.n
|
|
@@ -448,17 +469,17 @@ class Matrix:
|
|
|
448
469
|
if pivot > 1: # we can make the pivot smaller
|
|
449
470
|
done = min(j, done)
|
|
450
471
|
tmp = pow(pivot, -1, ring.n)
|
|
451
|
-
for k in range(j,
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
return
|
|
472
|
+
for k in range(j, R.cols):
|
|
473
|
+
R.matrix[i][k] *= tmp
|
|
474
|
+
R.map(lambda x: x % ring.n)
|
|
475
|
+
R.map(ring)
|
|
476
|
+
return R
|
|
456
477
|
|
|
457
478
|
|
|
458
479
|
def hrnf(self, start = 0, drop_zero_rows: bool = True) -> "Matrix":
|
|
459
480
|
"Compute the Hermite row normal form."
|
|
460
481
|
n, m = self.cols, self.rows
|
|
461
|
-
if not
|
|
482
|
+
if not self.is_integer(convert = True):
|
|
462
483
|
raise ValueError("Hermite normal form requires integer entries!")
|
|
463
484
|
H = self[:,:]
|
|
464
485
|
H.pivotcols = []
|
|
@@ -506,7 +527,7 @@ class Matrix:
|
|
|
506
527
|
def hnf(self, drop_zero_columns: bool = True) -> "Matrix":
|
|
507
528
|
"Compute the Hermite normal form."
|
|
508
529
|
n, m = self.cols, self.rows
|
|
509
|
-
if not
|
|
530
|
+
if not self.is_integer(convert = True):
|
|
510
531
|
raise ValueError("Hermite normal form requires integer entries!")
|
|
511
532
|
H = self[:,:]
|
|
512
533
|
j = n - 1
|
|
@@ -542,7 +563,7 @@ class Matrix:
|
|
|
542
563
|
|
|
543
564
|
def snf(self, drop_zero_rows: bool = False, drop_zero_columns: bool = False, include_S: bool = True, include_T: bool = True) -> "Matrix":
|
|
544
565
|
"Computes the Smith normal form D of a matrix A with integer coefficients together with invertible matrices S and T such that D = S * A * T."
|
|
545
|
-
if not
|
|
566
|
+
if not self.is_integer(convert = True):
|
|
546
567
|
raise ValueError("Smith normal form requires integer entries!")
|
|
547
568
|
m, n = self.rows, self.cols
|
|
548
569
|
A = self[:,:]
|
|
@@ -685,11 +706,15 @@ class Matrix:
|
|
|
685
706
|
if hasattr(self.matrix[0][0], "ring") and not self.matrix[0][0].ring.is_field():
|
|
686
707
|
# the matrix is over a ring (not a field)
|
|
687
708
|
ring = self.matrix[0][0].ring
|
|
688
|
-
R = [ list(map(lambda x: Fraction(int(x)),
|
|
709
|
+
R = [ list(map(lambda x: Fraction(int(x)), row)) for row in self.matrix ]
|
|
689
710
|
zero, one = ring(0), 1
|
|
711
|
+
elif self.is_integer():
|
|
712
|
+
ring = None
|
|
713
|
+
R = [ list(map(Fraction, row)) for row in self.matrix ]
|
|
714
|
+
zero, one = 0, 1
|
|
690
715
|
else:
|
|
691
716
|
ring = None
|
|
692
|
-
R = [
|
|
717
|
+
R = [ row[:] for row in self.matrix ]
|
|
693
718
|
zero, one = self._guess_zero()
|
|
694
719
|
D = one
|
|
695
720
|
i = 0
|