kryptools 0.4__tar.gz → 0.5__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 (28) hide show
  1. {kryptools-0.4 → kryptools-0.5}/PKG-INFO +2 -2
  2. {kryptools-0.4 → kryptools-0.5}/kryptools/Zmod.py +29 -11
  3. {kryptools-0.4 → kryptools-0.5}/kryptools/dlp.py +5 -4
  4. {kryptools-0.4 → kryptools-0.5}/kryptools/dlp_qs.py +3 -3
  5. {kryptools-0.4 → kryptools-0.5}/kryptools/ec.py +1 -1
  6. {kryptools-0.4 → kryptools-0.5}/kryptools/factor_ecm.py +1 -1
  7. {kryptools-0.4 → kryptools-0.5}/kryptools/la.py +14 -6
  8. {kryptools-0.4 → kryptools-0.5}/kryptools/nt.py +3 -2
  9. {kryptools-0.4 → kryptools-0.5}/kryptools/poly.py +34 -26
  10. {kryptools-0.4 → kryptools-0.5}/kryptools.egg-info/PKG-INFO +2 -2
  11. {kryptools-0.4 → kryptools-0.5}/pyproject.toml +2 -2
  12. {kryptools-0.4 → kryptools-0.5}/LICENSE +0 -0
  13. {kryptools-0.4 → kryptools-0.5}/README.md +0 -0
  14. {kryptools-0.4 → kryptools-0.5}/kryptools/__init__.py +0 -0
  15. {kryptools-0.4 → kryptools-0.5}/kryptools/dlp_bsgs.py +0 -0
  16. {kryptools-0.4 → kryptools-0.5}/kryptools/dlp_ic.py +0 -0
  17. {kryptools-0.4 → kryptools-0.5}/kryptools/dlp_rho.py +0 -0
  18. {kryptools-0.4 → kryptools-0.5}/kryptools/factor.py +0 -0
  19. {kryptools-0.4 → kryptools-0.5}/kryptools/factor_dix.py +0 -0
  20. {kryptools-0.4 → kryptools-0.5}/kryptools/factor_fmt.py +0 -0
  21. {kryptools-0.4 → kryptools-0.5}/kryptools/factor_pm1.py +0 -0
  22. {kryptools-0.4 → kryptools-0.5}/kryptools/factor_qs.py +0 -0
  23. {kryptools-0.4 → kryptools-0.5}/kryptools/lat.py +0 -0
  24. {kryptools-0.4 → kryptools-0.5}/kryptools/primes.py +0 -0
  25. {kryptools-0.4 → kryptools-0.5}/kryptools.egg-info/SOURCES.txt +0 -0
  26. {kryptools-0.4 → kryptools-0.5}/kryptools.egg-info/dependency_links.txt +0 -0
  27. {kryptools-0.4 → kryptools-0.5}/kryptools.egg-info/top_level.txt +0 -0
  28. {kryptools-0.4 → kryptools-0.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kryptools
3
- Version: 0.4
3
+ Version: 0.5
4
4
  Summary: Implemenation of same basic algorithms used in cryptography.
5
5
  Author-email: Gerald Teschl <gerald.teschl@univie.ac.at>
6
6
  Project-URL: Homepage, https://github.com/teschlg/kryptools
@@ -9,7 +9,7 @@ Project-URL: Docs, https://github.com/teschlg/kryptools/tree/main/doc
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Operating System :: OS Independent
12
- Requires-Python: >=3.8
12
+ Requires-Python: >=3.9
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
15
 
@@ -90,48 +90,66 @@ class ZmodPoint:
90
90
  return hash(self.x)
91
91
 
92
92
  def __add__(self, other: "ZmodPoint") -> "ZmodPoint":
93
- if isinstance(other, self.__class__) and self.ring == other.ring:
93
+ if isinstance(other, self.__class__):
94
+ if self.ring != other.ring:
95
+ raise NotImplementedError("Cannot add elements from different rings.")
94
96
  return self.__class__(self.x + other.x, self.ring)
95
97
  if isinstance(other, int):
96
98
  return self.__class__(self.x + other, self.ring)
97
99
  return NotImplemented
98
100
 
99
101
  def __radd__(self, scalar: int) -> "ZmodPoint":
100
- return self.__class__(scalar + self.x, self.ring)
102
+ if isinstance(scalar, int):
103
+ return self.__class__(scalar + self.x, self.ring)
104
+ return NotImplemented
101
105
 
102
106
  def __neg__(self) -> "ZmodPoint":
103
107
  return self.__class__(-self.x, self.ring)
104
108
 
105
109
  def __sub__(self, other: "ZmodPoint") -> "ZmodPoint":
106
- if isinstance(other, self.__class__) and self.ring == other.ring:
110
+ if isinstance(other, self.__class__):
111
+ if self.ring != other.ring:
112
+ raise NotImplementedError("Cannot subtract elements from different rings.")
107
113
  return self.__class__(self.x - other.x, self.ring)
108
114
  if isinstance(other, int):
109
115
  return self.__class__(self.x - other, self.ring)
110
116
  return NotImplemented
111
117
 
112
118
  def __rsub__(self, scalar: int) -> "ZmodPoint":
113
- return self.__class__(scalar - self.x, self.ring)
119
+ if isinstance(scalar, int):
120
+ return self.__class__(scalar - self.x, self.ring)
121
+ return NotImplemented
114
122
 
115
123
  def __mul__(self, other: "ZmodPoint") -> "ZmodPoint":
116
- if isinstance(other, self.__class__) and self.ring == other.ring:
124
+ if isinstance(other, self.__class__):
125
+ if self.ring != other.ring:
126
+ raise NotImplementedError("Cannot multiply elements from different rings.")
117
127
  return self.__class__(self.x * other.x, self.ring)
118
128
  if isinstance(other, int):
119
129
  return self.__class__(self.x * other, self.ring)
120
130
  return NotImplemented
121
131
 
122
132
  def __rmul__(self, scalar: int) -> "ZmodPoint":
123
- return self.__class__(scalar * self.x, self.ring)
133
+ if isinstance(scalar, int):
134
+ return self.__class__(scalar * self.x, self.ring)
135
+ return NotImplemented
124
136
 
125
137
  def __truediv__(self, other: "ZmodPoint") -> "ZmodPoint":
126
- if not isinstance(other, self.__class__) or self.ring != other.ring:
127
- return NotImplemented
128
- return self.__class__(self.x * pow(other.x, -1, self.ring.n), self.ring)
138
+ if isinstance(other, self.__class__):
139
+ if self.ring != other.ring:
140
+ raise NotImplementedError("Cannot divide elements from different rings.")
141
+ return self.__class__(self.x * pow(other.x, -1, self.ring.n), self.ring)
142
+ return NotImplemented
129
143
 
130
144
  def __rtruediv__(self, scalar: int) -> "ZmodPoint":
131
- return self.__class__(scalar * pow(self.x, -1, self.ring.n), self.ring)
145
+ if isinstance(scalar, int):
146
+ return self.__class__(scalar * pow(self.x, -1, self.ring.n), self.ring)
147
+ return NotImplemented
132
148
 
133
149
  def __pow__(self, scalar: int) -> "ZmodPoint":
134
- return self.__class__(pow(self.x, scalar, self.ring.n), self.ring)
150
+ if isinstance(scalar, int):
151
+ return self.__class__(pow(self.x, scalar, self.ring.n), self.ring)
152
+ return NotImplemented
135
153
 
136
154
  def sharp(self):
137
155
  "Returns a symmetric (w.r.t. 0) representative."
@@ -11,7 +11,7 @@ from .dlp_qs import dlog_qs
11
11
  from .factor import factorint
12
12
 
13
13
 
14
- def dlog_naive(a: int, b: int, n: int, m: int = None) -> int:
14
+ def dlog_naive(a: int, b: int, n: int, m: int = None) -> int|None:
15
15
  """Compute the discrete log_a(b) in Z_n of an element a of order m by exhaustive search."""
16
16
  a %= n
17
17
  b %= n
@@ -43,14 +43,14 @@ def _dlog_ph(a: int, b: int, n: int, q: int, k: int) -> int:
43
43
  for j in range(2, k + 1):
44
44
  aj = pow(a, q ** (k - j), n)
45
45
  bj = pow(b, q ** (k - j), n)
46
- yj = _dlog_switch(a1, bj * pow(aj, -xj, n) % n, n, q)
46
+ yj = _dlog_switch(a1, bj * pow(aj, -xj, n) % n, n, q) # pylint: disable=E1130
47
47
  if yj is None:
48
48
  return None
49
49
  xj = xj + q ** (j - 1) * yj % q**j
50
50
  return xj
51
51
 
52
52
 
53
- def dlog(a: int, b: int, n: int, m: int = None) -> int:
53
+ def dlog(a: int, b: int, n: int, m: int|None = None) -> int:
54
54
  """Compute the discrete log_a(b) in Z_n of an element a of order m using Pohlig-Hellman reduction."""
55
55
  a %= n
56
56
  b %= n
@@ -60,7 +60,8 @@ def dlog(a: int, b: int, n: int, m: int = None) -> int:
60
60
  mf = factorint(m)
61
61
  else:
62
62
  m, mf = order(a, n, True)
63
- assert pow(b, m, n) == 1, "DLP not solvable."
63
+ if pow(b, m, n) != 1:
64
+ raise ValueError("DLP not solvable.")
64
65
  # We first use Pohlig-Hellman to split m into powers of prime factors
65
66
  mm = []
66
67
  ll = []
@@ -227,7 +227,7 @@ def dlog_qs(a: int, b: int, n: int, m: int, pollard: bool = True, sieve_factor:
227
227
  if r == 0:
228
228
  roots = [ -(inv2 * aa) % p ] # one root
229
229
  else:
230
- roots = [ (inv2 * (r - aa)) % p, (inv2 * (-r - aa)) % p ] # two roots
230
+ roots = [ (inv2 * (r - aa)) % p, (inv2 * (-r - aa)) % p ] # two roots pylint: disable=E1130
231
231
  for r in roots:
232
232
  x = r # start value for x
233
233
  while x < max_j:
@@ -255,10 +255,10 @@ def dlog_qs(a: int, b: int, n: int, m: int, pollard: bool = True, sieve_factor:
255
255
  relation = find_relation(include_b)
256
256
  res = process_relation(relation)
257
257
  if res:
258
- return(res)
258
+ return res
259
259
 
260
260
  #
261
- # find the B-smooth numbers and add them to the system
261
+ # find the B-smooth numbers and add them to the system
262
262
  #
263
263
 
264
264
  for s in range(sieve_bound):
@@ -320,7 +320,7 @@ class ECPoint:
320
320
  def __neg__(self) -> "ECPoint":
321
321
  if self.x is None or not self.y:
322
322
  return self
323
- return ECPoint(self.x, -self.y, self.curve)
323
+ return ECPoint(self.x, -self.y, self.curve) # pylint: disable=E1130
324
324
 
325
325
  def order(self) -> int:
326
326
  """Compute the order of an element."""
@@ -84,7 +84,7 @@ def _ecm_parameters(B1: int, B2: int = None, D: int = None, primes: tuple = None
84
84
  return D, stage_one, stage_two_deltas
85
85
 
86
86
 
87
- def factor_ecm(n: int, B1: int = 11000, B2: int = 1900000, curves: int = 74, ecm_parameters: tuple = None):
87
+ def factor_ecm(n: int, B1: int = 11000, B2: int = 1900000, curves: int = 74, ecm_parameters: tuple|None = None):
88
88
  "Factors a number n using Lentsta's ECM method."
89
89
 
90
90
  if ecm_parameters:
@@ -3,6 +3,8 @@ Linear algebra
3
3
  """
4
4
 
5
5
  from math import inf, sqrt, prod
6
+ from numbers import Number
7
+
6
8
 
7
9
  class Matrix:
8
10
  """
@@ -149,12 +151,16 @@ class Matrix:
149
151
  return result
150
152
 
151
153
  def __add__(self, other) -> "Matrix":
152
- if isinstance(other, Matrix) and other.cols == self.cols and other.rows == self.rows:
154
+ if isinstance(other, Matrix):
155
+ if other.cols != self.cols or other.rows != self.rows:
156
+ raise NotImplementedError("Matrix dimensions do not match!")
153
157
  return Matrix([ [ x1 + y1 for x1, y1 in zip(x,y)] for x, y in zip(self.matrix, other.matrix)])
154
158
  return NotImplemented
155
159
 
156
160
  def __sub__(self, other) -> "Matrix":
157
- if isinstance(other, Matrix) and other.cols == self.cols and other.rows == self.rows:
161
+ if isinstance(other, Matrix):
162
+ if other.cols != self.cols or other.rows != self.rows:
163
+ raise NotImplementedError("Matrix dimensions do not match!")
158
164
  return Matrix([ [ x1 - y1 for x1, y1 in zip(x,y)] for x, y in zip(self.matrix, other.matrix)])
159
165
  return NotImplemented
160
166
 
@@ -164,12 +170,14 @@ class Matrix:
164
170
  def __mul__(self, other) -> "Matrix":
165
171
  if isinstance(other, Matrix):
166
172
  return self.multiply(other)
167
- return Matrix([ [item * other for item in row] for row in self.matrix ])
173
+ if isinstance(other, Number) or type(other) == type(self.matrix[0][0]):
174
+ return Matrix([ [item * other for item in row] for row in self.matrix ])
175
+ return NotImplemented
168
176
 
169
177
  def __rmul__(self, other) -> "Matrix":
170
- if isinstance(other, Matrix):
171
- return self.multiply(other)
172
- return Matrix([ [item * other for item in row] for row in self.matrix ])
178
+ if isinstance(other, Number) or type(other) == type(self.matrix[0][0]):
179
+ return Matrix([ [item * other for item in row] for row in self.matrix ])
180
+ return NotImplemented
173
181
 
174
182
  def rref(self) -> "Matrix":
175
183
  "Compute the reduced echelon form of a matrix M."
@@ -104,6 +104,7 @@ def crt(a: list[int], m: list[int]) -> int:
104
104
 
105
105
 
106
106
  def fraction_repr(self):
107
+ "Representation of a fraction."
107
108
  if self.denominator == 1:
108
109
  return str(self.numerator)
109
110
  return str(self.numerator) + "/" + str(self.denominator)
@@ -228,7 +229,7 @@ def order(a: int, n: int, factor=False) -> int:
228
229
  """Compute the order of `a` in the group Z_n^*."""
229
230
  a %= n
230
231
  assert a != 0 and gcd(a, n) == 1, f"{a} and {n} are not coprime!"
231
- factors = dict() # We compute euler_phi(n) and its factorization in one pass
232
+ factors = {} # We compute euler_phi(n) and its factorization in one pass
232
233
  for p, k in factorint(n).items(): # first factorize n
233
234
  for pm, km in factorint(p - 1).items(): # factor p-1 and add the factors
234
235
  if pm in factors:
@@ -255,7 +256,7 @@ def order(a: int, n: int, factor=False) -> int:
255
256
  else:
256
257
  break
257
258
  if factor and i < k:
258
- factors_order[p] = k - i
259
+ factors_order[p] = k - i # pylint: disable=E0606
259
260
  if factor:
260
261
  return order_a, factors_order
261
262
  return order_a
@@ -2,6 +2,8 @@
2
2
  Polynomials
3
3
  """
4
4
 
5
+ from numbers import Number
6
+
5
7
  class Poly:
6
8
  """
7
9
  Represents a polynomial as a list of coefficients.
@@ -94,12 +96,11 @@ class Poly:
94
96
 
95
97
  def __add__(self, other: "Poly") -> "Poly":
96
98
  if not isinstance(other, self.__class__):
97
- try:
98
- tmp = self.coeff[:]
99
+ tmp = self.coeff[:]
100
+ if isinstance(other, int) or type(other) == type(tmp[0]):
99
101
  tmp[0] += other
100
102
  return self.__class__(tmp, modulus=self.modulus)
101
- except:
102
- return NotImplemented
103
+ return NotImplemented
103
104
  ls, lo = len(self.coeff), len(other.coeff)
104
105
  if ls < lo:
105
106
  scoeff = self.coeff + (lo - ls) * [0]
@@ -116,12 +117,10 @@ class Poly:
116
117
 
117
118
  def __radd__(self, other: "Poly") -> "Poly":
118
119
  if not isinstance(other, self.__class__):
119
- try:
120
+ if isinstance(other, Number) or type(other) == type(self.coeff[0]):
120
121
  tmp = self.coeff[:]
121
122
  tmp[0] += other
122
123
  return self.__class__(tmp, modulus=self.modulus)
123
- except:
124
- pass
125
124
  return NotImplemented
126
125
 
127
126
  def __neg__(self) -> "Poly":
@@ -129,12 +128,11 @@ class Poly:
129
128
 
130
129
  def __sub__(self, other: "Poly") -> "Poly":
131
130
  if not isinstance(other, self.__class__):
132
- try:
131
+ if isinstance(other, int) or type(other) == type(self.coeff[0]):
133
132
  tmp = self.coeff[:]
134
133
  tmp[0] -= other
135
134
  return self.__class__(tmp, modulus=self.modulus)
136
- except:
137
- return NotImplemented
135
+ return NotImplemented
138
136
  ls, lo = len(self.coeff), len(other.coeff)
139
137
  if ls < lo:
140
138
  scoeff = self.coeff + (lo - ls) * [0]
@@ -147,24 +145,21 @@ class Poly:
147
145
  modulus = self.modulus
148
146
  if not modulus and other.modulus:
149
147
  modulus = other.modulus
150
- return self.__class__([s - o for s, o in zip(scoeff, ocoeff)], modulus=modulus)
148
+ return self.__class__([s - o for s, o in zip(scoeff, ocoeff)], modulus = modulus)
151
149
 
152
150
  def __rsub__(self, other: "Poly") -> "Poly":
153
151
  if not isinstance(other, self.__class__):
154
- try:
152
+ if isinstance(other, int) or type(other) == type(self.coeff[0]):
155
153
  tmp = self.coeff[:]
156
154
  tmp[0] -= other
157
155
  return self.__class__(tmp, modulus=self.modulus)
158
- except:
159
- pass
160
156
  return NotImplemented
161
157
 
162
158
  def __mul__(self, other: "Poly") -> "Poly":
163
159
  if not isinstance(other, self.__class__):
164
- try:
165
- return Poly([other * s for s in self.coeff])
166
- except:
167
- return NotImplemented
160
+ if isinstance(other, int) or type(other) == type(self.coeff[0]):
161
+ return Poly([other * s for s in self.coeff], modulus = self.modulus)
162
+ return NotImplemented
168
163
  ls, lo = len(self.coeff), len(other.coeff)
169
164
  coeff = [0] * (ls + lo - 1)
170
165
  for k in range(ls + lo - 1):
@@ -177,23 +172,36 @@ class Poly:
177
172
  modulus = self.modulus
178
173
  if not modulus and other.modulus:
179
174
  modulus = other.modulus
180
- return self.__class__(coeff, modulus=modulus)
175
+ return self.__class__(coeff, modulus = modulus)
181
176
 
182
177
  def __rmul__(self, other: int) -> "Poly":
183
- return self.__class__([other * s for s in self.coeff], modulus=self.modulus)
178
+ if isinstance(other, int) or type(other) == type(self.coeff[0]):
179
+ return self.__class__([other * s for s in self.coeff], modulus=self.modulus)
180
+ return NotImplemented
184
181
 
185
182
  def __pow__(self, i: int) -> "Poly":
186
- res = self.__class__([1], modulus=self.modulus)
183
+ if not isinstance(i, int):
184
+ return NotImplemented
185
+ zero = 0 * self.coeff[0]
186
+ one = zero + 1
187
+ res = self.__class__([one], modulus=self.modulus)
187
188
  if i < 0:
188
189
  if not self.modulus:
189
- raise NotImplementedError("Cannot divide.")
190
+ raise NotImplementedError("Cannot divide polynomials without modulus.")
190
191
  tmp = self.inv()
192
+ i *= -1
191
193
  else:
192
194
  tmp = self
193
195
  for _ in range(i):
194
196
  res *= tmp
195
197
  return res
196
198
 
199
+ def __floordiv__(self, other: "Poly") -> "Poly":
200
+ return self.divmod(other)[0]
201
+
202
+ def __mod__(self, other: "Poly") -> "Poly":
203
+ return self.divmod(other)[1]
204
+
197
205
  def divmod(self, other: "Poly") -> ("Poly", "Poly"):
198
206
  "Polynom division with remainder."
199
207
  if isinstance(other, list):
@@ -261,10 +269,10 @@ class Poly:
261
269
  raise NotImplementedError(f"Cannot invert {self} modulo {other}.")
262
270
  if not other:
263
271
  raise NotImplementedError(f"{other} must be nonzero.")
272
+ zero = 0 * self.coeff[0]
273
+ one = zero +1
264
274
  r0, r1 = other, self
265
- y0, y1 = self.__class__([0], modulus=self.modulus), self.__class__(
266
- [1], modulus=self.modulus
267
- )
275
+ y0, y1 = self.__class__([zero], modulus=self.modulus), self.__class__([one], modulus=self.modulus)
268
276
  while r1:
269
277
  q, r = r0.divmod(r1)
270
278
  r0, r1 = r1, r
@@ -272,6 +280,6 @@ class Poly:
272
280
  if r0.degree() != 0:
273
281
  raise ValueError(f"{self} is not invertible mod {other}.")
274
282
  tmp = 1 / r0[0]
275
- for i in range(y0.degree()):
283
+ for i in range(len(y0)):
276
284
  y0.coeff[i] *= tmp
277
285
  return y0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kryptools
3
- Version: 0.4
3
+ Version: 0.5
4
4
  Summary: Implemenation of same basic algorithms used in cryptography.
5
5
  Author-email: Gerald Teschl <gerald.teschl@univie.ac.at>
6
6
  Project-URL: Homepage, https://github.com/teschlg/kryptools
@@ -9,7 +9,7 @@ Project-URL: Docs, https://github.com/teschlg/kryptools/tree/main/doc
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Operating System :: OS Independent
12
- Requires-Python: >=3.8
12
+ Requires-Python: >=3.9
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
15
 
@@ -1,12 +1,12 @@
1
1
  [project]
2
2
  name = "kryptools"
3
- version = "0.4"
3
+ version = "0.5"
4
4
  authors = [
5
5
  { name="Gerald Teschl", email="gerald.teschl@univie.ac.at" },
6
6
  ]
7
7
  description = "Implemenation of same basic algorithms used in cryptography."
8
8
  readme = "README.md"
9
- requires-python = ">=3.8"
9
+ requires-python = ">=3.9"
10
10
  classifiers = [
11
11
  "Programming Language :: Python :: 3",
12
12
  "License :: OSI Approved :: MIT License",
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