A Python port of the Invisible Internet Project (I2P)
at main 57 lines 1.9 kB view raw
1"""Tests for EdDSA blinding primitives.""" 2 3import pytest 4 5from i2p_crypto.eddsa_blinding import EdDSABlinding, HAS_NACL 6 7pytestmark = pytest.mark.skipif(not HAS_NACL, reason="pynacl not installed") 8 9 10def test_reduce_returns_32_bytes(): 11 data_64 = b"\x01" * 64 12 result = EdDSABlinding.reduce(data_64) 13 assert isinstance(result, bytes) 14 assert len(result) == 32 15 16 17def test_scalar_mult_base_returns_32_bytes(): 18 # Use a known clamped scalar 19 scalar = EdDSABlinding.seed_to_scalar(b"\xaa" * 32) 20 pub = EdDSABlinding.scalar_mult_base(scalar) 21 assert isinstance(pub, bytes) 22 assert len(pub) == 32 23 24 25def test_scalar_mult_base_deterministic(): 26 scalar = EdDSABlinding.seed_to_scalar(b"\xbb" * 32) 27 pub1 = EdDSABlinding.scalar_mult_base(scalar) 28 pub2 = EdDSABlinding.scalar_mult_base(scalar) 29 assert pub1 == pub2 30 31 32def test_blind_private_roundtrip_with_public(): 33 """blind(priv, alpha) * G == blind(pub, alpha * G).""" 34 seed_a = b"\x11" * 32 35 seed_alpha = b"\x22" * 32 36 37 scalar_a = EdDSABlinding.seed_to_scalar(seed_a) 38 scalar_alpha = EdDSABlinding.seed_to_scalar(seed_alpha) 39 40 # Method 1: blind private, then derive public 41 blinded_priv = EdDSABlinding.blind_private(scalar_a, scalar_alpha) 42 pub_from_priv = EdDSABlinding.scalar_mult_base(blinded_priv) 43 44 # Method 2: derive publics, then blind (add points) 45 pub_a = EdDSABlinding.scalar_mult_base(scalar_a) 46 pub_alpha = EdDSABlinding.scalar_mult_base(scalar_alpha) 47 pub_from_pub = EdDSABlinding.blind_public(pub_a, pub_alpha) 48 49 assert pub_from_priv == pub_from_pub 50 51 52def test_seed_to_scalar_clamping(): 53 """Verify the scalar is properly clamped per RFC 8032.""" 54 scalar = EdDSABlinding.seed_to_scalar(b"\xff" * 32) 55 assert scalar[0] & 0x07 == 0 # bottom 3 bits cleared 56 assert scalar[31] & 0x80 == 0 # top bit cleared 57 assert scalar[31] & 0x40 == 0x40 # second-to-top bit set