"""Tests for EdDSA blinding primitives.""" import pytest from i2p_crypto.eddsa_blinding import EdDSABlinding, HAS_NACL pytestmark = pytest.mark.skipif(not HAS_NACL, reason="pynacl not installed") def test_reduce_returns_32_bytes(): data_64 = b"\x01" * 64 result = EdDSABlinding.reduce(data_64) assert isinstance(result, bytes) assert len(result) == 32 def test_scalar_mult_base_returns_32_bytes(): # Use a known clamped scalar scalar = EdDSABlinding.seed_to_scalar(b"\xaa" * 32) pub = EdDSABlinding.scalar_mult_base(scalar) assert isinstance(pub, bytes) assert len(pub) == 32 def test_scalar_mult_base_deterministic(): scalar = EdDSABlinding.seed_to_scalar(b"\xbb" * 32) pub1 = EdDSABlinding.scalar_mult_base(scalar) pub2 = EdDSABlinding.scalar_mult_base(scalar) assert pub1 == pub2 def test_blind_private_roundtrip_with_public(): """blind(priv, alpha) * G == blind(pub, alpha * G).""" seed_a = b"\x11" * 32 seed_alpha = b"\x22" * 32 scalar_a = EdDSABlinding.seed_to_scalar(seed_a) scalar_alpha = EdDSABlinding.seed_to_scalar(seed_alpha) # Method 1: blind private, then derive public blinded_priv = EdDSABlinding.blind_private(scalar_a, scalar_alpha) pub_from_priv = EdDSABlinding.scalar_mult_base(blinded_priv) # Method 2: derive publics, then blind (add points) pub_a = EdDSABlinding.scalar_mult_base(scalar_a) pub_alpha = EdDSABlinding.scalar_mult_base(scalar_alpha) pub_from_pub = EdDSABlinding.blind_public(pub_a, pub_alpha) assert pub_from_priv == pub_from_pub def test_seed_to_scalar_clamping(): """Verify the scalar is properly clamped per RFC 8032.""" scalar = EdDSABlinding.seed_to_scalar(b"\xff" * 32) assert scalar[0] & 0x07 == 0 # bottom 3 bits cleared assert scalar[31] & 0x80 == 0 # top bit cleared assert scalar[31] & 0x40 == 0x40 # second-to-top bit set