kryptools 1.5.3__tar.gz → 1.7__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 (60) hide show
  1. {kryptools-1.5.3 → kryptools-1.7}/PKG-INFO +6 -3
  2. {kryptools-1.5.3 → kryptools-1.7}/README.md +5 -2
  3. {kryptools-1.5.3 → kryptools-1.7}/kryptools/GF2.py +84 -35
  4. {kryptools-1.5.3 → kryptools-1.7}/kryptools/Zmod.py +8 -5
  5. {kryptools-1.5.3 → kryptools-1.7}/kryptools/__init__.py +4 -4
  6. kryptools-1.7/kryptools/code.py +664 -0
  7. {kryptools-1.5.3 → kryptools-1.7}/kryptools/factor_qs.py +2 -2
  8. kryptools-1.7/kryptools/la.py +952 -0
  9. {kryptools-1.5.3 → kryptools-1.7}/kryptools/poly.py +219 -6
  10. {kryptools-1.5.3 → kryptools-1.7}/kryptools/primes.py +1 -1
  11. {kryptools-1.5.3 → kryptools-1.7}/kryptools.egg-info/PKG-INFO +6 -3
  12. {kryptools-1.5.3 → kryptools-1.7}/pyproject.toml +1 -1
  13. {kryptools-1.5.3 → kryptools-1.7}/tests/test_GF2.py +26 -1
  14. {kryptools-1.5.3 → kryptools-1.7}/tests/test_Zmod.py +5 -2
  15. {kryptools-1.5.3 → kryptools-1.7}/tests/test_code.py +34 -2
  16. kryptools-1.7/tests/test_la.py +92 -0
  17. {kryptools-1.5.3 → kryptools-1.7}/tests/test_poly.py +25 -3
  18. kryptools-1.5.3/kryptools/code.py +0 -327
  19. kryptools-1.5.3/kryptools/la.py +0 -446
  20. kryptools-1.5.3/tests/test_la.py +0 -28
  21. {kryptools-1.5.3 → kryptools-1.7}/LICENSE +0 -0
  22. {kryptools-1.5.3 → kryptools-1.7}/kryptools/aes.py +0 -0
  23. {kryptools-1.5.3 → kryptools-1.7}/kryptools/blockcipher.py +0 -0
  24. {kryptools-1.5.3 → kryptools-1.7}/kryptools/conway_polynomials.py +0 -0
  25. {kryptools-1.5.3 → kryptools-1.7}/kryptools/des.py +0 -0
  26. {kryptools-1.5.3 → kryptools-1.7}/kryptools/dlp.py +0 -0
  27. {kryptools-1.5.3 → kryptools-1.7}/kryptools/dlp_bsgs.py +0 -0
  28. {kryptools-1.5.3 → kryptools-1.7}/kryptools/dlp_ic.py +0 -0
  29. {kryptools-1.5.3 → kryptools-1.7}/kryptools/dlp_qs.py +0 -0
  30. {kryptools-1.5.3 → kryptools-1.7}/kryptools/dlp_rho.py +0 -0
  31. {kryptools-1.5.3 → kryptools-1.7}/kryptools/ec.py +0 -0
  32. {kryptools-1.5.3 → kryptools-1.7}/kryptools/factor.py +0 -0
  33. {kryptools-1.5.3 → kryptools-1.7}/kryptools/factor_dix.py +0 -0
  34. {kryptools-1.5.3 → kryptools-1.7}/kryptools/factor_ecm.py +0 -0
  35. {kryptools-1.5.3 → kryptools-1.7}/kryptools/factor_fmt.py +0 -0
  36. {kryptools-1.5.3 → kryptools-1.7}/kryptools/factor_pm1.py +0 -0
  37. {kryptools-1.5.3 → kryptools-1.7}/kryptools/factor_rho.py +0 -0
  38. {kryptools-1.5.3 → kryptools-1.7}/kryptools/intfuncs.py +0 -0
  39. {kryptools-1.5.3 → kryptools-1.7}/kryptools/keccak.py +0 -0
  40. {kryptools-1.5.3 → kryptools-1.7}/kryptools/lat.py +0 -0
  41. {kryptools-1.5.3 → kryptools-1.7}/kryptools/nt.py +0 -0
  42. {kryptools-1.5.3 → kryptools-1.7}/kryptools/sha1.py +0 -0
  43. {kryptools-1.5.3 → kryptools-1.7}/kryptools.egg-info/SOURCES.txt +0 -0
  44. {kryptools-1.5.3 → kryptools-1.7}/kryptools.egg-info/dependency_links.txt +0 -0
  45. {kryptools-1.5.3 → kryptools-1.7}/kryptools.egg-info/top_level.txt +0 -0
  46. {kryptools-1.5.3 → kryptools-1.7}/setup.cfg +0 -0
  47. {kryptools-1.5.3 → kryptools-1.7}/tests/test_aes.py +0 -0
  48. {kryptools-1.5.3 → kryptools-1.7}/tests/test_des.py +0 -0
  49. {kryptools-1.5.3 → kryptools-1.7}/tests/test_dlog.py +0 -0
  50. {kryptools-1.5.3 → kryptools-1.7}/tests/test_ec.py +0 -0
  51. {kryptools-1.5.3 → kryptools-1.7}/tests/test_factor.py +0 -0
  52. {kryptools-1.5.3 → kryptools-1.7}/tests/test_factor_fmt.py +0 -0
  53. {kryptools-1.5.3 → kryptools-1.7}/tests/test_factor_pm1.py +0 -0
  54. {kryptools-1.5.3 → kryptools-1.7}/tests/test_factor_qs.py +0 -0
  55. {kryptools-1.5.3 → kryptools-1.7}/tests/test_intfuncs.py +0 -0
  56. {kryptools-1.5.3 → kryptools-1.7}/tests/test_keccak.py +0 -0
  57. {kryptools-1.5.3 → kryptools-1.7}/tests/test_lat.py +0 -0
  58. {kryptools-1.5.3 → kryptools-1.7}/tests/test_nt.py +0 -0
  59. {kryptools-1.5.3 → kryptools-1.7}/tests/test_primes.py +0 -0
  60. {kryptools-1.5.3 → kryptools-1.7}/tests/test_sha1.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kryptools
3
- Version: 1.5.3
3
+ Version: 1.7
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
@@ -47,13 +47,16 @@ The tools contained are:
47
47
  * lattices: Hadamard ratio, Babai rounding/nearest plane algorithm, lattice reduction (Lenstra-Lenstra-Lovaz)
48
48
  * linear codes: Hamming distance, left standard form, parity check matrix
49
49
 
50
- * Matrix: a class for Matrices (inverse, det, reduced echelon form, etc.)
50
+ * Matrix: a class for Matrices (inverse, det, reduced echelon form, kernel, etc.)
51
+ * BinaryMatrix: a class for Matrices with binary entries (for much faster row operations)
51
52
  * Poly: a class for polynomials (division, modulo, factoring and irreducibility test over finite fields, Lagrange interpolation)
52
53
  * Zmod: a class for the ring of integers modulo an integer
53
54
  * GF2: a class for Galois fields GF(2^n)
54
- * Goppa: a class for encoding and decoding Goppa codes
55
+ * BinaryCode: a class for encoding and decoding binary linear codes
56
+ * GoppaCode: a class for encoding and decoding binary Goppa codes
55
57
  * CyclicCode: a class for encoding and decoding cyclic codes
56
58
  * ReedSolomonCode: a class for encoding and decoding Reed-Solomon codes
59
+ * BCHCode: a class for encoding and decoding primitive narrow sense BCH codes
57
60
 
58
61
  * BlockCipher: a class implementing the usual modes of operation (ECB, CBC, GCM, etc.)
59
62
  * AESCipher: individual AES operations
@@ -29,13 +29,16 @@ The tools contained are:
29
29
  * lattices: Hadamard ratio, Babai rounding/nearest plane algorithm, lattice reduction (Lenstra-Lenstra-Lovaz)
30
30
  * linear codes: Hamming distance, left standard form, parity check matrix
31
31
 
32
- * Matrix: a class for Matrices (inverse, det, reduced echelon form, etc.)
32
+ * Matrix: a class for Matrices (inverse, det, reduced echelon form, kernel, etc.)
33
+ * BinaryMatrix: a class for Matrices with binary entries (for much faster row operations)
33
34
  * Poly: a class for polynomials (division, modulo, factoring and irreducibility test over finite fields, Lagrange interpolation)
34
35
  * Zmod: a class for the ring of integers modulo an integer
35
36
  * GF2: a class for Galois fields GF(2^n)
36
- * Goppa: a class for encoding and decoding Goppa codes
37
+ * BinaryCode: a class for encoding and decoding binary linear codes
38
+ * GoppaCode: a class for encoding and decoding binary Goppa codes
37
39
  * CyclicCode: a class for encoding and decoding cyclic codes
38
40
  * ReedSolomonCode: a class for encoding and decoding Reed-Solomon codes
41
+ * BCHCode: a class for encoding and decoding primitive narrow sense BCH codes
39
42
 
40
43
  * BlockCipher: a class implementing the usual modes of operation (ECB, CBC, GCM, etc.)
41
44
  * AESCipher: individual AES operations
@@ -35,7 +35,7 @@ class GF2:
35
35
  f6
36
36
 
37
37
  """
38
- def __init__(self, n: int, modulus: int | None = None):
38
+ def __init__(self, n: int, modulus: int | None = None, cached = False):
39
39
  if not isinstance(n, int) or n < 1:
40
40
  raise ValueError(f"{n} is not a positive integer.")
41
41
  if not modulus:
@@ -55,14 +55,23 @@ class GF2:
55
55
  self.byteorder: str = "big" # big|little
56
56
  self.mult_order = self.order - 1
57
57
  self.factors = {} # factoring of the group order
58
+ self.cached = False # use precomputed log/exp tables to speed up multiplication
59
+ self.log = None # precomputed log table
60
+ self.exp = None # precomputed exp table
61
+ if cached:
62
+ self.cache()
58
63
 
59
64
  def __repr__(self):
60
65
  return f"GF(2^{self.degree})"
61
66
 
62
67
  def __call__(self, x: int | list | tuple | range | map):
63
68
  if isinstance(x, list|tuple|range|map):
64
- return [GF2nPoint(xx, self) for xx in x]
65
- return GF2nPoint(x, self)
69
+ if isinstance(x, bytes | bytearray):
70
+ return [ GF2nPoint(int.from_bytes(x, byteorder=self.byteorder), self) for xx in x]
71
+ return [GF2nPoint(int(xx) % self.order, self) for xx in x]
72
+ if isinstance(x, bytes | bytearray):
73
+ return GF2nPoint(int.from_bytes(x, byteorder=self.byteorder), self)
74
+ return GF2nPoint(int(x) % self.order, self)
66
75
 
67
76
  def __len__(self):
68
77
  return self.order
@@ -80,26 +89,26 @@ class GF2:
80
89
  return isinstance(other, GF2nPoint) and self == other.field
81
90
 
82
91
  def _factors(self) -> dict:
83
- "Return the factroization order of the group order of GF(2^n)^*."
92
+ "Return the factroization of the group order of GF(2^n)^*."
84
93
  if not self.factors:
85
94
  self.factors = factorint(self.mult_order)
86
95
  return self.factors
87
96
 
88
97
  def zero(self) -> bool:
89
98
  "Return zero."
90
- return self(0)
99
+ return GF2nPoint(0, self)
91
100
 
92
101
  def one(self) -> bool:
93
102
  "Return one."
94
103
  if self.bitreversed:
95
- return self(self.order - 1)
96
- return self(1)
104
+ return GF2nPoint(self.order >> 1, self)
105
+ return GF2nPoint(1, self)
97
106
 
98
107
  def random(self, num: int = 0) -> "GF2nPoint":
99
108
  "Return a single random point or a list of random points."
100
109
  if num:
101
- return([self(randint(0,self.order-1)) for _ in range(num)])
102
- return self(randint(0,self.order-1))
110
+ return([GF2nPoint(randint(0,self.order-1), self) for _ in range(num)])
111
+ return GF2nPoint(randint(0,self.order-1), self)
103
112
 
104
113
  def is_cyclic(self) -> bool:
105
114
  "GF(2^n)^* is cyclic."
@@ -111,10 +120,12 @@ class GF2:
111
120
 
112
121
  def generator(self) -> int | None:
113
122
  "Return a generator of the group GF(2^n)^*."
123
+ if self.cached:
124
+ return self.exp[1]
114
125
  if self.degree == 1:
115
- return self(1)
126
+ return self.one()
116
127
  for a in range(2, self.order):
117
- a = self(a)
128
+ a = GF2nPoint(a, self)
118
129
  if a.is_generator():
119
130
  return a
120
131
 
@@ -129,16 +140,35 @@ class GF2:
129
140
  def star(self) -> list:
130
141
  "Return a generator for all elements of the group GF(2^n)n^*."
131
142
  for x in range(1, self.order):
132
- yield self(x)
143
+ yield GF2nPoint(x, self)
144
+
145
+ def poly(self) -> Poly:
146
+ "Return the associated irreducible polynomial."
147
+ coeff = [int(d) for d in str(
148
+ format(self.modulus, "b"))]
149
+ if self.bitreversed:
150
+ return Poly(coeff + [1])
151
+ return Poly(list(reversed(coeff)))
152
+
153
+ def cache(self) -> None:
154
+ "Create a exp/log table to speed up multiplication."
155
+ if not self.cached:
156
+ self.exp = [ 0 ] * self.mult_order
157
+ self.log = [ 0 ] * self.order
158
+ g = self.generator()
159
+ gj = self.one()
160
+ for j in range(self.mult_order):
161
+ self.exp[j] = gj
162
+ self.log[gj.x] = j
163
+ gj *= g
164
+ self.cached = True
133
165
 
134
166
 
135
167
  class GF2nPoint:
136
168
  "Represents a point in the Galois field GF(2^n)."
137
169
 
138
170
  def __init__(self, x: int, field: "GF2"):
139
- if isinstance(x, bytes | bytearray):
140
- x = int.from_bytes(x, byteorder=field.byteorder)
141
- self.x = int(x) % field.order
171
+ self.x = x
142
172
  self.field = field
143
173
 
144
174
  def __repr__(self):
@@ -162,13 +192,11 @@ class GF2nPoint:
162
192
 
163
193
  def bits(self) -> list:
164
194
  "Convert to a list of bits."
195
+ coeff = [int(d) for d in str(
196
+ format(self.x, "0" + str(self.field.degree) + "b"))]
165
197
  if self.field.bitreversed:
166
- coeff = [int(d) for d in str(
167
- format(self.x, "0" + str(self.field.degree) + "b"))]
168
- else:
169
- coeff = reversed([int(d) for d in str(
170
- format(self.x, "0" + str(self.field.degree) + "b"))])
171
- return list(coeff)
198
+ coeff.reverse()
199
+ return coeff
172
200
 
173
201
  def poly(self) -> "Poly":
174
202
  "Convert to a polynomial."
@@ -193,7 +221,7 @@ class GF2nPoint:
193
221
  return NotImplemented
194
222
  if self.field != other.field:
195
223
  raise NotImplementedError("Cannot add elements from different fields.")
196
- return self.field(self.x ^ other.x)
224
+ return self.__class__(self.x ^ other.x, self.field)
197
225
 
198
226
  __sub__ = __add__
199
227
 
@@ -206,11 +234,15 @@ class GF2nPoint:
206
234
  if isinstance(other, int):
207
235
  if other % 2:
208
236
  return self
209
- return self.field(0)
237
+ return self.__class__(0, self.field)
210
238
  if not isinstance(other, self.__class__):
211
239
  return NotImplemented
212
240
  if self.field != other.field:
213
- raise NotImplementedError("Cannot add elements from different fields.")
241
+ raise NotImplementedError("Cannot multiply elements from different fields.")
242
+ if self.field.cached:
243
+ if self.x and other.x:
244
+ return self.field.exp[(self.field.log[self.x] + self.field.log[other.x]) % self.field.mult_order]
245
+ return self.field.zero()
214
246
  z = 0
215
247
  y = other.x
216
248
  if self.field.bitreversed:
@@ -232,13 +264,13 @@ class GF2nPoint:
232
264
  y <<= 1
233
265
  if y & bitmap1:
234
266
  y ^= self.field.modulus
235
- return self.field(z)
267
+ return self.__class__(z, self.field)
236
268
 
237
269
  def __rmul__(self, scalar: int) -> "GF2nPoint":
238
270
  if isinstance(scalar, int):
239
271
  if scalar % 2:
240
272
  return self
241
- return self.field(0)
273
+ return self.__class__(0, self.field)
242
274
  return NotImplemented
243
275
 
244
276
  def __truediv__(self, other: "GF2nPoint") -> "GF2nPoint":
@@ -253,16 +285,22 @@ class GF2nPoint:
253
285
  def __pow__(self, j: int) -> "GF2nPoint":
254
286
  if not isinstance(j, int):
255
287
  return NotImplemented
256
- if not (self.x) and j < 0:
257
- raise ValueError("Division by zero.")
288
+ if self.x == 0:
289
+ if j < 0:
290
+ raise ValueError("Division by zero.")
291
+ if j:
292
+ return self
293
+ return self.field.one()
294
+ j %= self.field.mult_order
295
+ if self.field.cached:
296
+ return self.field.exp[j * self.field.log[self.x] % self.field.mult_order]
258
297
  if self.field.order == 2:
259
298
  return self
260
299
  if self.field.bitreversed:
261
- res = self.field(self.field.order >> 1)
300
+ res = self.__class__(self.field.order >> 1, self.field)
262
301
  else:
263
- res = self.field(1)
264
- x = self.field(self.x)
265
- j %= self.field.order - 1
302
+ res = self.__class__(1, self.field)
303
+ x = self.__class__(self.x, self.field)
266
304
  while j > 0:
267
305
  # If j is odd, multiply with x
268
306
  if j & 1:
@@ -276,13 +314,13 @@ class GF2nPoint:
276
314
  "Cyclic rotation to the left."
277
315
  x = self.x << j
278
316
  x = (x % self.field.order) + (x // self.field.order)
279
- return self.field(x)
317
+ return self.__class__(self.x, self.field)
280
318
 
281
319
  def __rshift__(self, j: int) -> "GF2nPoint":
282
320
  "Cyclic rotation to the right."
283
321
  x = self.x >> j
284
322
  x += (self.field.order >> j) * (self.x % 2**j)
285
- return self.field(x)
323
+ return self.__class__(self.x, self.field)
286
324
 
287
325
  def sqrt(self) -> "GF2nPoint":
288
326
  "Compute the square root."
@@ -308,6 +346,17 @@ class GF2nPoint:
308
346
  "Test if the point is a generator of the group GF(2^n)^*."
309
347
  return self.field.mult_order == self.order()
310
348
 
349
+ def minpoly(self) -> Poly:
350
+ "Return the minimal polynomial of an element."
351
+ aj = self
352
+ mpoly = Poly([aj, self.field.one()])
353
+ for _ in range(1, self.field.degree):
354
+ aj = aj**2 # Frobenius
355
+ if aj == self:
356
+ break
357
+ mpoly *= Poly([aj, self.field.one()])
358
+ return mpoly
359
+
311
360
  def sbox(self, inv: bool = False) -> "GF2nPoint":
312
361
  "Apply the AES sbox."
313
362
  if self.field.degree == 8 and self.field.modulus == 0b100011011: # AES
@@ -321,7 +370,7 @@ class GF2nPoint:
321
370
  raise ValueError("sbox is only availaible for AES/MiniAES field.")
322
371
 
323
372
  # sbox for AES
324
- GF2_aes = GF2(8, 0b100011011) # x^8 + x^4 + x^3 + x + 1 = AES
373
+ GF2_aes = GF2(8, 0b100011011, cached = True) # x^8 + x^4 + x^3 + x + 1 = AES
325
374
 
326
375
  aes_sbox = [99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
327
376
  202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
@@ -43,8 +43,8 @@ class Zmod:
43
43
 
44
44
  def __call__(self, x: int | list | tuple | range | map):
45
45
  if isinstance(x, list|tuple|range|map):
46
- return [ZmodPoint(xx, self) for xx in x]
47
- return ZmodPoint(x, self)
46
+ return [ZmodPoint(int(xx), self) for xx in x]
47
+ return ZmodPoint(int(x), self)
48
48
 
49
49
  def __iter__(self):
50
50
  for x in range(self.n):
@@ -157,7 +157,7 @@ class ZmodPoint:
157
157
  "Represents a point in the ring Zmod."
158
158
 
159
159
  def __init__(self, x: int, ring: "Zmod"):
160
- self.x = int(x) % ring.n
160
+ self.x = x % ring.n
161
161
  self.ring = ring
162
162
 
163
163
  def __repr__(self):
@@ -247,8 +247,11 @@ class ZmodPoint:
247
247
 
248
248
  def sharp(self):
249
249
  "Returns a symmetric (w.r.t. 0) representative."
250
- tmp = (self.ring.n - 1) // 2
251
- return (self.x + tmp) % self.ring.n - tmp
250
+ if self.x <= self.ring.n // 2:
251
+ return self.x
252
+ return self.x - self.ring.n
253
+
254
+ mods = sharp
252
255
 
253
256
  def order(self) -> int:
254
257
  "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.5.3"
8
+ __version__ = "1.7"
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
@@ -14,12 +14,12 @@ from .intfuncs import iroot, ilog, perfect_square, perfect_power, prime_power
14
14
  from .factor import factorint, divisors
15
15
  from .dlp import dlog
16
16
  from .ec import EC_Weierstrass
17
- from .la import Matrix, zeros, eye
17
+ from .la import Matrix, zeros, eye, circulant, BinaryMatrix
18
18
  from .lat import gram_det, hadamard_ratio, hermite_nf, gram_schmidt, babai_round_cvp, babai_round_bnd, babai_plane_cvp, babai_plane_bnd, lagrange_lr, lll, random_unimodular_matrix
19
- from .poly import Poly, lagrange_interpolation
19
+ from .poly import Poly, PolyBinMult, lagrange_interpolation
20
20
  from .Zmod import Zmod
21
21
  from .GF2 import GF2, GF2_aes, GF2_miniaes, GF2_ghash
22
- from .code import left_standard_form, gen2pchk, hamming_dist, Goppa, CyclicCode, ReedSolomonCode
22
+ from .code import gen2pchk, hamming_dist, BinaryCode, GolayCode, HammingCode, ReedMullerCode, GoppaCode, CyclicCode, ReedSolomonCode, BCHCode
23
23
  from .blockcipher import BlockCipher, bytexor
24
24
  from .aes import AESKeySchedule, AESCipher, AESBlockCipher
25
25
  from .des import list2int, int2list, permute, invert_permutation, rotate_left, SDESKeySchedule, SDESCipher, DESKeySchedule, DESCipher, DESBlockCipher