Skip to content

Clamp X25519 private scalars loaded via from_private_bytes - #92

Open
bergie wants to merge 1 commit into
attermann:masterfrom
bergie:fix/clamp-seeded-x25519-scalars
Open

bergie wants to merge 1 commit into
attermann:masterfrom
bergie:fix/clamp-seeded-x25519-scalars

Conversation

@bergie

@bergie bergie commented Sep 28, 2026

Copy link
Copy Markdown

The raw Curve25519::eval ladder leaves RFC 7748 scalar clamping to the caller (as Curve25519::dh1 does for generated keys), but the Python reference implementation clamps inside X25519. Identities derived from seed material that is not already clamped — for example deterministic rfed channel identities that use SHA-256(name) directly as the private scalar — therefore produced public keys and Diffie-Hellman shared secrets that disagreed with Python RNS, breaking encryption against Python peers.

Clamp the scalar in from_private_bytes. Clamping is idempotent, so generated keys and keys loaded from files written by Python RNS (whose stored scalars are already clamped) are unaffected.

Adds a test_crypto interop vector generated by the Python reference pinning public-key derivation, the shared secret, and the Identity::load_private_key path for a seeded identity.

The raw Curve25519::eval ladder leaves RFC 7748 scalar clamping to the
caller (as Curve25519::dh1 does for generated keys), but the Python
reference implementation clamps inside X25519. Identities derived from
seed material that is not already clamped — for example deterministic
rfed channel identities that use SHA-256(name) directly as the private
scalar — therefore produced public keys and Diffie-Hellman shared
secrets that disagreed with Python RNS, breaking encryption against
Python peers.

Clamp the scalar in from_private_bytes. Clamping is idempotent, so
generated keys and keys loaded from files written by Python RNS (whose
stored scalars are already clamped) are unaffected.

Adds a test_crypto interop vector generated by the Python reference
pinning public-key derivation, the shared secret, and the
Identity::load_private_key path for a seeded identity.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant