Digital Signatures

DSA, ECDSA and Ed25519 — what a signature actually proves, why the per-signature nonce is the most dangerous value in applied cryptography, and the deterministic designs that removed the footgun.

A signature proves that whoever holds a specific private key saw a specific message — authenticity, integrity, and non-repudiation in one primitive. Unlike a MAC, verification requires no secret, so anyone can check it: that asymmetry is what makes certificates, code signing, and software update channels possible. The scheme mechanics are straightforward; the operational story is dominated by one value, the per-signature nonce.

What actually gets signed #

Never the message — always its hash. Signing H(m)H(m) rather than mm makes signatures constant-size and fast regardless of input length, but it means the signature is only as strong as the hash: a collision H(m1)=H(m2)H(m_1) = H(m_2) yields one signature valid for two different documents. This is precisely how the 2008 rogue-CA and 2012 Flame attacks worked — they attacked the hash, not the signature algorithm (see Merkle–Damgård).

DSA #

Descended from ElGamal and Schnorr, standardized in 1994 — and no longer approved. FIPS 186-5 (February 2023) removed DSA as an approved algorithm for signature generation, retaining it only to verify signatures that already exist; NIST cited lack of industry use and analyses showing DSA implementations are vulnerable when domain parameters are not properly generated. The current standard approves exactly three schemes: RSA, ECDSA and EdDSA. DSA is worth understanding anyway, because ECDSA is DSA with the group swapped and inherits its defining hazard.

It works in a prime-order subgroup: a large prime pp, a 160-bit (now 224/256-bit) prime qq dividing p−1p-1, and gg of order qq. Private key x<qx < q; public key y=gx mod py = g^x \bmod p.

Sign message mm with a random per-signature secret kk:

r=(gk mod p) mod q,s=k−1(H(m)+xr) mod qr = \left(g^k \bmod p\right) \bmod q, \qquad s = k^{-1}\left(H(m) + xr\right) \bmod q

Verify with (r,s)(r, s) and yy:

w=s−1 mod q,u1=H(m) w mod q,u2=r w mod qw = s^{-1} \bmod q, \quad u_1 = H(m)\,w \bmod q, \quad u_2 = r\,w \bmod q

v=(gu1yu2 mod p) mod q  =?  rv = \left(g^{u_1} y^{u_2} \bmod p\right) \bmod q \;\overset{?}{=}\; r

ECDSA is the same algebra with the multiplicative group replaced by an elliptic curve: rr becomes the x-coordinate of kGkG. Same equations, same nonce requirement, far smaller keys — which is why it took over TLS certificates, Bitcoin and Ethereum.

The nonce is the whole ballgame #

kk must be secret, unique, and unpredictable for every signature. Each property fails differently, and all three failures are total:

Reuse the same kk for two messages and the private key falls out algebraically. Two signatures (r,s1)(r, s_1), (r,s2)(r, s_2) share rr — visibly, on the wire:

k=H(m1)−H(m2)s1−s2 mod q,x=sk−H(m)r mod qk = \frac{H(m_1) - H(m_2)}{s_1 - s_2} \bmod q, \qquad x = \frac{sk - H(m)}{r} \bmod q

Leak a few bits of kk across many signatures and lattice reduction recovers xx — biased nonces need only ~100 signatures with a handful of known bits. Predict kk from a weak RNG and xx follows from a single signature.

  1. 2010 Sony ships the PS3 with a constant ECDSA nonce; fail0verflow extracts the console's master signing key at 27C3. Every "signed" firmware after that is forgeable.
  2. 2013 Android's SecureRandom flaw repeats nonces in Bitcoin wallet signatures; thieves scan the public blockchain for repeated r values and drain the affected wallets.
  3. 2013+ Repeated-r scanning becomes standing practice on public chains — every reuse is permanently visible to anyone.
  4. 2022 CVE-2022-21449 ("Psychic Signatures"): Java 15–18 accepted r = s = 0 as valid for any message — a missing range check, not a nonce bug, but the same class of catastrophic verification failure.

The structural fix: deterministic and Edwards signatures #

RFC 6979 derives kk deterministically as HMAC-DRBG(private_key, H(m)). Same message and key always produce the same signature, no RNG is consulted at signing time, and the nonce is unpredictable to anyone without the private key. It is a drop-in change — the signatures remain standard ECDSA and verify with unmodified verifiers.

Ed25519 (RFC 8032) goes further, redesigning the scheme around the failure modes:

Property ECDSA Ed25519
Nonce caller-supplied randomness deterministic: H(key prefix ∣ m)H(\text{key prefix} \,|\, m)
Point arithmetic branchy, needs constant-time care complete Edwards formulas, no special cases
Signature malleability malleable (both ss and −s-s valid) canonical form enforced
Signature / key size 64 / 32 bytes (P-256) 64 / 32 bytes
Encoding ASN.1 DER — a parsing-bug generator fixed-length octet strings
Verification pitfalls point validation, zero checks fewer edge cases; cofactor rules specified

Comparing signature performance correctly #

ECDSA signing computes one fixed-base scalar multiplication plus modular arithmetic; verification combines two scalar multiplications. ECKCDSA and ECGDSA rearrange that algebra, so operation-count comparisons depend on whether inversion is performed in the scalar field or curve field, whether fixed-base tables are precomputed, and which coordinates avoid inversions during point multiplication.

That makes a symbolic count useful for explaining an implementation, but insufficient for choosing a scheme. Measure the exact curve, library, CPU, constant-time mode, precomputation memory, batch size, key/signature encoding, and verification workload. A faster formula with variable-time secret-dependent code is not an acceptable signing implementation.

The current NIST portfolio also extends beyond the classical schemes in FIPS 186-5: FIPS 204 standardizes ML-DSA and FIPS 205 standardizes SLH-DSA for post-quantum signatures. That is a migration choice with different key/signature sizes and deployment constraints, not an interchangeable “faster ECDSA.”

Source claims audit #

Seeded from a university lab manual (DSA/SSL lab, following Applied Cryptography). Status of its load-bearing claims:

Claim from source Status Notes
DSA parameter definitions, sign/verify equations, verification identity v=rv = r current Matches FIPS 186; independently recomputed on toy parameters above
"DSA is used only for signatures, cannot be used for encryption" current Correct and worth stressing
"DSA is a variant of Schnorr and ElGamal signatures" current Accurate lineage
"pp is 512 to 1024 bits, multiple of 64; qq is 160 bits" outdated Those sizes are FIPS 186-2 era. FIPS 186-4 raised them to pp = 2048/3072 with qq = 224/256; FIPS 186-5 then dropped DSA entirely for signature generation
DSA presented as a current signature standard outdated Verified against FIPS 186-5 (2023): DSA is approved only for verifying existing signatures. Approved generation algorithms are RSA, ECDSA, EdDSA
"kk is chosen randomly, less than qq" current but dangerously understated Stated as a mechanical step with no warning. Nonce failure is the dominant real-world break; added above
"The standard specifies use of SHA" needs updating Meant SHA-1; current DSS specifies SHA-2/SHA-3. SHA-1 signatures are forbidden
DSA prime-generation procedure from a seed current as history The verifiable-seed idea persists; specific sizes superseded
Source omits ECDSA and EdDSA entirely — Added; ECDSA is what actually ships today, Ed25519 is the recommendation
Source omits nonce reuse consequences — Added: key recovery math plus the PS3 and Bitcoin incidents

Sources

  1. docsFIPS 186-5 — Digital Signature Standard (DSS)
  2. docsRFC 6979 — Deterministic Usage of DSA and ECDSA
  3. docsRFC 8032 — Edwards-Curve Digital Signature Algorithm (EdDSA)
  4. talkConsole Hacking 2010: PS3 Epic Fail (fail0verflow, 27C3)
  5. docsNIST Digital Signatures Project

Searches titles, aliases, headings, summaries, and full text.↑↓ move ↵ open esc close