EdDSA / Ed25519 — countermeasures
- Spec:
RFC 8032 [JL17]
- Crate path:
arcana::ecc::eddsa- Cargo feature:
none — Ed25519 is unconditionally compiled. Ed448 is planned but not yet implemented (RFC 8032 Appendix A port pending).
EdDSA is structurally more SCA-friendly than ECDSA — the nonce is HMAC-derived from the secret, the scalar is well-formed by construction (no rejection sampling), and the scalar multiplication is on a Twisted-Edwards curve where the unified addition formulas avoid the special cases of Weierstrass addition. In return, EdDSA’s deterministic nature ([JL17]) makes it the textbook target of single-fault key-recovery attacks ([RP17]).
Coverage matrix
Threat |
Status |
Countermeasure(s) |
|---|---|---|
SPA on Ed25519 scalar mul |
partial — audit pending |
The Ed25519 scalar multiplication path in
|
DPA on scalar mul |
vulnerable |
Plan |
Single-fault on deterministic Ed25519 |
vulnerable |
Plan |
Template attacks on Ed25519 ([SBB+18]) |
vulnerable |
Plan |
Power analysis on intermediate hash digest
(the SHA-512 of |
partial |
Plan |
Background — Ed25519 signing flow
Ed25519 derives the per-signature nonce r deterministically:
where a is the secret scalar derived from the seed (= the
truncated, clamped form of the upper half of H(seed)), A =
a · B is the public key, and B is the Edwards generator.
The single-fault attack (Romailler-Pelissier [RP17]):
Sign
Monce normally →(R, s).Inject a fault during the second signing of
Msorchanges: e.g. glitch one byte of the SHA-512 state →r' ≠ r.The fault produces
(R', s')withr ≠ r'but the same challengek(sincek = H(R || A || M)andRchanged too — but this is what the attacker observes).
Actually the standard formulation: glitch one of the two
signatures so it’s effectively non-deterministic. From two
non-equal r for the same message, the attacker recovers
a = (s - s') / (k - k') mod ℓ (modulo factor adjustments).
One fault → key recovery.
Single-fault → key recovery (T1-D)
The countermeasure is the same as the ECDSA side: hedged signing. The CFRG draft [MTR24] already specifies the EdDSA variant.
Implementation hooks:
New
ed25519_sign_hedged(sk, msg, rng) -> SignatureAPI.Internally:
\[r = H(\mathrm{prefix} \;\|\; \rho \;\|\; M) \bmod \ell\]where
ρis 32 bytes of fresh randomness; everything else unchanged.Pure-Ed25519 deterministic stays available for KAT compatibility (RFC 8032 §7.1 vectors must keep verifying bit-for-bit).
Tests: KAT regression for the deterministic path; randomized round-trip for the hedged path; fault unit test asserting two
ed25519_sign_hedgedcalls on the same message yield differentR-components.
This item is the same as the ECDSA-side T1-D; the two share
the rng plumbing and the API design.
SPA / DPA on the Edwards scalar multiplication (T1-F, T2-A)
Audit gap
The Ed25519 scalar multiplication code in
arcana::ecc::eddsa::scalar_mul_* was written before the
Weierstrass-side hardening (commit 76191c1) and has not been
re-audited under the same lens. Specific items to check:
Branch-free ladder: confirm the loop body uses
ct_swapbetween two accumulator points, not a window method that conditionally selects from a precomputed table.No early exit on Z = 0: the Edwards twisted formula \((X : Y : Z : T)\) (extended coordinates) does not have the “point at infinity” issue of Weierstrass — the neutral element
(0, 1, 1, 0)is just a normal point. So this particular issue does not arise; confirm anyway.Constant-time clamping: the secret scalar is clamped per RFC 7748 (clear bits 0/1/2/255, set bit 254). The clamping itself uses bitwise ops, no branches; confirm.
``black_box`` shielding on the Curve25519 field
reduce_p— same pattern as the Weierstrass side.
Item T1-F: full audit pass mirroring what was done for
Weierstrass in 76191c1. Estimated effort: 2 days.
Z-coordinate randomization
Edwards curves admit the same Z-rerandomization technique as Weierstrass:
Implementation route is identical to ecdsa_ecdh.rst T2-A:
draw λ from an internal SCA-RNG before the ladder, scale all
four extended coords. Cost: 4 field multiplications; ~< 1 %
overhead.
Scalar blinding works the same way: a' = a + r · ℓ for
ℓ = 2^252 + 27742317777372353535851937790883648493, the order
of the prime-order subgroup.
Reading list
Code path summary
Path |
Today (2026-04-21) |
Target (post T1-D + T1-F + T2-A) |
|---|---|---|
|
Pure RFC 8032 deterministic |
Unchanged (kept for KAT determinism) |
|
n/a |
RFC 8032 + 32-byte fresh randomness |
Edwards |
Audit pending |
Audited CT + Z-rerand + scalar blinding |
SHA-512 used inside Ed25519 |
Audit pending |
Same as HMAC / CMAC / KMAC / GMAC — countermeasures (CDPA mitigation if T2-D applies) |
Ed448
Ed448 is deferred in arcana (RFC 8032 Appendix A reference Python port pending). When it lands, the same threat-model chapter applies (mutatis mutandis on Curve448 / Goldilocks): hedged mode, Z-rerandomization, scalar blinding. The implementation route is otherwise identical, since Curve448 also admits extended Twisted-Edwards coordinates.