A Python port of the Invisible Internet Project (I2P)
at main 156 lines 6.2 kB view raw
1"""Tests for i2p_crypto EdDSA — Ed25519 signing/verification.""" 2 3import pytest 4 5 6class TestEdDSAEngine: 7 def test_sign_verify_roundtrip(self): 8 from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair 9 kp = EdDSAKeyPair.generate() 10 data = b"Hello, Ed25519!" 11 sig = EdDSAEngine.sign(data, kp.private_key) 12 assert len(sig) == 64 13 assert EdDSAEngine.verify(data, sig, kp.public_key) 14 15 def test_verify_wrong_data(self): 16 from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair 17 kp = EdDSAKeyPair.generate() 18 sig = EdDSAEngine.sign(b"correct", kp.private_key) 19 assert not EdDSAEngine.verify(b"wrong", sig, kp.public_key) 20 21 def test_verify_wrong_key(self): 22 from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair 23 kp1 = EdDSAKeyPair.generate() 24 kp2 = EdDSAKeyPair.generate() 25 sig = EdDSAEngine.sign(b"data", kp1.private_key) 26 assert not EdDSAEngine.verify(b"data", sig, kp2.public_key) 27 28 def test_sign_with_offset_length(self): 29 from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair 30 kp = EdDSAKeyPair.generate() 31 data = b"XXXhelloXXX" 32 sig = EdDSAEngine.sign(data, kp.private_key, offset=3, length=5) 33 assert EdDSAEngine.verify(b"hello", sig, kp.public_key) 34 35 def test_verify_with_offset_length(self): 36 from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair 37 kp = EdDSAKeyPair.generate() 38 sig = EdDSAEngine.sign(b"hello", kp.private_key) 39 data = b"XXXhelloXXX" 40 assert EdDSAEngine.verify(data, sig, kp.public_key, offset=3, length=5) 41 42 def test_deterministic_signatures(self): 43 from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair 44 kp = EdDSAKeyPair.from_private_bytes(bytes(range(32))) 45 sig1 = EdDSAEngine.sign(b"deterministic", kp.private_key) 46 sig2 = EdDSAEngine.sign(b"deterministic", kp.private_key) 47 assert sig1 == sig2 # Ed25519 is deterministic 48 49 def test_empty_message(self): 50 from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair 51 kp = EdDSAKeyPair.generate() 52 sig = EdDSAEngine.sign(b"", kp.private_key) 53 assert EdDSAEngine.verify(b"", sig, kp.public_key) 54 55 def test_large_message(self): 56 from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair 57 kp = EdDSAKeyPair.generate() 58 data = bytes(range(256)) * 100 # 25.6 KB 59 sig = EdDSAEngine.sign(data, kp.private_key) 60 assert EdDSAEngine.verify(data, sig, kp.public_key) 61 62 def test_cross_verify_known_seed(self): 63 """Sign with known seed, verify with derived public key.""" 64 from i2p_crypto.eddsa import EdDSAEngine, public_key_from_private 65 seed = bytes.fromhex( 66 "c5aa8df43f9f837bedb7442f31dcb7b1" 67 "66d38535076f094b85ce3a2e0b4458f7" 68 ) 69 pub = public_key_from_private(seed) 70 msg = b"test cross-verify" 71 sig = EdDSAEngine.sign(msg, seed) 72 assert EdDSAEngine.verify(msg, sig, pub) 73 74 def test_signature_length(self): 75 from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair 76 kp = EdDSAKeyPair.generate() 77 for msg in [b"", b"x", b"y" * 10000]: 78 sig = EdDSAEngine.sign(msg, kp.private_key) 79 assert len(sig) == EdDSAEngine.SIGNATURE_LENGTH 80 81 def test_corrupted_signature_rejected(self): 82 from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair 83 kp = EdDSAKeyPair.generate() 84 sig = bytearray(EdDSAEngine.sign(b"data", kp.private_key)) 85 sig[0] ^= 0xFF 86 assert not EdDSAEngine.verify(b"data", bytes(sig), kp.public_key) 87 88 def test_one_shot_alias(self): 89 from i2p_crypto.eddsa import EdDSAEngine 90 assert EdDSAEngine.sign_one_shot is EdDSAEngine.sign 91 assert EdDSAEngine.verify_one_shot is EdDSAEngine.verify 92 93 94class TestEdDSAKeyPair: 95 def test_generate(self): 96 from i2p_crypto.eddsa import EdDSAKeyPair 97 kp = EdDSAKeyPair.generate() 98 assert len(kp.private_key) == 32 99 assert len(kp.public_key) == 32 100 101 def test_from_private_bytes(self): 102 from i2p_crypto.eddsa import EdDSAKeyPair 103 seed = bytes(range(32)) 104 kp = EdDSAKeyPair.from_private_bytes(seed) 105 assert kp.private_key == seed 106 107 def test_sign_verify_via_keypair(self): 108 from i2p_crypto.eddsa import EdDSAKeyPair 109 kp = EdDSAKeyPair.generate() 110 sig = kp.sign(b"test") 111 assert kp.verify(b"test", sig) 112 assert not kp.verify(b"wrong", sig) 113 114 def test_reproducible_public_key(self): 115 from i2p_crypto.eddsa import EdDSAKeyPair 116 seed = bytes(range(32)) 117 kp1 = EdDSAKeyPair.from_private_bytes(seed) 118 kp2 = EdDSAKeyPair.from_private_bytes(seed) 119 assert kp1.public_key == kp2.public_key 120 121 def test_different_keys_different_public(self): 122 from i2p_crypto.eddsa import EdDSAKeyPair 123 kp1 = EdDSAKeyPair.generate() 124 kp2 = EdDSAKeyPair.generate() 125 assert kp1.public_key != kp2.public_key 126 127 def test_keypair_sign_matches_engine(self): 128 from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair 129 kp = EdDSAKeyPair.from_private_bytes(bytes(range(32))) 130 msg = b"consistency check" 131 sig_kp = kp.sign(msg) 132 sig_engine = EdDSAEngine.sign(msg, kp.private_key) 133 assert sig_kp == sig_engine 134 135 136class TestPublicKeyFromPrivate: 137 def test_derive_public_key(self): 138 from i2p_crypto.eddsa import public_key_from_private, EdDSAKeyPair 139 seed = bytes(range(32)) 140 kp = EdDSAKeyPair.from_private_bytes(seed) 141 derived = public_key_from_private(seed) 142 assert derived == kp.public_key 143 144 def test_deterministic_derivation(self): 145 from i2p_crypto.eddsa import public_key_from_private 146 seed = b"\xab" * 32 147 pub1 = public_key_from_private(seed) 148 pub2 = public_key_from_private(seed) 149 assert pub1 == pub2 150 assert len(pub1) == 32 151 152 def test_different_seeds_different_pubkeys(self): 153 from i2p_crypto.eddsa import public_key_from_private 154 pub1 = public_key_from_private(b"\x00" * 32) 155 pub2 = public_key_from_private(b"\x01" + b"\x00" * 31) 156 assert pub1 != pub2