"""Tests for i2p_crypto EdDSA — Ed25519 signing/verification.""" import pytest class TestEdDSAEngine: def test_sign_verify_roundtrip(self): from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair kp = EdDSAKeyPair.generate() data = b"Hello, Ed25519!" sig = EdDSAEngine.sign(data, kp.private_key) assert len(sig) == 64 assert EdDSAEngine.verify(data, sig, kp.public_key) def test_verify_wrong_data(self): from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair kp = EdDSAKeyPair.generate() sig = EdDSAEngine.sign(b"correct", kp.private_key) assert not EdDSAEngine.verify(b"wrong", sig, kp.public_key) def test_verify_wrong_key(self): from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair kp1 = EdDSAKeyPair.generate() kp2 = EdDSAKeyPair.generate() sig = EdDSAEngine.sign(b"data", kp1.private_key) assert not EdDSAEngine.verify(b"data", sig, kp2.public_key) def test_sign_with_offset_length(self): from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair kp = EdDSAKeyPair.generate() data = b"XXXhelloXXX" sig = EdDSAEngine.sign(data, kp.private_key, offset=3, length=5) assert EdDSAEngine.verify(b"hello", sig, kp.public_key) def test_verify_with_offset_length(self): from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair kp = EdDSAKeyPair.generate() sig = EdDSAEngine.sign(b"hello", kp.private_key) data = b"XXXhelloXXX" assert EdDSAEngine.verify(data, sig, kp.public_key, offset=3, length=5) def test_deterministic_signatures(self): from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair kp = EdDSAKeyPair.from_private_bytes(bytes(range(32))) sig1 = EdDSAEngine.sign(b"deterministic", kp.private_key) sig2 = EdDSAEngine.sign(b"deterministic", kp.private_key) assert sig1 == sig2 # Ed25519 is deterministic def test_empty_message(self): from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair kp = EdDSAKeyPair.generate() sig = EdDSAEngine.sign(b"", kp.private_key) assert EdDSAEngine.verify(b"", sig, kp.public_key) def test_large_message(self): from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair kp = EdDSAKeyPair.generate() data = bytes(range(256)) * 100 # 25.6 KB sig = EdDSAEngine.sign(data, kp.private_key) assert EdDSAEngine.verify(data, sig, kp.public_key) def test_cross_verify_known_seed(self): """Sign with known seed, verify with derived public key.""" from i2p_crypto.eddsa import EdDSAEngine, public_key_from_private seed = bytes.fromhex( "c5aa8df43f9f837bedb7442f31dcb7b1" "66d38535076f094b85ce3a2e0b4458f7" ) pub = public_key_from_private(seed) msg = b"test cross-verify" sig = EdDSAEngine.sign(msg, seed) assert EdDSAEngine.verify(msg, sig, pub) def test_signature_length(self): from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair kp = EdDSAKeyPair.generate() for msg in [b"", b"x", b"y" * 10000]: sig = EdDSAEngine.sign(msg, kp.private_key) assert len(sig) == EdDSAEngine.SIGNATURE_LENGTH def test_corrupted_signature_rejected(self): from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair kp = EdDSAKeyPair.generate() sig = bytearray(EdDSAEngine.sign(b"data", kp.private_key)) sig[0] ^= 0xFF assert not EdDSAEngine.verify(b"data", bytes(sig), kp.public_key) def test_one_shot_alias(self): from i2p_crypto.eddsa import EdDSAEngine assert EdDSAEngine.sign_one_shot is EdDSAEngine.sign assert EdDSAEngine.verify_one_shot is EdDSAEngine.verify class TestEdDSAKeyPair: def test_generate(self): from i2p_crypto.eddsa import EdDSAKeyPair kp = EdDSAKeyPair.generate() assert len(kp.private_key) == 32 assert len(kp.public_key) == 32 def test_from_private_bytes(self): from i2p_crypto.eddsa import EdDSAKeyPair seed = bytes(range(32)) kp = EdDSAKeyPair.from_private_bytes(seed) assert kp.private_key == seed def test_sign_verify_via_keypair(self): from i2p_crypto.eddsa import EdDSAKeyPair kp = EdDSAKeyPair.generate() sig = kp.sign(b"test") assert kp.verify(b"test", sig) assert not kp.verify(b"wrong", sig) def test_reproducible_public_key(self): from i2p_crypto.eddsa import EdDSAKeyPair seed = bytes(range(32)) kp1 = EdDSAKeyPair.from_private_bytes(seed) kp2 = EdDSAKeyPair.from_private_bytes(seed) assert kp1.public_key == kp2.public_key def test_different_keys_different_public(self): from i2p_crypto.eddsa import EdDSAKeyPair kp1 = EdDSAKeyPair.generate() kp2 = EdDSAKeyPair.generate() assert kp1.public_key != kp2.public_key def test_keypair_sign_matches_engine(self): from i2p_crypto.eddsa import EdDSAEngine, EdDSAKeyPair kp = EdDSAKeyPair.from_private_bytes(bytes(range(32))) msg = b"consistency check" sig_kp = kp.sign(msg) sig_engine = EdDSAEngine.sign(msg, kp.private_key) assert sig_kp == sig_engine class TestPublicKeyFromPrivate: def test_derive_public_key(self): from i2p_crypto.eddsa import public_key_from_private, EdDSAKeyPair seed = bytes(range(32)) kp = EdDSAKeyPair.from_private_bytes(seed) derived = public_key_from_private(seed) assert derived == kp.public_key def test_deterministic_derivation(self): from i2p_crypto.eddsa import public_key_from_private seed = b"\xab" * 32 pub1 = public_key_from_private(seed) pub2 = public_key_from_private(seed) assert pub1 == pub2 assert len(pub1) == 32 def test_different_seeds_different_pubkeys(self): from i2p_crypto.eddsa import public_key_from_private pub1 = public_key_from_private(b"\x00" * 32) pub2 = public_key_from_private(b"\x01" + b"\x00" * 31) assert pub1 != pub2