Skip to content

Reject non-canonical Ed25519 public keys with y >= p (GH #1348)#1349

Open
Coralesoft wants to merge 1 commit into
weidai11:masterfrom
Coralesoft:fix/issue-1348-ed25519-canonical
Open

Reject non-canonical Ed25519 public keys with y >= p (GH #1348)#1349
Coralesoft wants to merge 1 commit into
weidai11:masterfrom
Coralesoft:fix/issue-1348-ed25519-canonical

Conversation

@Coralesoft
Copy link
Copy Markdown

Fixes #1348.

Problem

ed25519PublicKey::Validate() returns true unconditionally, and the Donna verify path unpacks the encoded public key without rejecting y >= p = 2^255 - 19. This lets multiple byte encodings decode to the same group element, as demonstrated by the PoC in the issue (canonical y = 1 and non-canonical y = p + 1 both verify against the same witness signature).

Fix

  • xed25519.cpp: new IsCanonicalY helper; Validate() calls it and returns false for y >= p.
  • donna_32.cpp, donna_64.cpp: new ed25519_pubkey_is_canonical helper; ge25519_unpack_negative_vartime rejects non-canonical y before point
    recovery.
  • validat9.cpp: regression test covering canonical (y = 1, y = p - 1, accepted) and
    non-canonical (y = p, y = p + 1, y = 2^255 - 1, rejected) using the witness signature from the PoC.

Testing

./cryptest.exe v

Validation passes locally on GCC 14 (Linux) and MinGW-w64 GCC 14 (Windows). ValidateEd25519 shows:

passed    non-canonical public-key rejection

No other tests affected.

Compatibility

  • API unchanged.
  • Keys produced by any compliant Ed25519 implementation are unaffected since a compliant encoder never emits y >= p.
  • Only crafted or malformed keys are newly rejected. A caller relying on Validate() always returning true will now see false
    for such keys.

References

Per RFC 8032 section 5.1.3, the encoded y coordinate of an Ed25519
public key must satisfy y < p = 2^255 - 19. ed25519PublicKey::Validate()
returned true unconditionally, and the Donna verify path unpacked
pubkeys without a canonicality check, so encodings with y = p,
y = p + 1, and similar aliases decoded to the identity point.

Adds an IsCanonicalY helper in xed25519.cpp and a matching
ed25519_pubkey_is_canonical helper in donna_32.cpp and donna_64.cpp.
Validate() and ge25519_unpack_negative_vartime() now reject y >= p
before point recovery. Regression test in validat9.cpp covers
y = 1, y = p - 1 (accepted) and y = p, y = p + 1, y = 2^255 - 1
(rejected) against the witness signature from the issue.
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.

Ed25519 verification accepts non-canonical public keys with `y >= p

1 participant