A Python port of the Invisible Internet Project (I2P)
1"""Tests for i2p_crypto DSA — SigType enum, KeyGenerator, DSAEngine dispatcher."""
2
3import pytest
4
5
6class TestSigType:
7 def test_dsa_sha1_constants(self):
8 from i2p_crypto.dsa import SigType
9 st = SigType.DSA_SHA1
10 assert st.code == 0
11 assert st.pubkey_len == 128
12 assert st.privkey_len == 20
13 assert st.sig_len == 40
14 assert st.hash_algo == "sha1"
15
16 def test_ecdsa_sha256_p256(self):
17 from i2p_crypto.dsa import SigType
18 st = SigType.ECDSA_SHA256_P256
19 assert st.code == 1
20 assert st.pubkey_len == 64
21 assert st.privkey_len == 32
22 assert st.sig_len == 64
23 assert st.hash_algo == "sha256"
24
25 def test_ecdsa_sha384_p384(self):
26 from i2p_crypto.dsa import SigType
27 st = SigType.ECDSA_SHA384_P384
28 assert st.code == 2
29 assert st.pubkey_len == 96
30 assert st.privkey_len == 48
31 assert st.sig_len == 96
32 assert st.hash_algo == "sha384"
33
34 def test_ecdsa_sha512_p521(self):
35 from i2p_crypto.dsa import SigType
36 st = SigType.ECDSA_SHA512_P521
37 assert st.code == 3
38 assert st.pubkey_len == 132
39 assert st.privkey_len == 66
40 assert st.sig_len == 132
41 assert st.hash_algo == "sha512"
42
43 def test_eddsa_sha512_ed25519(self):
44 from i2p_crypto.dsa import SigType
45 st = SigType.EdDSA_SHA512_Ed25519
46 assert st.code == 7
47 assert st.pubkey_len == 32
48 assert st.privkey_len == 32
49 assert st.sig_len == 64
50 assert st.hash_algo == "sha512"
51
52 def test_reddsa_sha512_ed25519(self):
53 from i2p_crypto.dsa import SigType
54 st = SigType.RedDSA_SHA512_Ed25519
55 assert st.code == 11
56 assert st.pubkey_len == 32
57 assert st.privkey_len == 32
58 assert st.sig_len == 64
59
60 def test_by_code(self):
61 from i2p_crypto.dsa import SigType
62 assert SigType.by_code(0) is SigType.DSA_SHA1
63 assert SigType.by_code(7) is SigType.EdDSA_SHA512_Ed25519
64 assert SigType.by_code(999) is None
65
66 def test_all_codes_unique(self):
67 from i2p_crypto.dsa import SigType
68 codes = [st.code for st in SigType]
69 assert len(codes) == len(set(codes))
70
71 def test_default_sig_type(self):
72 from i2p_crypto.dsa import SigType
73 # I2P default is EdDSA_SHA512_Ed25519
74 assert SigType.EdDSA_SHA512_Ed25519.code == 7
75
76
77class TestKeyGenerator:
78 def test_generate_eddsa_keypair(self):
79 from i2p_crypto.dsa import SigType, KeyGenerator
80 pub, priv = KeyGenerator.generate(SigType.EdDSA_SHA512_Ed25519)
81 assert len(pub) == 32
82 assert len(priv) == 32
83
84 def test_generate_ecdsa_p256_keypair(self):
85 from i2p_crypto.dsa import SigType, KeyGenerator
86 pub, priv = KeyGenerator.generate(SigType.ECDSA_SHA256_P256)
87 assert len(pub) == 64
88 assert len(priv) == 32
89
90 def test_generate_ecdsa_p384_keypair(self):
91 from i2p_crypto.dsa import SigType, KeyGenerator
92 pub, priv = KeyGenerator.generate(SigType.ECDSA_SHA384_P384)
93 assert len(pub) == 96
94 assert len(priv) == 48
95
96 def test_generate_ecdsa_p521_keypair(self):
97 from i2p_crypto.dsa import SigType, KeyGenerator
98 pub, priv = KeyGenerator.generate(SigType.ECDSA_SHA512_P521)
99 assert len(pub) == 132
100 assert len(priv) == 66
101
102 def test_generate_unique_keys(self):
103 from i2p_crypto.dsa import SigType, KeyGenerator
104 pub1, _ = KeyGenerator.generate(SigType.EdDSA_SHA512_Ed25519)
105 pub2, _ = KeyGenerator.generate(SigType.EdDSA_SHA512_Ed25519)
106 assert pub1 != pub2
107
108
109class TestDSAEngine:
110 def test_sign_verify_eddsa(self):
111 from i2p_crypto.dsa import SigType, KeyGenerator, DSAEngine
112 pub, priv = KeyGenerator.generate(SigType.EdDSA_SHA512_Ed25519)
113 sig = DSAEngine.sign(b"hello", priv, SigType.EdDSA_SHA512_Ed25519)
114 assert len(sig) == 64
115 assert DSAEngine.verify(b"hello", sig, pub, SigType.EdDSA_SHA512_Ed25519)
116
117 def test_sign_verify_ecdsa_p256(self):
118 from i2p_crypto.dsa import SigType, KeyGenerator, DSAEngine
119 pub, priv = KeyGenerator.generate(SigType.ECDSA_SHA256_P256)
120 sig = DSAEngine.sign(b"test data", priv, SigType.ECDSA_SHA256_P256)
121 assert len(sig) == 64
122 assert DSAEngine.verify(b"test data", sig, pub, SigType.ECDSA_SHA256_P256)
123
124 def test_sign_verify_ecdsa_p384(self):
125 from i2p_crypto.dsa import SigType, KeyGenerator, DSAEngine
126 pub, priv = KeyGenerator.generate(SigType.ECDSA_SHA384_P384)
127 sig = DSAEngine.sign(b"test", priv, SigType.ECDSA_SHA384_P384)
128 assert len(sig) == 96
129 assert DSAEngine.verify(b"test", sig, pub, SigType.ECDSA_SHA384_P384)
130
131 def test_sign_verify_ecdsa_p521(self):
132 from i2p_crypto.dsa import SigType, KeyGenerator, DSAEngine
133 pub, priv = KeyGenerator.generate(SigType.ECDSA_SHA512_P521)
134 sig = DSAEngine.sign(b"test", priv, SigType.ECDSA_SHA512_P521)
135 assert len(sig) == 132
136 assert DSAEngine.verify(b"test", sig, pub, SigType.ECDSA_SHA512_P521)
137
138 def test_verify_wrong_data(self):
139 from i2p_crypto.dsa import SigType, KeyGenerator, DSAEngine
140 pub, priv = KeyGenerator.generate(SigType.EdDSA_SHA512_Ed25519)
141 sig = DSAEngine.sign(b"correct", priv, SigType.EdDSA_SHA512_Ed25519)
142 assert not DSAEngine.verify(b"wrong", sig, pub, SigType.EdDSA_SHA512_Ed25519)
143
144 def test_verify_wrong_key(self):
145 from i2p_crypto.dsa import SigType, KeyGenerator, DSAEngine
146 st = SigType.EdDSA_SHA512_Ed25519
147 _, priv1 = KeyGenerator.generate(st)
148 pub2, _ = KeyGenerator.generate(st)
149 sig = DSAEngine.sign(b"data", priv1, st)
150 assert not DSAEngine.verify(b"data", sig, pub2, st)
151
152 def test_sign_empty_message(self):
153 from i2p_crypto.dsa import SigType, KeyGenerator, DSAEngine
154 pub, priv = KeyGenerator.generate(SigType.EdDSA_SHA512_Ed25519)
155 sig = DSAEngine.sign(b"", priv, SigType.EdDSA_SHA512_Ed25519)
156 assert DSAEngine.verify(b"", sig, pub, SigType.EdDSA_SHA512_Ed25519)
157
158 def test_corrupted_signature_rejected(self):
159 from i2p_crypto.dsa import SigType, KeyGenerator, DSAEngine
160 st = SigType.ECDSA_SHA256_P256
161 pub, priv = KeyGenerator.generate(st)
162 sig = bytearray(DSAEngine.sign(b"data", priv, st))
163 sig[0] ^= 0xFF
164 assert not DSAEngine.verify(b"data", bytes(sig), pub, st)
165
166 def test_cross_type_verify_fails(self):
167 """Signature from one type should not verify under another."""
168 from i2p_crypto.dsa import SigType, KeyGenerator, DSAEngine
169 pub_ed, priv_ed = KeyGenerator.generate(SigType.EdDSA_SHA512_Ed25519)
170 sig = DSAEngine.sign(b"data", priv_ed, SigType.EdDSA_SHA512_Ed25519)
171 pub_ec, _ = KeyGenerator.generate(SigType.ECDSA_SHA256_P256)
172 # Different type, different key — should fail gracefully
173 assert not DSAEngine.verify(b"data", sig, pub_ec, SigType.ECDSA_SHA256_P256)
174
175 def test_large_message(self):
176 from i2p_crypto.dsa import SigType, KeyGenerator, DSAEngine
177 st = SigType.ECDSA_SHA256_P256
178 pub, priv = KeyGenerator.generate(st)
179 data = bytes(range(256)) * 100
180 sig = DSAEngine.sign(data, priv, st)
181 assert DSAEngine.verify(data, sig, pub, st)