Skip to content

Commit 1a54acd

Browse files
authored
Merge pull request libp2p#1134 from GautamBytes/fix/issue-ed25519-interop
Fix Ed25519 key generation interoperability
2 parents d1c5759 + 5ea51e9 commit 1a54acd

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

libp2p/crypto/ed25519.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
the PyNaCl library. Ed25519 is used for libp2p peer identity signatures.
66
"""
77

8+
from nacl.bindings import crypto_core_ed25519_is_valid_point
89
from nacl.exceptions import (
910
BadSignatureError,
1011
)
@@ -66,8 +67,25 @@ def __init__(self, impl: PrivateKeyImpl) -> None:
6667
def new(cls, seed: bytes | None = None) -> "Ed25519PrivateKey":
6768
if seed:
6869
private_key_impl = PrivateKeyImpl(seed)
70+
if not crypto_core_ed25519_is_valid_point(
71+
bytes(private_key_impl.verify_key)
72+
):
73+
raise ValueError(
74+
"Provided seed generates a public key that is not a "
75+
"valid Ed25519 curve point."
76+
)
6977
else:
70-
private_key_impl = PrivateKeyImpl.generate()
78+
for _ in range(100):
79+
private_key_impl = PrivateKeyImpl.generate()
80+
if crypto_core_ed25519_is_valid_point(
81+
bytes(private_key_impl.verify_key)
82+
):
83+
break
84+
else:
85+
raise RuntimeError(
86+
"Failed to generate a valid Ed25519 key after 100 attempts."
87+
)
88+
7189
return cls(private_key_impl)
7290

7391
def to_bytes(self) -> bytes:

newsfragments/921.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed interoperability issue where generated Ed25519 keys were not always valid curve points, complying with strict ZIP-215 validation.

tests/core/crypto/test_ed25519_comprehensive.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""
77

88
import pytest
9+
from nacl.bindings import crypto_core_ed25519_is_valid_point
910

1011
from libp2p.crypto.ed25519 import (
1112
Ed25519PrivateKey,
@@ -266,3 +267,29 @@ def test_public_key_equality(self):
266267

267268
# Note: Ed25519PublicKey is not hashable, so we can't test set operations
268269
# This is expected behavior for cryptographic key objects
270+
271+
def test_generated_keys_are_valid_curve_points(self):
272+
"""
273+
Test that keys generated by Ed25519PrivateKey.new() are always
274+
valid curve points. This prevents interoperability issues with
275+
strict implementations (e.g. Rust).
276+
"""
277+
# 1. Test Random Generation (50 iterations for probabilistic check)
278+
for _ in range(50):
279+
key_pair = create_new_key_pair()
280+
is_valid = crypto_core_ed25519_is_valid_point(
281+
key_pair.public_key.to_bytes()
282+
)
283+
assert is_valid is True, "Generated public key is not a valid curve point"
284+
285+
# 2. Test Seeded Generation with various patterns
286+
seeds = [
287+
b"a" * 32,
288+
b"b" * 32,
289+
b"\x00" * 32,
290+
b"\xff" * 32,
291+
bytes(range(32)),
292+
]
293+
for seed in seeds:
294+
key = Ed25519PrivateKey.new(seed)
295+
assert crypto_core_ed25519_is_valid_point(key.get_public_key().to_bytes())

0 commit comments

Comments
 (0)