kryptools 0.9.8__tar.gz → 0.9.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-0.9.8 → kryptools-0.9.9}/PKG-INFO +1 -1
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/Zmod.py +6 -2
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/__init__.py +1 -1
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/ec.py +5 -1
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/factor.py +1 -1
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/factor_ecm.py +0 -1
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/factor_fmt.py +1 -1
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/factor_pm1.py +1 -1
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/factor_rho.py +0 -1
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/la.py +2 -2
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/nt.py +3 -1
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/primes.py +3 -3
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools.egg-info/PKG-INFO +1 -1
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools.egg-info/SOURCES.txt +10 -1
- {kryptools-0.9.8 → kryptools-0.9.9}/pyproject.toml +1 -1
- kryptools-0.9.9/tests/test_Zmod.py +51 -0
- kryptools-0.9.9/tests/test_dlog.py +18 -0
- kryptools-0.9.9/tests/test_ec.py +25 -0
- kryptools-0.9.9/tests/test_factor.py +18 -0
- kryptools-0.9.9/tests/test_la.py +15 -0
- kryptools-0.9.9/tests/test_lat.py +9 -0
- kryptools-0.9.9/tests/test_nt.py +38 -0
- kryptools-0.9.9/tests/test_poly.py +15 -0
- kryptools-0.9.9/tests/test_primes.py +27 -0
- {kryptools-0.9.8 → kryptools-0.9.9}/LICENSE +0 -0
- {kryptools-0.9.8 → kryptools-0.9.9}/README.md +0 -0
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/dlp.py +0 -0
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/dlp_bsgs.py +0 -0
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/dlp_ic.py +0 -0
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/dlp_qs.py +0 -0
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/dlp_rho.py +0 -0
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/factor_dix.py +0 -0
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/factor_qs.py +0 -0
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/lat.py +0 -0
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools/poly.py +0 -0
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools.egg-info/dependency_links.txt +0 -0
- {kryptools-0.9.8 → kryptools-0.9.9}/kryptools.egg-info/top_level.txt +0 -0
- {kryptools-0.9.8 → kryptools-0.9.9}/setup.cfg +0 -0
|
@@ -30,7 +30,11 @@ class Zmod:
|
|
|
30
30
|
self.group_order = 0
|
|
31
31
|
self.factors = {} # factoring of the group order
|
|
32
32
|
|
|
33
|
-
def __call__(self, x: int):
|
|
33
|
+
def __call__(self, x: int|list|tuple):
|
|
34
|
+
if isinstance(x, list):
|
|
35
|
+
return [ZmodPoint(xx, self) for xx in x]
|
|
36
|
+
elif isinstance(x, tuple):
|
|
37
|
+
return (ZmodPoint(xx, self) for xx in x)
|
|
34
38
|
return ZmodPoint(x, self)
|
|
35
39
|
|
|
36
40
|
def __eq__(self, other):
|
|
@@ -76,7 +80,7 @@ class Zmod:
|
|
|
76
80
|
|
|
77
81
|
def star(self) -> int:
|
|
78
82
|
"""Return a list of all elements of the group Z_n^*."""
|
|
79
|
-
elements = [ 1 ]
|
|
83
|
+
elements = [ self(1) ]
|
|
80
84
|
for a in range(2, self.n):
|
|
81
85
|
if gcd(a, self.n) > 1:
|
|
82
86
|
continue
|
|
@@ -5,7 +5,7 @@ Implemenation of same basic algorithms used in cryptography.
|
|
|
5
5
|
__author__ = "Gerald Teschl"
|
|
6
6
|
__copyright__ = "Copyright 2024, Gerald Teschl"
|
|
7
7
|
__license__ = "MIT License"
|
|
8
|
-
__version__ = "0.9.
|
|
8
|
+
__version__ = "0.9.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, order, crt
|
|
@@ -71,6 +71,10 @@ class EC_Weierstrass():
|
|
|
71
71
|
return False
|
|
72
72
|
|
|
73
73
|
def __contains__(self, P: "ECPoint") -> bool:
|
|
74
|
+
if not isinstance(P, ECPoint) or P.curve != self:
|
|
75
|
+
return False
|
|
76
|
+
if P.x is None and P.y is None:
|
|
77
|
+
return True
|
|
74
78
|
return P.y**2 == P.x**3 + self.a * P.x + self.b
|
|
75
79
|
|
|
76
80
|
def info(self):
|
|
@@ -268,7 +272,7 @@ class ECPoint:
|
|
|
268
272
|
else:
|
|
269
273
|
y = (curve.p - y1) % curve.p
|
|
270
274
|
self.y = curve.gf(y)
|
|
271
|
-
if not
|
|
275
|
+
if self not in curve:
|
|
272
276
|
raise ValueError("Point not on curve!")
|
|
273
277
|
|
|
274
278
|
def __repr__(self):
|
|
@@ -59,7 +59,7 @@ def factor_pm1(n: int, B1: int|None = None, B2: int|None = None, x: int = 2, pm1
|
|
|
59
59
|
y = pow(x, stage_two_deltas[0], n)
|
|
60
60
|
D = (y - 1) % n
|
|
61
61
|
for k, d in enumerate(stage_two_deltas[1:]):
|
|
62
|
-
if not
|
|
62
|
+
if d not in saved:
|
|
63
63
|
saved[d] = pow(x, d, n)
|
|
64
64
|
y = y * saved[d] % n
|
|
65
65
|
D = D * (y - 1) % n
|
|
@@ -187,12 +187,12 @@ class Matrix:
|
|
|
187
187
|
def __mul__(self, other) -> "Matrix":
|
|
188
188
|
if isinstance(other, Matrix):
|
|
189
189
|
return self.multiply(other)
|
|
190
|
-
if isinstance(other, Number) or type(other)
|
|
190
|
+
if isinstance(other, Number) or type(other) is type(self.matrix[0][0]):
|
|
191
191
|
return self.__class__([ [item * other for item in row] for row in self.matrix ])
|
|
192
192
|
return NotImplemented
|
|
193
193
|
|
|
194
194
|
def __rmul__(self, other) -> "Matrix":
|
|
195
|
-
if isinstance(other, Number) or type(other)
|
|
195
|
+
if isinstance(other, Number) or type(other) is type(self.matrix[0][0]):
|
|
196
196
|
return self.__class__([ [item * other for item in row] for row in self.matrix ])
|
|
197
197
|
return NotImplemented
|
|
198
198
|
|
|
@@ -143,6 +143,8 @@ def carmichael_lambda(n: int) -> int:
|
|
|
143
143
|
"""Carmichael's lambda function of `n`."""
|
|
144
144
|
if not isinstance(n, int) or n < 1:
|
|
145
145
|
raise ValueError(f"{n} is not a positive integer")
|
|
146
|
+
if n == 1:
|
|
147
|
+
return 1
|
|
146
148
|
k = factorint(n)
|
|
147
149
|
lam_all = [] # values corresponding to the prime factors
|
|
148
150
|
for p in k:
|
|
@@ -224,7 +226,7 @@ def crt(a: list[int], m: list[int], coprime = True) -> int:
|
|
|
224
226
|
if g == 1: # moduli are coprime, nothing to be done
|
|
225
227
|
continue
|
|
226
228
|
if (a[i] - a[j]) % g:
|
|
227
|
-
|
|
229
|
+
raise ValueError("Congruences not solvable!")
|
|
228
230
|
for p, k in factorint(g).items():
|
|
229
231
|
p = p**k # remove this factor from one of the equations
|
|
230
232
|
if gcd(m[i] // p, p) == 1:
|
|
@@ -72,7 +72,7 @@ def miller_rabin_test(n: int, bases: list[int] | int) -> bool:
|
|
|
72
72
|
if a == 0:
|
|
73
73
|
continue
|
|
74
74
|
b = pow(a, m, n)
|
|
75
|
-
if b
|
|
75
|
+
if b in (1, n - 1):
|
|
76
76
|
continue
|
|
77
77
|
for _ in range(1, k):
|
|
78
78
|
b = pow(b, 2, n)
|
|
@@ -154,7 +154,7 @@ def lucas_test(n: int) -> bool:
|
|
|
154
154
|
return n == 2
|
|
155
155
|
if perfect_square(n) is not None: # the search for D will not succeed in this case
|
|
156
156
|
return False
|
|
157
|
-
|
|
157
|
+
|
|
158
158
|
# write n = k 2^s - 1
|
|
159
159
|
k = (n + 1) // 2
|
|
160
160
|
s = 1
|
|
@@ -163,7 +163,7 @@ def lucas_test(n: int) -> bool:
|
|
|
163
163
|
s += 1
|
|
164
164
|
|
|
165
165
|
# Selfridge method for choosing D
|
|
166
|
-
|
|
166
|
+
|
|
167
167
|
D = 5
|
|
168
168
|
while True:
|
|
169
169
|
g = gcd(abs(D), n)
|
|
@@ -24,4 +24,13 @@ kryptools/primes.py
|
|
|
24
24
|
kryptools.egg-info/PKG-INFO
|
|
25
25
|
kryptools.egg-info/SOURCES.txt
|
|
26
26
|
kryptools.egg-info/dependency_links.txt
|
|
27
|
-
kryptools.egg-info/top_level.txt
|
|
27
|
+
kryptools.egg-info/top_level.txt
|
|
28
|
+
tests/test_Zmod.py
|
|
29
|
+
tests/test_dlog.py
|
|
30
|
+
tests/test_ec.py
|
|
31
|
+
tests/test_factor.py
|
|
32
|
+
tests/test_la.py
|
|
33
|
+
tests/test_lat.py
|
|
34
|
+
tests/test_nt.py
|
|
35
|
+
tests/test_poly.py
|
|
36
|
+
tests/test_primes.py
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from math import gcd
|
|
3
|
+
from kryptools import Zmod
|
|
4
|
+
|
|
5
|
+
def test_Zmod():
|
|
6
|
+
for n in [5, 6]:
|
|
7
|
+
Z_n = Zmod(n)
|
|
8
|
+
for a in range(n):
|
|
9
|
+
aa = Z_n(a)
|
|
10
|
+
bool(aa) == bool(a)
|
|
11
|
+
for i in range(4):
|
|
12
|
+
assert aa ** i == Z_n(pow(a, i, n))
|
|
13
|
+
if i == 0 or gcd(a, n) == 1:
|
|
14
|
+
assert aa ** -i == Z_n(pow(a, -i, n))
|
|
15
|
+
else:
|
|
16
|
+
with pytest.raises(ValueError):
|
|
17
|
+
aa ** -i
|
|
18
|
+
if gcd(a, n) == 1:
|
|
19
|
+
assert aa ** aa.order() == Z_n(1)
|
|
20
|
+
else:
|
|
21
|
+
with pytest.raises(ValueError):
|
|
22
|
+
aa.order()
|
|
23
|
+
for b in range(n):
|
|
24
|
+
bb = Z_n(b)
|
|
25
|
+
assert aa + bb == Z_n(a + b)
|
|
26
|
+
assert aa - bb == Z_n(a - b)
|
|
27
|
+
assert aa * bb == Z_n(a * b)
|
|
28
|
+
if gcd(b, n) == 1:
|
|
29
|
+
assert aa / bb == Z_n( a * pow(b, -1, n) )
|
|
30
|
+
|
|
31
|
+
Z_5 = Zmod(5)
|
|
32
|
+
assert Z_5(3).order() == 4
|
|
33
|
+
assert Z_5(1).is_generator() == False
|
|
34
|
+
assert Z_5(3).is_generator() == True
|
|
35
|
+
assert Z_5.generator(all = True) == Z_5([2, 3])
|
|
36
|
+
assert Z_5.star() == Z_5([1, 2, 3, 4])
|
|
37
|
+
assert [Z_5(i).sharp() for i in range(Z_5.n)] == [0, 1, 2, -2, -1]
|
|
38
|
+
assert [abs(Z_5(i)) for i in range(Z_5.n)] == [0, 1, 2, 2, 1]
|
|
39
|
+
assert str(Z_5(3)) == "3"
|
|
40
|
+
Z_5.short = False
|
|
41
|
+
assert str(Z_5(6)) == "1 (mod 5)"
|
|
42
|
+
|
|
43
|
+
Z_6 = Zmod(6)
|
|
44
|
+
assert Z_6(5).order() == 2
|
|
45
|
+
with pytest.raises(ValueError):
|
|
46
|
+
Z_6(3).order()
|
|
47
|
+
assert Z_6(1).is_generator() == False
|
|
48
|
+
assert Z_6(5).is_generator() == True
|
|
49
|
+
assert Z_6.generator(all = True) == Z_6([5])
|
|
50
|
+
assert Z_6.star() == Z_6([1, 5])
|
|
51
|
+
assert str(Z_6(3)) == "3"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from random import randint, seed
|
|
3
|
+
from kryptools import dlog
|
|
4
|
+
|
|
5
|
+
seed(0)
|
|
6
|
+
|
|
7
|
+
with pytest.raises(ValueError):
|
|
8
|
+
dlog(1, 3, 10)
|
|
9
|
+
|
|
10
|
+
def test_dlogt():
|
|
11
|
+
for data in (
|
|
12
|
+
[557639, 278819, 2],
|
|
13
|
+
[24570203447, 12285101723, 2],
|
|
14
|
+
[28031135240181527, 14015567620090763, 2] ):
|
|
15
|
+
p, m, a = data # m is the order of a in Z_p
|
|
16
|
+
x = randint(2, m - 1)
|
|
17
|
+
b = pow(a, x, p)
|
|
18
|
+
assert dlog(a, b, p) == x
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from random import randint, seed
|
|
3
|
+
from kryptools import EC_Weierstrass
|
|
4
|
+
seed(0)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_EC():
|
|
8
|
+
ec = EC_Weierstrass(239, 3, 1)
|
|
9
|
+
O = ec(None, None) # point at infinity
|
|
10
|
+
assert O in ec
|
|
11
|
+
P = ec.random()
|
|
12
|
+
assert P in ec
|
|
13
|
+
Q = ec.random()
|
|
14
|
+
assert Q in ec
|
|
15
|
+
assert P + O == P
|
|
16
|
+
assert O + P == P
|
|
17
|
+
R = O
|
|
18
|
+
for i in range(5):
|
|
19
|
+
assert i * P == R
|
|
20
|
+
R += P
|
|
21
|
+
assert P + Q == Q + P
|
|
22
|
+
assert Q.order() * Q == O
|
|
23
|
+
k = randint(1, ec.order())
|
|
24
|
+
R = k * Q
|
|
25
|
+
assert R.dlog(Q) == k
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from kryptools import factorint, is_prime
|
|
3
|
+
|
|
4
|
+
def myprod(factors: dict) -> int:
|
|
5
|
+
n = 1
|
|
6
|
+
for p in factors:
|
|
7
|
+
assert is_prime(p)
|
|
8
|
+
n *= p**factors[p]
|
|
9
|
+
return n
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_factorint():
|
|
13
|
+
assert factorint(0) == {0: 1}
|
|
14
|
+
assert factorint(1) == {}
|
|
15
|
+
for n in ( 1489576198567193874913874619387459183543154617315437135656,
|
|
16
|
+
2**128 - 1,
|
|
17
|
+
4521089809**7 ):
|
|
18
|
+
assert n == myprod(factorint(n))
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from fractions import Fraction
|
|
3
|
+
from kryptools import Matrix, Zmod
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_Matrix():
|
|
7
|
+
M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 12]])
|
|
8
|
+
M.map(Fraction)
|
|
9
|
+
Mi = M.inv()
|
|
10
|
+
assert M * Mi == M.eye()
|
|
11
|
+
|
|
12
|
+
Z_11 = Zmod(11)
|
|
13
|
+
M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 12]], ring=Z_11)
|
|
14
|
+
Mi = M.inv()
|
|
15
|
+
assert M * Mi == M.eye()
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from kryptools import carmichael_lambda, euler_phi, moebius_mu
|
|
3
|
+
|
|
4
|
+
#https://oeis.org/A000010
|
|
5
|
+
OEIS_A000010 = [
|
|
6
|
+
1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16, 6, 18, 8, 12, 10, 22, 8, 20,
|
|
7
|
+
12, 18, 12, 28, 8, 30, 16, 20, 16, 24, 12, 36, 18, 24, 16, 40, 12, 42, 20, 24, 22,
|
|
8
|
+
46, 16, 42, 20, 32, 24, 52, 18, 40, 24, 36, 28, 58, 16, 60, 30, 36, 32, 48, 20,
|
|
9
|
+
66, 32, 44 ]
|
|
10
|
+
|
|
11
|
+
def test_euler_phi():
|
|
12
|
+
for n in range(1, len(OEIS_A000010)+1):
|
|
13
|
+
assert euler_phi(n) == OEIS_A000010[n - 1]
|
|
14
|
+
|
|
15
|
+
#https://oeis.org/A002322
|
|
16
|
+
OEIS_A002322 = [
|
|
17
|
+
1, 1, 2, 2, 4, 2, 6, 2, 6, 4, 10, 2, 12, 6, 4, 4, 16, 6, 18, 4, 6, 10, 22, 2, 20,
|
|
18
|
+
12, 18, 6, 28, 4, 30, 8, 10, 16, 12, 6, 36, 18, 12, 4, 40, 6, 42, 10, 12, 22, 46,
|
|
19
|
+
4, 42, 20, 16, 12, 52, 18, 20, 6, 18, 28, 58, 4, 60, 30, 6, 16, 12, 10, 66, 16,
|
|
20
|
+
22, 12, 70, 6, 72, 36, 20, 18, 30, 12, 78, 4, 54 ]
|
|
21
|
+
|
|
22
|
+
def test_carmichael_lambda():
|
|
23
|
+
for n in range(1, len(OEIS_A002322)+1):
|
|
24
|
+
assert carmichael_lambda(n) == OEIS_A002322[n - 1]
|
|
25
|
+
|
|
26
|
+
#https://oeis.org/A008683
|
|
27
|
+
OEIS_A008683 = [
|
|
28
|
+
1, -1, -1, 0, -1, 1, -1, 0, 0, 1, -1, 0, -1, 1, 1, 0, -1, 0, -1, 0, 1, 1, -1, 0,
|
|
29
|
+
0, 1, 0, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, 1, 1, 0, -1, -1, -1, 0, 0, 1, -1, 0, 0,
|
|
30
|
+
0, 1, 0, -1, 0, 1, 0, 1, 1, -1, 0, -1, 1, 0, 0, 1, -1, -1, 0, 1, -1, -1, 0, -1, 1,
|
|
31
|
+
0, 0, 1, -1 ]
|
|
32
|
+
|
|
33
|
+
def test_moebius_mu():
|
|
34
|
+
for n in range(1, len(OEIS_A008683)+1):
|
|
35
|
+
assert moebius_mu(n) == OEIS_A008683[n - 1]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from kryptools import Poly, Zmod
|
|
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
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from kryptools import sieve_eratosthenes, prime_pi, next_prime, previous_prime
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
#https://oeis.org/A000040
|
|
6
|
+
OEIS_A000010 = [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
|
|
7
|
+
71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163,
|
|
8
|
+
167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263,
|
|
9
|
+
269, 271 ]
|
|
10
|
+
|
|
11
|
+
def test_sieve_eratosthenes():
|
|
12
|
+
for i, p in enumerate(sieve_eratosthenes(OEIS_A000010[-1])):
|
|
13
|
+
assert p == OEIS_A000010[i]
|
|
14
|
+
if i > 0:
|
|
15
|
+
assert previous_prime(p-1) == OEIS_A000010[i-1]
|
|
16
|
+
if i < len(OEIS_A000010) - 1:
|
|
17
|
+
assert next_prime(p+1) == OEIS_A000010[i+1]
|
|
18
|
+
|
|
19
|
+
#https://oeis.org/A000040
|
|
20
|
+
OEIS_A000720 = [ 0, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,
|
|
21
|
+
9, 9, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 14, 14, 14, 14,
|
|
22
|
+
15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 17, 17, 18, 18, 18, 18, 18, 18, 19,
|
|
23
|
+
19, 19, 19, 20, 20, 21, 21, 21, 21, 21, 21 ]
|
|
24
|
+
|
|
25
|
+
def test_prime_pi():
|
|
26
|
+
for n in range(1, len(OEIS_A000720)+1):
|
|
27
|
+
assert prime_pi(n) == OEIS_A000720[n - 1]
|
|
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
|