Skip to content

delegation-chain-ref: verify Ed25519 hardening against known edge cases (preventive, no vulnerability) - #138

Merged
giskard09 merged 1 commit into
mainfrom
security/delegation-chain-ref-ed25519-hardening
Oct 18, 2026
Merged

giskard09 merged 1 commit into
mainfrom
security/delegation-chain-ref-ed25519-hardening

Conversation

@giskard09

Copy link
Copy Markdown
Owner

Summary

Preventive self-audit, no external trigger against this repo. The same day, unrelated to us, robertolocatelli81-dev/Noûs found (x402-foundation/tsc#4) that identity-element Ed25519 keys (R=identity, S=0) forge a signature valid for any message under naive RFC 8032 verification, and that some libraries accept non-canonically-encoded points/scalars (novifinancial/ed25519-speccheck classes 0 and 11).

hop_signature in delegation-chain-ref-v1 is this repo's only live Ed25519 check — everywhere else (peer-reconciliation-ref-v1's co_signer, anchoring-precedence-ref-v1's admission_invariant) signature validity is a declared, externally-resolved fact, not computed by our own code. This was the one place a weak crypto library would actually matter, and it had never been checked explicitly — "PyNaCl/libsodium is strict" was an assumption, not a verified fact in this repo.

Result: no vulnerability found

Reproduced, not assumed:

  1. small-order-key-vectors.json (small-order-identity-key-universal-forgery-001): constructs the real attack inside a real 2-hop chain, through this spec's own hop_signing_preimage() — hop 1's delegator key is the identity element and hop_signature is the textbook universal-forgery signature (verifies for any message under the naive equation). Correctly hop_signature_invalid, confirmed through this repo's own verify_hop_signature() code path, not an isolated crypto-library unit test. verify.py's main() now runs this file too — 16/16 across the whole suite.

  2. ed25519-hardening/: the full published novifinancial/ed25519-speccheck suite (Apache-2.0, 12 vectors, vendored verbatim at commit 65519336fda78a3d016e947df6d82848aca0c9da, byte-verified via git hash-object against the GitHub blob — see NOTICE.md) run against this repo's pinned PyNaCl (requirements.txt). 12/12 match the published LibSodium column exactly: small-order A/R (classes 0–2), out-of-range S (6–7), and non-canonical point encodings for both R and A (8–11 — the two classes Noûs named) are all rejected; only the one benign mixed-order edge case every major library accepts (class 3) passes.

Documentation

Added explicitly to docs/spec/delegation-chain-ref.md as a verified guarantee of the pinned dependency, not of this spec's own logic — a future PyNaCl/libsodium upgrade, or a reimplementation with a different Ed25519 library, is not guaranteed to inherit it. check_hardening.py exists to be rerun after any such change, not only once.

Reproduce

python3 examples/conformance/delegation-chain-ref/verify.py
python3 examples/conformance/delegation-chain-ref/ed25519-hardening/check_hardening.py

(needs pip install -r examples/conformance/delegation-chain-ref/requirements.txt)

Test plan

  • verify.py → 16/16 (12 pre-existing + 4 from other files, now + the new small-order vector)
  • check_hardening.py → 12/12, matches published LibSodium behavior exactly
  • small-order-key-vectors.json's hop 0 (legitimate signer) independently confirmed valid on its own, confirming the vector's non-attack half is sound
  • Vendored cases.json verified byte-identical to the source commit via git hash-object

…es (preventive, no vulnerability found)

Preventive self-audit, no external trigger against this repo. Same day,
unrelated to us, robertolocatelli81-dev/Noûs found that identity-element
Ed25519 keys (R=identity, S=0) forge a signature valid for any message
under naive RFC 8032 verification, and that some libraries accept
non-canonically-encoded points/scalars (x402-foundation/tsc#4,
novifinancial/ed25519-speccheck classes 0 and 11).

hop_signature in delegation-chain-ref-v1 is this repo's only LIVE Ed25519
check -- everywhere else (peer-reconciliation-ref-v1's co_signer,
anchoring-precedence-ref-v1's admission_invariant) signature validity is
a declared, externally-resolved fact, not computed by our own code. This
was the one place a weak library would actually matter, and it had never
been checked explicitly -- PyNaCl/libsodium being strict was assumed, not
verified.

Result: no vulnerability. Reproduced, not assumed:

- examples/conformance/delegation-chain-ref/small-order-key-vectors.json
  (small-order-identity-key-universal-forgery-001): a real 2-hop chain
  through this spec's own hop_signing_preimage(), where hop 1's delegator
  key IS the identity element and hop_signature IS the textbook
  universal-forgery signature. Correctly hop_signature_invalid --
  confirmed through the repo's own verify_hop_signature(), not an
  isolated library unit test. verify.py's main() now runs this file too
  (16/16 total across the whole delegation-chain-ref suite).

- examples/conformance/delegation-chain-ref/ed25519-hardening/: the full
  published novifinancial/ed25519-speccheck suite (Apache-2.0, 12
  vectors, vendored verbatim at commit 65519336fda78a3d016e947df6d82848
  aca0c9da, byte-verified via git hash-object against the GitHub blob)
  run against this repo's pinned PyNaCl (requirements.txt). 12/12 match
  the published LibSodium column exactly: small-order A/R (classes 0-2),
  out-of-range S (6-7), and non-canonical point encodings for both R and
  A (8-11, the two classes Noûs named) are all rejected; only the one
  benign mixed-order edge case every major library accepts (class 3)
  passes.

Documented explicitly in docs/spec/delegation-chain-ref.md as a verified
guarantee of the pinned dependency, not of this spec's own logic -- a
future PyNaCl/libsodium upgrade or a reimplementation with a different
Ed25519 library is not guaranteed to inherit it. check_hardening.py
exists to be rerun after any such change.

Reproduce:
  python3 examples/conformance/delegation-chain-ref/verify.py
  python3 examples/conformance/delegation-chain-ref/ed25519-hardening/check_hardening.py

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@giskard09
giskard09 merged commit 0d53350 into main Oct 18, 2026
4 checks passed
@giskard09
giskard09 deleted the security/delegation-chain-ref-ed25519-hardening branch October 18, 2026 15:17
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