kryptools 1.2__tar.gz → 1.3.1__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 (58) hide show
  1. {kryptools-1.2 → kryptools-1.3.1}/PKG-INFO +3 -1
  2. {kryptools-1.2 → kryptools-1.3.1}/README.md +2 -0
  3. {kryptools-1.2 → kryptools-1.3.1}/kryptools/GF2.py +3 -0
  4. {kryptools-1.2 → kryptools-1.3.1}/kryptools/Zmod.py +5 -1
  5. {kryptools-1.2 → kryptools-1.3.1}/kryptools/__init__.py +2 -1
  6. kryptools-1.3.1/kryptools/code.py +140 -0
  7. {kryptools-1.2 → kryptools-1.3.1}/kryptools/la.py +2 -2
  8. {kryptools-1.2 → kryptools-1.3.1}/kryptools/lat.py +2 -1
  9. {kryptools-1.2 → kryptools-1.3.1}/kryptools/poly.py +29 -7
  10. {kryptools-1.2 → kryptools-1.3.1}/kryptools.egg-info/PKG-INFO +3 -1
  11. {kryptools-1.2 → kryptools-1.3.1}/kryptools.egg-info/SOURCES.txt +2 -0
  12. {kryptools-1.2 → kryptools-1.3.1}/pyproject.toml +1 -1
  13. {kryptools-1.2 → kryptools-1.3.1}/tests/test_GF2.py +5 -0
  14. {kryptools-1.2 → kryptools-1.3.1}/tests/test_Zmod.py +9 -0
  15. kryptools-1.3.1/tests/test_code.py +41 -0
  16. {kryptools-1.2 → kryptools-1.3.1}/tests/test_la.py +7 -0
  17. kryptools-1.3.1/tests/test_poly.py +36 -0
  18. kryptools-1.2/tests/test_poly.py +0 -20
  19. {kryptools-1.2 → kryptools-1.3.1}/LICENSE +0 -0
  20. {kryptools-1.2 → kryptools-1.3.1}/kryptools/aes.py +0 -0
  21. {kryptools-1.2 → kryptools-1.3.1}/kryptools/blockcipher.py +0 -0
  22. {kryptools-1.2 → kryptools-1.3.1}/kryptools/conway_polynomials.py +0 -0
  23. {kryptools-1.2 → kryptools-1.3.1}/kryptools/des.py +0 -0
  24. {kryptools-1.2 → kryptools-1.3.1}/kryptools/dlp.py +0 -0
  25. {kryptools-1.2 → kryptools-1.3.1}/kryptools/dlp_bsgs.py +0 -0
  26. {kryptools-1.2 → kryptools-1.3.1}/kryptools/dlp_ic.py +0 -0
  27. {kryptools-1.2 → kryptools-1.3.1}/kryptools/dlp_qs.py +0 -0
  28. {kryptools-1.2 → kryptools-1.3.1}/kryptools/dlp_rho.py +0 -0
  29. {kryptools-1.2 → kryptools-1.3.1}/kryptools/ec.py +0 -0
  30. {kryptools-1.2 → kryptools-1.3.1}/kryptools/factor.py +0 -0
  31. {kryptools-1.2 → kryptools-1.3.1}/kryptools/factor_dix.py +0 -0
  32. {kryptools-1.2 → kryptools-1.3.1}/kryptools/factor_ecm.py +0 -0
  33. {kryptools-1.2 → kryptools-1.3.1}/kryptools/factor_fmt.py +0 -0
  34. {kryptools-1.2 → kryptools-1.3.1}/kryptools/factor_pm1.py +0 -0
  35. {kryptools-1.2 → kryptools-1.3.1}/kryptools/factor_qs.py +0 -0
  36. {kryptools-1.2 → kryptools-1.3.1}/kryptools/factor_rho.py +0 -0
  37. {kryptools-1.2 → kryptools-1.3.1}/kryptools/intfuncs.py +0 -0
  38. {kryptools-1.2 → kryptools-1.3.1}/kryptools/keccak.py +0 -0
  39. {kryptools-1.2 → kryptools-1.3.1}/kryptools/nt.py +0 -0
  40. {kryptools-1.2 → kryptools-1.3.1}/kryptools/primes.py +0 -0
  41. {kryptools-1.2 → kryptools-1.3.1}/kryptools/sha1.py +0 -0
  42. {kryptools-1.2 → kryptools-1.3.1}/kryptools.egg-info/dependency_links.txt +0 -0
  43. {kryptools-1.2 → kryptools-1.3.1}/kryptools.egg-info/top_level.txt +0 -0
  44. {kryptools-1.2 → kryptools-1.3.1}/setup.cfg +0 -0
  45. {kryptools-1.2 → kryptools-1.3.1}/tests/test_aes.py +0 -0
  46. {kryptools-1.2 → kryptools-1.3.1}/tests/test_des.py +0 -0
  47. {kryptools-1.2 → kryptools-1.3.1}/tests/test_dlog.py +0 -0
  48. {kryptools-1.2 → kryptools-1.3.1}/tests/test_ec.py +0 -0
  49. {kryptools-1.2 → kryptools-1.3.1}/tests/test_factor.py +0 -0
  50. {kryptools-1.2 → kryptools-1.3.1}/tests/test_factor_fmt.py +0 -0
  51. {kryptools-1.2 → kryptools-1.3.1}/tests/test_factor_pm1.py +0 -0
  52. {kryptools-1.2 → kryptools-1.3.1}/tests/test_factor_qs.py +0 -0
  53. {kryptools-1.2 → kryptools-1.3.1}/tests/test_intfuncs.py +0 -0
  54. {kryptools-1.2 → kryptools-1.3.1}/tests/test_keccak.py +0 -0
  55. {kryptools-1.2 → kryptools-1.3.1}/tests/test_lat.py +0 -0
  56. {kryptools-1.2 → kryptools-1.3.1}/tests/test_nt.py +0 -0
  57. {kryptools-1.2 → kryptools-1.3.1}/tests/test_primes.py +0 -0
  58. {kryptools-1.2 → kryptools-1.3.1}/tests/test_sha1.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kryptools
3
- Version: 1.2
3
+ Version: 1.3.1
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
@@ -39,11 +39,13 @@ The tools contained are:
39
39
  * elliptic curves (Weierstrass form), group operations, order, discrete logarithms
40
40
  * linear algebra: Hermite normal form, Gram-Schmidt
41
41
  * lattices: Hadamard ratio, Babai rounding/nearest plane algorithm, lattice reduction (Lenstra-Lenstra-Lovaz)
42
+ * linear codes: Hamming distance, left standard form, parity check matrix
42
43
 
43
44
  * Matrix: a class for Matrices (inverse, det, reduced echelon form, etc.)
44
45
  * Poly: a class for polynomials (division, modulo)
45
46
  * Zmod: a class for the ring of integers modulo an integer
46
47
  * GF2: a class for Galois fields GF(2^n)
48
+ * Goppa: a class for encoding and decoding Goppa codes
47
49
 
48
50
  * BlockCipher: a class implementing the usual modes of operation (ECB, CBC, GCM, etc.)
49
51
  * AESCipher: individual AES operations
@@ -21,11 +21,13 @@ The tools contained are:
21
21
  * elliptic curves (Weierstrass form), group operations, order, discrete logarithms
22
22
  * linear algebra: Hermite normal form, Gram-Schmidt
23
23
  * lattices: Hadamard ratio, Babai rounding/nearest plane algorithm, lattice reduction (Lenstra-Lenstra-Lovaz)
24
+ * linear codes: Hamming distance, left standard form, parity check matrix
24
25
 
25
26
  * Matrix: a class for Matrices (inverse, det, reduced echelon form, etc.)
26
27
  * Poly: a class for polynomials (division, modulo)
27
28
  * Zmod: a class for the ring of integers modulo an integer
28
29
  * GF2: a class for Galois fields GF(2^n)
30
+ * Goppa: a class for encoding and decoding Goppa codes
29
31
 
30
32
  * BlockCipher: a class implementing the usual modes of operation (ECB, CBC, GCM, etc.)
31
33
  * AESCipher: individual AES operations
@@ -62,6 +62,9 @@ class GF2:
62
62
  return [GF2nPoint(xx, self) for xx in x]
63
63
  return GF2nPoint(x, self)
64
64
 
65
+ def __len__(self):
66
+ return self.order
67
+
65
68
  def __iter__(self):
66
69
  for x in range(self.order):
67
70
  yield GF2nPoint(x, self)
@@ -17,7 +17,7 @@ class Zmod:
17
17
  To define a finite Galois field modulo the prime 5 use
18
18
  >>> Z_5=Zmod(5)
19
19
 
20
- To declare 3 as an element of our Galois filed use
20
+ To declare 3 as an element of our Galois field use
21
21
  >>> Z_5(3)
22
22
  3
23
23
 
@@ -210,6 +210,10 @@ class ZmodPoint:
210
210
  def __abs__(self) -> int:
211
211
  return abs(self.sharp())
212
212
 
213
+ def bits(self) -> list:
214
+ "Convert to a list of bits."
215
+ return [int(d) for d in str(format(self.x, "0" + str(int.bit_length(self.ring.n - 1)) + "b"))]
216
+
213
217
  def sharp(self):
214
218
  "Returns a symmetric (w.r.t. 0) representative."
215
219
  tmp = (self.ring.n - 1) // 2
@@ -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.2"
8
+ __version__ = "1.3.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
@@ -19,6 +19,7 @@ from .lat import gram_det, hadamard_ratio, hermite_nf, gram_schmidt, babai_round
19
19
  from .poly import Poly
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
22
23
  from .blockcipher import BlockCipher, bytexor
23
24
  from .aes import AESKeySchedule, AESCipher, AESBlockCipher
24
25
  from .des import list2int, int2list, permute, invert_permutation, rotate_left, SDESKeySchedule, SDESCipher, DESKeySchedule, DESCipher, DESBlockCipher
@@ -0,0 +1,140 @@
1
+ """
2
+ Linear codes
3
+ """
4
+
5
+ from .Zmod import Zmod
6
+ from .GF2 import GF2
7
+ from .poly import Poly
8
+ from .la import Matrix, eye, zeros
9
+
10
+
11
+ def poly2bits(x: Poly) -> list:
12
+ "Convert a polynomial in GF(2^n)[x] to a list of binary digits."
13
+ out = []
14
+ for c in x.coeff:
15
+ out += c.bits()
16
+ return out
17
+
18
+ def left_standard_form(M: Matrix) -> (Matrix, Matrix):
19
+ "Compute the left standard form of a generator matrix. Return the standard form and the pertmutation matrix."
20
+ # reduced row echelon form
21
+ M = M.rref()
22
+ # purge zero rows
23
+ for i in range(M.rows-1,-1,-1):
24
+ if not M[i,:]:
25
+ M.delete_rows(i)
26
+ # permute columns to get the identity on the left
27
+ last = min(M.rows, M.cols)
28
+ P = eye(M.cols)
29
+ for i in range(last):
30
+ if not M[i,i]: # the diagonal entry vanishes
31
+ # find the index of the pivot and permute
32
+ j = i + 1
33
+ while j <= M.cols and not M[i, j]:
34
+ j += 1
35
+ P[:,i], P[:,j] = P[:,j], P[:,i]
36
+ M[:,i], M[:,j] = M[:,j], M[:,i]
37
+ return M, P
38
+
39
+ def gen2pchk(G: Matrix) -> Matrix:
40
+ "Compute the parity check matrix from a given generator matrix (and vice versa)."
41
+ G, P = left_standard_form(G)
42
+ d = G.cols - G.rows
43
+ if d <= 0:
44
+ raise ValueError("A generator matrix must have more columns than rows!")
45
+ zero = 0 * G[0]
46
+ one = zero**0
47
+ # we start with a zero matrix
48
+ H = zeros(d, G.cols, zero = zero)
49
+ # create the identity on the right
50
+ for i in range(d):
51
+ H[i,G.rows+i] = one
52
+ # add minus the transpose of the right part of G as the left part
53
+ tmp = - G[:,-d:].transpose()
54
+ for i in range(G.cols - d):
55
+ H[:, i] = tmp[:, i]
56
+ return H * P.transpose()
57
+
58
+ def hamming_dist(a: iter, b: iter):
59
+ "Hamming distance of two iterables."
60
+ if len(a) != len(b):
61
+ raise ValueError("Both iteralbles must have equal length.")
62
+ return sum(aa != bb for aa, bb in zip(a, b))
63
+
64
+ class Goppa():
65
+ """
66
+ Binary irreducible Goppa code.
67
+
68
+ Example:
69
+
70
+ >>> gf = GF2(4) # base field GF(2^n)
71
+ >>> g = Poly([2, 0, 0, 1], ring = gf) # irreducible Polynomial for the code
72
+ >>> alpha = list(gf) # list of points from the base field (must not contain zeros of g)
73
+ >>> goppa = Goppa(gf, g, alpha)
74
+
75
+ To encode a list of bits (the length must be equal to the dimension k of the code)
76
+ >>> goppa.encode([1, 0, 1, 1])
77
+ [0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1]
78
+
79
+ Decoding still works if there are at most deg(g) errors:
80
+ >>> goppa.decode([0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0])
81
+ [1, 0, 1, 1]
82
+
83
+ """
84
+
85
+ def __init__(self, gf: GF2, g: Poly, alpha: list["GF2Point"]):
86
+ if not all(map(lambda x: x in gf, alpha)):
87
+ raise ValueError(f"{x}: alpha must be a list of elements from the Galois field!")
88
+ if not g.rabin_test():
89
+ raise ValueError(f"The polynomial g must be irreducible!")
90
+ self.gf = gf # underlying Galois field
91
+ self.g = g # polynomial
92
+ self.alpha = alpha # list of elements from gf
93
+ # Compute the control matrix
94
+ self.Z_2 = Zmod(2)
95
+
96
+ tmp =[]
97
+ for x in alpha:
98
+ tmp.append(Poly([-x, 1], ring = gf, modulus = g).inv().bits())
99
+ self.H = Matrix(tmp, ring=self.Z_2).transpose()
100
+ # Compute the generator matrix
101
+ self.G = gen2pchk(self.H)
102
+
103
+ def __repr__(self):
104
+ return f"Binary irreducible Goppa code over GF(2^{self.gf.power}) with polynomial g(x) = {self.g}."
105
+
106
+ def encode(self, x: list[int]):
107
+ "Encode a given list of bits."
108
+ x = Matrix(x, ring = self.Z_2)
109
+ y = self.G.transpose() * x
110
+ y.map(int)
111
+ return list(y)
112
+
113
+ def decode(self, y: list[int]):
114
+ "Decode a given list of bits."
115
+ y = Matrix(y, ring = self.Z_2)
116
+ if self.H * y: # no code word
117
+ s = self.gf(0) # syndrom polynomial
118
+ for i, x in enumerate(self.alpha):
119
+ s += int(y[i]) * Poly([-x, 1], ring = self.gf, modulus = self.g).inv()
120
+ v = (s.inv() - Poly([0, 1], ring = self.gf, modulus = self.g))**(self.gf.order ** self.g.degree() // 2)
121
+ # determine error locator polynomial sigma(x) = a(x^2) + b(x^2) * x
122
+ # find a and b by running EEA until b has the desired degree
123
+ v.modulus = None
124
+ r0, r1 = self.g, v
125
+ y0, y1 = Poly([self.gf(0)]), Poly([self.gf(1)])
126
+ while 2 * r1.degree() > self.g.degree():
127
+ q, r = r0.divmod(r1)
128
+ r0, r1 = r1, r
129
+ y0, y1 = y1, y0 - q * y1
130
+ a, b = r1, y1
131
+ sigma = a**2 + b**2 * Poly([0,1], ring = self.gf)
132
+ # correct the error
133
+ for x in self.alpha:
134
+ if not sigma(x):
135
+ y[int(x)] += 1
136
+ if self.H * y:
137
+ raise ValueError("Decoding failed!")
138
+ x = self.G.transpose().solve(y)
139
+ x.map(int)
140
+ return list(x)
@@ -191,7 +191,7 @@ class Matrix:
191
191
  return False
192
192
  if self.rows != other.rows or self.cols != other.cols:
193
193
  return False
194
- return any(self[i] == other[i] for i in range(self.rows * self.cols))
194
+ return all(self[i] == other[i] for i in range(self.rows * self.cols))
195
195
 
196
196
  def __bool__(self):
197
197
  return any(bool(self[i]) for i in range(self.rows * self.cols))
@@ -374,7 +374,7 @@ class Matrix:
374
374
  A[:, 0:self.cols] = self
375
375
  A[:, self.cols] = b
376
376
  A = A.rref()
377
- solution = self.zeros(self.rows, 1)
377
+ solution = self.zeros(self.cols, 1)
378
378
  for i in range(A.rows-1, -1, -1):
379
379
  if not any(A.matrix[i][:-1]):
380
380
  if A.matrix[i][-1]:
@@ -109,7 +109,8 @@ def babai_plane_bnd(U: Matrix, p=2) -> float:
109
109
 
110
110
  def lagrange_lr(V: Matrix) -> Matrix:
111
111
  "Lagrange lattice reduction."
112
- assert (V.rows, V.cols) == (2, 2)
112
+ if (V.rows, V.cols) != (2, 2):
113
+ raise ValueError("Lagrange lattice reduction requires dimension two.")
113
114
  v1, v2 = V[:, 0], V[:, 1]
114
115
  if norm2(v1) > norm2(v2):
115
116
  v1, v2 = v2, v1
@@ -4,7 +4,7 @@ Polynomials
4
4
 
5
5
  from numbers import Number
6
6
  from .primes import is_prime
7
- from .factor import factorint
7
+ #from .factor import factorint
8
8
 
9
9
  class Poly:
10
10
  """
@@ -231,6 +231,16 @@ class Poly:
231
231
  tmp *= tmp
232
232
  return res
233
233
 
234
+ def bits(self) -> list[int]:
235
+ "List of bits of all coefficients."
236
+ ring = self.coeff[0].__class__
237
+ if not (hasattr(ring, 'bits') and callable(ring.bits)):
238
+ raise NotImplementedError("Coefficients cannot be converted to bits.")
239
+ out = []
240
+ for c in self.coeff:
241
+ out += c.bits()
242
+ return out
243
+
234
244
  def max(self) -> int:
235
245
  "Maximum of the absolute value of all coefficients."
236
246
  return max(abs(c) for c in self.coeff)
@@ -377,11 +387,23 @@ class Poly:
377
387
  isfield = True
378
388
  if not isfield:
379
389
  raise ValueError("The polynomial does not seem to be over a finite field.")
380
- n = self.degree()
381
- x = self.__class__([0, 1], ring=ring, modulus = self.coeff) # x
382
- for p in factorint(n).keys():
383
- g = self.gcd(x**(q**(n//p)) - x) # gcd with x^{q/n} - x
390
+ #n = self.degree()
391
+ #x = self.__class__([0, 1], ring=ring, modulus = self.coeff) # x
392
+ #for p in factorint(n).keys():
393
+ # g = self.gcd(x**(q**(n//p)) - x) # gcd with x^{q/n} - x
394
+ # if g.degree():
395
+ # return False
396
+ #g = x**(q**n) - x
397
+ #return not(g)
398
+ x = Poly([0, 1], ring = ring) # x
399
+ xq = Poly(q * [0] + [1], ring = ring, modulus = self.coeff) # x^q modulo self to keep the polynomials small
400
+ for k in range(1, self.degree() // 2 + 1):
401
+ if k == 1:
402
+ b = xq
403
+ else:
404
+ b **= q # we compute x^{q^k} mod a recursively
405
+ g = self.gcd(b - x) # gcd with x^{q^k} - x
384
406
  if g.degree():
385
407
  return False
386
- g = x**(q**n) - x
387
- return not(g)
408
+ return True
409
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kryptools
3
- Version: 1.2
3
+ Version: 1.3.1
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
@@ -39,11 +39,13 @@ The tools contained are:
39
39
  * elliptic curves (Weierstrass form), group operations, order, discrete logarithms
40
40
  * linear algebra: Hermite normal form, Gram-Schmidt
41
41
  * lattices: Hadamard ratio, Babai rounding/nearest plane algorithm, lattice reduction (Lenstra-Lenstra-Lovaz)
42
+ * linear codes: Hamming distance, left standard form, parity check matrix
42
43
 
43
44
  * Matrix: a class for Matrices (inverse, det, reduced echelon form, etc.)
44
45
  * Poly: a class for polynomials (division, modulo)
45
46
  * Zmod: a class for the ring of integers modulo an integer
46
47
  * GF2: a class for Galois fields GF(2^n)
48
+ * Goppa: a class for encoding and decoding Goppa codes
47
49
 
48
50
  * BlockCipher: a class implementing the usual modes of operation (ECB, CBC, GCM, etc.)
49
51
  * AESCipher: individual AES operations
@@ -6,6 +6,7 @@ kryptools/Zmod.py
6
6
  kryptools/__init__.py
7
7
  kryptools/aes.py
8
8
  kryptools/blockcipher.py
9
+ kryptools/code.py
9
10
  kryptools/conway_polynomials.py
10
11
  kryptools/des.py
11
12
  kryptools/dlp.py
@@ -36,6 +37,7 @@ kryptools.egg-info/top_level.txt
36
37
  tests/test_GF2.py
37
38
  tests/test_Zmod.py
38
39
  tests/test_aes.py
40
+ tests/test_code.py
39
41
  tests/test_des.py
40
42
  tests/test_dlog.py
41
43
  tests/test_ec.py
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kryptools"
3
- version = "1.2"
3
+ version = "1.3.1"
4
4
  authors = [
5
5
  { name="Gerald Teschl", email="gerald.teschl@univie.ac.at" },
6
6
  ]
@@ -8,6 +8,11 @@ num_tests = 50
8
8
  def test_GF2_ops():
9
9
  for n, modulus in [(4, None), (8, None), (8, 0b100011011), (12, None), (128, 0b11100001 << 120)]:
10
10
  gf = GF2(n, modulus=modulus)
11
+ assert gf(1)
12
+ assert not gf(0)
13
+ assert gf(1) == gf(1)
14
+ assert not gf(1) == gf(0)
15
+ assert not gf(0) == 0
11
16
  if gf.power < 17:
12
17
  assert len(list(gf)) == gf.order
13
18
  assert len(list(gf.star())) == gf.order - 1
@@ -42,6 +42,11 @@ def test_Zmod_methods():
42
42
  assert list(Z_5.star()) == Z_5([1, 2, 3, 4])
43
43
  assert [Z_5(i).sharp() for i in range(Z_5.n)] == [0, 1, 2, -2, -1]
44
44
  assert [abs(Z_5(i)) for i in range(Z_5.n)] == [0, 1, 2, 2, 1]
45
+ assert not Z_5(0)
46
+ assert Z_5(1)
47
+ assert Z_5(2) == Z_5(2)
48
+ assert Z_5(2) != Z_5(3)
49
+ assert Z_5(2) != 2
45
50
  assert str(Z_5(3)) == "3"
46
51
  Z_5.short = False
47
52
  assert str(Z_5(6)) == "1 (mod 5)"
@@ -57,6 +62,10 @@ def test_Zmod_methods():
57
62
  assert Z_6(5).is_generator() is True
58
63
  assert list(Z_6.generators()) == Z_6([5])
59
64
  assert list(Z_6.star()) == Z_6([1, 5])
65
+ assert Z_6(1)
66
+ assert Z_6(2) == Z_6(2)
67
+ assert Z_6(2) != Z_6(3)
68
+ assert Z_5(2) != Z_6(2)
60
69
  assert str(Z_6(3)) == "3"
61
70
 
62
71
 
@@ -0,0 +1,41 @@
1
+ import pytest
2
+ from random import randint, seed
3
+ from kryptools import Zmod, GF2, Poly, Matrix
4
+ from kryptools import gen2pchk, Goppa
5
+
6
+ seed(0)
7
+ Z_2 = Zmod(2)
8
+
9
+ def Hamming2(h: int) -> Matrix:
10
+ "Parity check matrix for the binary Hamming code."
11
+ out = []
12
+ for i in range(1,2**h):
13
+ out.append([int(d) for d in str(format(i, "0" + str(h) + "b"))])
14
+ return Matrix(out, ring = Z_2).transpose()
15
+
16
+
17
+ def test_gen2pchk():
18
+ for h in range(2,6):
19
+ H = Hamming2(h)
20
+ G = gen2pchk(H)
21
+ assert not H * G.transpose()
22
+
23
+ num_tests = 10
24
+
25
+ def test_Goppa():
26
+ for gf, t in [ [GF2(4), 3], [GF2(6), 4]]:
27
+ found = False
28
+ while not found:
29
+ c = [randint(0,gf.order-1) for _ in range(t)] + [1]
30
+ g = Poly(c, ring = gf)
31
+ found = g.rabin_test()
32
+ alpha = list(gf)
33
+
34
+ goppa = Goppa(gf, g, alpha)
35
+ for _ in range(num_tests):
36
+ x = [ randint(0,1) for _ in range(goppa.G.rows) ]
37
+ y = goppa.encode(x)
38
+ for _ in range(t):
39
+ i = randint(0, goppa.G.cols-1)
40
+ y[i] = 1- y[i]
41
+ assert goppa.decode(y) == x
@@ -5,6 +5,13 @@ from kryptools import Matrix, Zmod
5
5
 
6
6
  def test_Matrix():
7
7
  M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 12]])
8
+ Z = M.zeros()
9
+ assert M
10
+ assert M == M
11
+ assert not Z
12
+ Z[0] = 1
13
+ assert Z
14
+ assert Z != Z.zeros()
8
15
  assert len(M) == 3 * 3
9
16
  assert M[0] == 1
10
17
  assert M[:] == [1, 2, 3, 4, 5, 6, 7, 8, 12]
@@ -0,0 +1,36 @@
1
+ import pytest
2
+ from kryptools import Poly, Zmod, GF2
3
+ from kryptools import divisors, moebius_mu
4
+
5
+
6
+ def test_Poly():
7
+ p = Poly([2, 0, 2])
8
+ q = Poly([1, 2, 3, 4])
9
+ d, m = q.divmod(p)
10
+ assert d * p + m == q
11
+
12
+ Z_5 = Zmod(5)
13
+ p.map(Z_5)
14
+ q.map(Z_5)
15
+ d, m = q.divmod(p)
16
+ assert d * p + m == q
17
+
18
+ gf = GF2(8, modulus=0b100011011)
19
+ p = Poly([2, 1, 1, 3], modulus=[1, 0, 0, 0, 1], ring=gf)
20
+ q = p.inv()
21
+ assert p * q == Poly([1], modulus=[1, 0, 0, 0, 1], ring=gf)
22
+
23
+ def test_rabin():
24
+ for gf,t in [ [Zmod(7), 4], [GF2(4), 3]]:
25
+ order = len(list(gf))
26
+ count = 0
27
+ for i in range(order**t):
28
+ c = []
29
+ while i:
30
+ i, m = divmod(i, order)
31
+ c.append(m)
32
+ c += [0] * (t- len(c)) + [1]
33
+ a = Poly(c, ring=gf)
34
+ if a.rabin_test():
35
+ count += 1
36
+ assert count == sum([moebius_mu(d) * order ** (t // d) for d in divisors(t)]) // t
@@ -1,20 +0,0 @@
1
- import pytest
2
- from kryptools import Poly, Zmod, GF2
3
-
4
-
5
- def test_Poly():
6
- p = Poly([2, 0, 2])
7
- q = Poly([1, 2, 3, 4])
8
- d, m = q.divmod(p)
9
- assert d * p + m == q
10
-
11
- Z_5 = Zmod(5)
12
- p.map(Z_5)
13
- q.map(Z_5)
14
- d, m = q.divmod(p)
15
- assert d * p + m == q
16
-
17
- gf = GF2(8, modulus=0b100011011)
18
- p = Poly([2, 1, 1, 3], modulus=[1, 0, 0, 0, 1], ring=gf)
19
- q = p.inv()
20
- assert p * q == Poly([1], modulus=[1, 0, 0, 0, 1], ring=gf)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes