Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
duyuefeng0708
GitHub Repository: duyuefeng0708/Cryptography-From-First-Principle
Path: blob/main/shared/tests/test_number_theory.py
483 views
unlisted
1
"""Tests for cryptolab.number_theory."""
2
3
import sys, os
4
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
5
6
from cryptolab.number_theory import (
7
gcd, extended_gcd, euler_phi, factor, divisors, is_prime,
8
power_mod, inverse_mod, primitive_root, crt, discrete_log,
9
)
10
import pytest
11
12
13
# --- gcd ---
14
15
def test_gcd_basic():
16
assert gcd(12, 8) == 4
17
assert gcd(17, 13) == 1
18
assert gcd(0, 5) == 5
19
assert gcd(5, 0) == 5
20
assert gcd(0, 0) == 0
21
22
def test_gcd_negative():
23
assert gcd(-12, 8) == 4
24
assert gcd(12, -8) == 4
25
26
27
# --- extended_gcd ---
28
29
def test_extended_gcd():
30
g, s, t = extended_gcd(35, 15)
31
assert g == 5
32
assert 35 * s + 15 * t == g
33
34
def test_extended_gcd_coprime():
35
g, s, t = extended_gcd(7, 11)
36
assert g == 1
37
assert 7 * s + 11 * t == 1
38
39
40
# --- factor ---
41
42
def test_factor():
43
assert factor(60) == {2: 2, 3: 1, 5: 1}
44
assert factor(1) == {}
45
assert factor(17) == {17: 1}
46
assert factor(2**10) == {2: 10}
47
48
def test_factor_zero():
49
assert factor(0) == {}
50
51
52
# --- divisors ---
53
54
def test_divisors():
55
assert divisors(12) == [1, 2, 3, 4, 6, 12]
56
assert divisors(1) == [1]
57
assert divisors(17) == [1, 17]
58
assert divisors(0) == []
59
60
61
# --- is_prime ---
62
63
def test_is_prime():
64
assert is_prime(2) is True
65
assert is_prime(3) is True
66
assert is_prime(4) is False
67
assert is_prime(17) is True
68
assert is_prime(1) is False
69
assert is_prime(0) is False
70
assert is_prime(97) is True
71
assert is_prime(100) is False
72
73
74
# --- euler_phi ---
75
76
def test_euler_phi():
77
assert euler_phi(1) == 1
78
assert euler_phi(7) == 6
79
assert euler_phi(12) == 4
80
assert euler_phi(30) == 8
81
# phi(p) = p - 1 for prime p
82
assert euler_phi(97) == 96
83
84
85
# --- power_mod ---
86
87
def test_power_mod():
88
assert power_mod(2, 10, 1000) == 1024 % 1000
89
assert power_mod(3, 0, 7) == 1
90
assert power_mod(5, 1, 13) == 5
91
assert power_mod(2, 10, 1) == 0
92
93
def test_power_mod_negative_exp():
94
# 3^(-1) mod 7 = 5 (since 3*5 = 15 = 1 mod 7)
95
assert power_mod(3, -1, 7) == 5
96
97
98
# --- inverse_mod ---
99
100
def test_inverse_mod():
101
assert inverse_mod(3, 7) == 5 # 3*5 = 15 = 1 mod 7
102
assert inverse_mod(2, 11) == 6 # 2*6 = 12 = 1 mod 11
103
104
def test_inverse_mod_no_inverse():
105
with pytest.raises(ValueError):
106
inverse_mod(2, 4)
107
108
109
# --- primitive_root ---
110
111
def test_primitive_root():
112
g = primitive_root(7)
113
assert g == 3 # 3 is the smallest primitive root mod 7
114
# Verify it has order 6
115
assert power_mod(g, 6, 7) == 1
116
for k in range(1, 6):
117
assert power_mod(g, k, 7) != 1
118
119
def test_primitive_root_small():
120
assert primitive_root(2) == 1
121
assert primitive_root(5) == 2
122
123
124
# --- crt ---
125
126
def test_crt():
127
# x = 2 mod 3, x = 3 mod 5 -> x = 8 mod 15
128
assert crt([2, 3], [3, 5]) == 8
129
130
def test_crt_three_moduli():
131
# x = 1 mod 2, x = 2 mod 3, x = 3 mod 5 -> x = 23 mod 30
132
assert crt([1, 2, 3], [2, 3, 5]) == 23
133
134
135
# --- discrete_log ---
136
137
def test_discrete_log():
138
# 3^x = 6 mod 7
139
# 3^1=3, 3^2=2, 3^3=6 -> x=3
140
assert discrete_log(6, 3, 7) == 3
141
142
def test_discrete_log_identity():
143
# g^0 = 1
144
assert discrete_log(1, 3, 7) == 0
145
146