53 min read

The Math Held; The Interface Leaked: A Field Guide to Digital Signatures

ECDLP and RSA held; the nonce, the canonical form, and the verifier broke instead. A field guide to ECDSA, EdDSA, RSA-PSS, determinism, and malleability.

Permalink

1. Two Signatures, One Nonce, and the Master Key Fell Out

In December 2010, at the 27th Chaos Communication Congress, a group called fail0verflow put a single slide on the screen that ended the security of the PlayStation 3 [1]. Sony had signed every piece of PS3 firmware with ECDSA, a scheme whose security rests on a discrete logarithm no one has ever solved for a 256-bit curve.

Sony's engineers did not need to fail. They reused the same secret random number -- the per-signature nonce -- for every signature, and any two signatures that share a nonce give up the private key by grade-school algebra. The curve was pristine. The master key fell out of two subtractions.

Twelve years later, the failure jumped one layer up the stack. Java shipped an ECDSA verifier that accepted the signature (r, s) = (0, 0) for any message and any public key -- "Psychic Signatures," CVE-2022-21449, a CVSS 7.5 flaw that forged TLS handshakes, signed JWTs, SAML assertions, and WebAuthn responses alike [4], [5]. One break leaked a private key through the nonce; the other waved a forgery through at the verifier. Neither touched the underlying hardness assumption. Nobody solved a discrete log. Nobody factored a modulus.

That is the pattern this article is about, worth stating as a question you can carry through every section: when a signer or verifier meets a value it did not create, what secret does it leak, or what forgery does it wave through? The answer is almost never "the math was weak." A signature scheme is only as safe as three things it hands the caller and refuses to decide for you: the per-signature nonce, the signature's canonical form, and the verifier's acceptance rule. ECDSA outsources all three at once.

That is why one scheme -- its elliptic-curve discrete logarithm fully intact -- spawned four categorically different disasters: the reused nonce of the PS3, the drained Android Bitcoin wallets, the malleable transactions that unsettled Bitcoin, and the psychic verifier in Java. You half-know these headlines already. This is the one sentence underneath all of them.

The math held; the interface leaked.

The rest of signature history since ECDSA is one effort to pull those three surfaces back inside the scheme, so the caller can no longer get them wrong. To see why a shared random number hands over a private key -- and why "just use Ed25519" is a real answer but not the whole one -- you first have to be precise about what a signature promises, and the three jobs ECDSA quietly delegates to you.

2. What a Signature Actually Is (and the Three Things ECDSA Hands You)

Everyone knows the one-liner: sign with the private key, verify with the public key. That one-liner hides three decisions the scheme refuses to make for you. Start with the part that is simple.

A digital signature scheme is three algorithms. KeyGen -> (pk, sk) produces a public verification key and a private signing key. Sign(sk, m) -> sigma turns a message and the private key into a signature. Verify(pk, m, sigma) -> {accept, reject} lets anyone holding the public key check the pair. The word anyone is the whole point.

A message authentication code also proves a message is authentic, but it verifies with the same secret used to produce it, so only insiders can check it. A signature is publicly verifiable and therefore non-repudiable: the entire world can confirm it, and only the holder of sk could have produced it.

Digital signature scheme

A triple of algorithms: KeyGen produces a public key and a private key; Sign maps a private key and a message to a signature; Verify maps a public key, a message, and a signature to accept or reject. Unlike a message authentication code, it is publicly verifiable and non-repudiable, since verification needs only the public key.

Public verifiability is what makes a signature strictly stronger than a MAC, and strictly slower. A MAC can rest on a single shared secret and a fast keyed hash. A signature cannot rest on any shared secret, because the verifier must be the whole world, so it has to be built on a public-key hardness assumption -- and pays for it in both compute and signature size.

The bar every scheme is measured against

"Secure" needs a precise meaning, and cryptographers settled on one in 1988. Goldwasser, Micali, and Rivest defined existential unforgeability under adaptive chosen-message attack, or EUF-CMA: an adversary who may ask you to sign any messages it likes, adaptively, still cannot produce a valid signature on a single new message it never queried [6]. That is a demanding bar, and every scheme in this article is designed to clear it.

But notice the exact word: a new message. EUF-CMA says nothing about whether there might be more than one valid signature on a message you did sign. Tighten the game by one word and you get strong unforgeability, SUF-CMA: the adversary cannot produce any new valid signature, even on an already-signed message. The gap between "new message" and "new signature" looks pedantic. It is the entire malleability story that unravels a Bitcoin transaction in a later section, so it is worth planting the seed now.

EUF-CMA (existential unforgeability under chosen-message attack)

The standard security goal for signatures: after obtaining signatures on messages of its choice, an adversary still cannot produce a valid signature on any message it did not query. It forbids forging a new message but says nothing about producing a second signature on an old one.

SUF-CMA (strong unforgeability)

A stronger goal that forbids even a new signature on an already-signed message. The difference from EUF-CMA is one word -- new message versus new signature -- and it is exactly the property that signature malleability violates.

EUF-CMA does not promise there is only one valid signature per message. A scheme can be perfectly unforgeable in the textbook sense and still let anyone manufacture a second, different signature on a message you already signed. Whether that matters depends on whether your protocol ever treats the signature itself as an identifier.

The thesis, stated as the scheme's interface

Here is the organizing idea of the field guide. A signature scheme hands the caller three things and quietly makes each one the caller's responsibility. ECDSA is the worked example that outsources all three.

Surface 1, the nonce. To sign, ECDSA needs a fresh secret random number for every signature. Supply a bad one and you leak the private key. Surface 2, the canonical form. A valid ECDSA signature (r, s) has an evil twin (r, n-s) that also verifies, so the caller must decide whether those are "the same" signature. Surface 3, the verifier. ECDSA's acceptance rule involves modular inversions and range checks, and the specification left enough slack that two conformant-looking verifiers can disagree about which signatures are valid. Every deployed break in this article lives in one of these three surfaces.

Ctrl + scroll to zoom
ECDSA hands the caller three surfaces, and each one is a place the private key or a forgery can leak out

The academic description of ECDSA that stands in for the paywalled ANSI standard spells out this division of labor: the scheme defines the arithmetic and leaves nonce generation, encoding choices, and verifier strictness to the implementer [7], [8]. The cleaner schemes we reach later pull these surfaces back inside the definition. BIP-340 Schnorr, for instance, specifies its verifier down to the byte precisely so the caller cannot get surface 3 wrong [3].

The table below is the entire article compressed into one grid: read across each row to watch a surface move from "the caller's problem" to "the scheme's problem."

SurfacePlain ECDSARFC 6979 / hedged ECDSAEd25519BIP-340 Schnorr
1. NonceCaller supplies from an RNGPulled inside: derived from key and messagePulled inside: native deterministicPulled inside: synthetic and hedged
2. Canonical formCaller must enforce low-sCaller must enforce low-sPulled inside: strict S < L on decodePulled inside: fixed 64-byte form
3. Verifier ruleCaller implements, easy to botchCaller implements, easy to botchMostly specified (RFC 8032)Pulled inside: specified at the byte level

Two of those three surfaces were invented before ECDSA existed: the nonce in 1985, the "form" problem in 1978. To understand why a modern scheme still hands them to you, we have to go back to the moment signatures were only an idea.

3. Where Signatures Came From (1976 to 1996)

In 1976, two Stanford researchers could describe exactly what a signature must do and had no way to build one. Whitfield Diffie and Martin Hellman's "New Directions in Cryptography" named the requirement -- a private operation that anyone can verify with public information, giving the world a way to hold a signer to their message -- but it offered no algorithm to realize it [9]. The problem was posed before it was solved, and the two ways it eventually got solved are the two tracks this whole article runs along.

Track A: the trapdoor line

Two years later, RSA gave the first concrete construction. Signing is the private-key operation, verifying is the public-key operation, and the trapdoor -- factoring is hard, so inverting the public operation without the private exponent is infeasible -- makes the asymmetry real [10].

It worked, and it immediately exhibited surface 2. Textbook RSA, which signs the bare message as σ=mdmodN\sigma = m^d \bmod N, is existentially forgeable: pick any σ\sigma, compute m=σemodNm = \sigma^e \bmod N, and you have a valid pair for a message you did not choose but that is still "signed."

It is also multiplicatively malleable, because σ1σ2modN\sigma_1 \cdot \sigma_2 \bmod N is a valid signature on m1m2modNm_1 \cdot m_2 \bmod N. The raw trapdoor has no notion of which messages are legitimately structured, so the caller must impose that structure. Getting that structure right, with a proof, took fifteen years and is the subject of a later section.

Track B: the discrete-log line

In 1985, Taher ElGamal built the first signature whose hardness rests on the discrete logarithm problem rather than factoring [11]. It also introduced the load-bearing footgun that defines the rest of this article: a fresh secret nonce drawn for every single signature. Learn that nonce, or reuse it, and the private key follows. This is where surface 1 enters the lineage, and DSA and ECDSA inherit it unchanged.

The engine and the yardstick

Two ideas from the late 1980s frame everything after. In 1986, Fiat and Shamir showed how to turn an interactive identification protocol -- prove you know a secret without revealing it -- into a non-interactive signature, by replacing the verifier's random challenge with a hash of the commitment and the message [12]. That transform is the engine underneath Schnorr, DSA, and EdDSA, and it comes with a catch we return to in the limits section: its security is argued in the random-oracle model, treating the hash as an ideal random function.

Then, in 1988, GMR gave the field its yardstick, EUF-CMA, the definition every later scheme is measured against [6].

Fiat-Shamir transform

A method that converts an interactive public-coin identification protocol into a non-interactive signature by replacing the verifier's random challenge with a hash of the commitment and the message. Its security is argued in the random-oracle model, which treats the hash function as an ideal random function.

The clean template, and the patent that froze it

In 1989, Claus-Peter Schnorr published the scheme that, in hindsight, got everything right. The signer commits to a random point R=kGR = kG, computes a challenge e=H(Rm)e = H(R \mathbin{\|} m) by hashing the commitment and message, and answers with s=k+exs = k + ex, where xx is the private key. Verification is a single linear check. That linearity is not a detail; it is the reason the scheme is provable, batchable, aggregatable, and non-malleable, and it is the direct ancestor of EdDSA and BIP-340 [13].

There was one problem, and it bent the entire history. Schnorr patented the scheme (US 4,995,082, invented 1989, granted 1991, expired 2008) [14]. NIST, which needed a royalty-free national standard, could not use it. So the best-behaved discrete-log signature ever designed sat frozen for two decades while the government standardized around something else. The clean scheme was invented first and deployed last.

Schnorr's work appears twice in the literature: at CRYPTO '89 as "Efficient Identification and Signatures for Smart Cards," and in the Journal of Cryptology in 1991 as "Efficient Signature Generation by Smart Cards." They are the same line of work at two venues; cite either, and do not treat one date as a correction of the other.
Ctrl + scroll to zoom
Two genealogies of the digital signature: the RSA trapdoor track and the discrete-log track, from the 1976 idea to the byte-exact schemes of the 2020s

With the clean scheme locked behind a patent, the U.S. government needed a signature standard of its own. The choices it made under patent pressure are the reason the worse-behaved scheme shipped to the entire internet first.

4. Padding, DSA, and the Fateful Nonce

Two tracks, two ways to get it wrong first. RSA had to learn not to sign the bare message. The discrete-log camp had to standardize around a secret it could not afford to leak.

Track A cleans up its form

The fix for textbook RSA's forgeability is a rule you will hear again: never sign the bare message. Hash it first, then pad the hash into a full-width, unpredictable representative that fills the modulus. Done right, this kills existential forgery -- an attacker can no longer start from a random σ\sigma and back out a validly structured message -- and it destroys the multiplicative structure that let signatures be multiplied together.

The workhorse encoding is PKCS#1 v1.5, a deterministic padding standardized in the early 1990s and still ubiquitous [15]. Full-Domain Hash was the conceptual bridge: hash the message across the entire width of the modulus. And in 1996, Bellare and Rogaway's Probabilistic Signature Scheme (PSS) added a random salt and, with it, the tightest security proof any deployed signature would ever get [16], [10].

We give PSS its own section later; for now, note only that Track A's first footgun was the form of what it signed, and Track A fixed it by structuring that form.

Track B standardizes, under patent pressure

The discrete-log camp went a different way, and politics shaped the outcome. In 1991 NIST proposed the Digital Signature Algorithm, and in 1994 it became FIPS 186 [17]. DSA is an ElGamal and Schnorr relative, deliberately structured to sidestep both the RSA patent and Schnorr's patent, credited to David Kravitz and assigned to the NSA [18]. In dodging the clean patented scheme, DSA inherited ElGamal's design decision without modification: a fresh secret nonce for every signature.

Keep the DSA dates distinct: proposed in 1991, standardized as FIPS 186 in 1994. The DSA patent (Kravitz, US 5,231,668) was filed in 1991 and granted in 1993. These four dates get conflated constantly.

Track B goes to curves

Through the late 1990s, Certicom and the ANSI X9F1 committee moved DSA onto elliptic curves. The elliptic-curve discrete logarithm is harder per bit than the finite-field version, so ECDSA gets equivalent security from much smaller keys -- 256-bit curves for 128-bit security, against 3072-bit fields for RSA and finite-field DSA. The template was otherwise unchanged, and so was the fateful decision: the same fresh secret nonce, once per signature [7].

The normative ECDSA standard, ANSI X9.62-1999, is paywalled, so this article cites the open Johnson-Menezes-Vanstone description as its stand-in and never quotes X9.62 text directly. One more scoping note that matters for later decision rules: ECDSA lives on two different families of curves in practice -- the NIST P-curves used across web PKI, and secp256k1, the curve Bitcoin and Ethereum chose. The nonce discipline is identical on both.

By the end of the 1990s, an enormous share of the world's authentication rested on Track B: DSA and ECDSA, both carrying a per-signature secret that had to be unique, unpredictable, and never leaked -- and that the caller, not the scheme, was responsible for generating perfectly, every single time. Surface 1 was loaded and handed over to millions of implementers.

The discrete-log camp had built its entire deployed base on a secret the caller had to generate perfectly, every single time. It took exactly one game console, one wallet app, and one SSH client to prove how badly that goes.

5. The Nonce Catastrophe: ECDSA in Full

Here is the mechanism underneath the PS3 break, the drained Bitcoin wallets, and the 2024 PuTTY disclosure. And here is the precision almost every retelling gets wrong.

ECDSA, mechanically

Key generation is a private scalar dd and its public point Q=[d]GQ = [d]G, where GG generates a group of prime order nn. To sign a message mm, ECDSA draws a nonce kk, forms R=[k]GR = [k]G, sets r=x(R)modnr = x(R) \bmod n, and computes

s=k1(H(m)+rd)modn.s = k^{-1}\bigl(H(m) + r\,d\bigr) \bmod n.

Verification recovers u1=H(m)s1u_1 = H(m)\,s^{-1} and u2=rs1u_2 = r\,s^{-1} and accepts exactly when x([u1]G+[u2]Q)modn=rx\bigl([u_1]G + [u_2]Q\bigr) \bmod n = r [7]. Throughout, H(m)H(m) is the hash truncated to the leftmost bitlen(n)\text{bitlen}(n) bits, not the full digest -- which matters whenever the hash is wider than the order nn, as with the P-521 curve behind the PuTTY story below. Stare at the signing equation and the danger is obvious.

The nonce kk is the load-bearing secret, and ss mixes kk, the message hash, and the private key dd into one linear relation. Anything you learn about kk becomes a linear equation in dd.

Per-signature nonce

The fresh secret integer that a discrete-log signature draws for each signature, used to form the commitment point. It is the load-bearing secret: because the signature value mixes the nonce with the message hash and the private key, anything an attacker learns about the nonce turns into a linear equation in the private key.

The repeat case: certain from two signatures

Sign two different messages with the same nonce and the two signatures share the same rr (because rr depends only on kk). Subtract the two signing equations and kk cancels, leaving a single linear equation you can solve directly for the private key:

d=s2H(m1)s1H(m2)r(s1s2)modn.d = \frac{s_2\,H(m_1) - s_1\,H(m_2)}{r\,(s_1 - s_2)} \bmod n.

This is not statistical. It is exact, from two signatures. It is the PlayStation 3: Sony used a constant kk, so every firmware signature shared an rr, and two of them were enough [1]. And it is the 2013 Android Bitcoin thefts: a flaw in the Java SecureRandom implementation caused the nonce to repeat across signatures generated on affected devices, and real coins drained from wallets whose signing keys were exposed by the collision [19], [20].

Keep the PS3 disclosures distinct: fail0verflow presented the constant-nonce ECDSA break at 27C3 in December 2010; George Hotz released a separate PS3 root key in January 2011 [21]. They are related events, not the same one. The widely cited figure of roughly 55 BTC lost in the 2013 Android incident comes from secondary reporting; the bitcoin.org primary alert states no loss total. Treat the number as reported, not official.

The recovery really is grade-school algebra. The demonstration below signs two messages under a reused nonce on toy-sized parameters, then plays the attacker: given only the public signature values, it recovers the nonce and then the private key.

JavaScript Recover an ECDSA private key from two signatures that share a nonce
// Illustrative toy sizes, NOT secure. Here r stands in for x([k]G) mod n;
// a real attacker reads r straight off the two signatures.
const n = 1000003n;                       // small prime "group order"
const mod = (a, m) => ((a % m) + m) % m;
function inv(a, m) {                       // modular inverse, extended Euclid
let [or, r] = [mod(a, m), m], [os, s] = [1n, 0n];
while (r !== 0n) { const q = or / r; [or, r] = [r, or - q * r]; [os, s] = [s, os - q * s]; }
return mod(os, m);
}
// Signer's secrets (the attacker never sees these):
const d = 123456n;                        // private key
const k = 654321n;                        // per-signature nonce -- REUSED: the whole bug
const r = 42n;                            // r = x([k]G) mod n; same k gives the same r
const h1 = 111111n, h2 = 222222n;         // two message hashes
// ECDSA signing: s = k^{-1} (h + r*d) mod n
const s1 = mod(inv(k, n) * mod(h1 + r * d, n), n);
const s2 = mod(inv(k, n) * mod(h2 + r * d, n), n);
// Attacker sees only (r, s1, s2, h1, h2). Recover k, then d:
const kRec = mod(mod(h1 - h2, n) * inv(mod(s1 - s2, n), n), n);
const dRec = mod(mod(s1 * kRec - h1, n) * inv(r, n), n);
console.log('recovered nonce k = ' + kRec + '  (true ' + k + ')');
console.log('recovered key   d = ' + dRec + '  (true ' + d + ')');
console.log(dRec === d ? 'PRIVATE KEY RECOVERED from two signatures' : 'mismatch');

Press Run to execute.

Two subtractions and two inversions. No discrete logarithm was harmed.

The bias case: statistical, and it needs many

Now change the failure. Instead of repeating the nonce, suppose the nonce generator is subtly biased -- say the top few bits are always zero. No two signatures share an rr, so the two-subtraction trick does not apply, and no single signature hands you the key.

What you have instead is a stream of signatures that each leak a little information about a secret, which is precisely the Hidden Number Problem: recover a hidden value from many samples that each reveal a few high-order bits. Reformulate the biased signatures as an HNP instance, run lattice reduction, and the private key falls out -- but only after you collect many signatures.

Hidden Number Problem (HNP)

The problem of recovering a hidden integer from many samples that each leak only a few of its high-order bits. A stream of biased-nonce signatures is an HNP instance, and lattice reduction solves it. This is why a biased nonce is a statistical attack that needs many signatures rather than a single one.

The canonical modern proof is PuTTY. In April 2024, CVE-2024-31497 disclosed that PuTTY's ECDSA nonce generator for the NIST P-521 curve was biased so that the first 9 bits of each nonce are zero, enabling full secret key recovery in roughly 60 signatures [2]. Sixty. Not two.

The rigor behind that number is a quarter-century of work: Boneh and Venkatesan introduced the Hidden Number Problem in 1996 [22]; Howgrave-Graham and Smart turned it into the first practical lattice recovery of DSA keys from partial nonces in 2001 [23]; Nguyen and Shparlinski made ECDSA key recovery from a few leaked nonce bits rigorous in 2003 [24]; and by 2020, LadderLeak recovered keys with under one bit of nonce leakage per signature [25].

Bleichenbacher's much-cited biased-nonce DSA attack has no standalone peer-reviewed paper; it circulated through talks and other authors' write-ups. Cite the mechanism through the Nguyen-Shparlinski and LadderLeak lattice literature, not a fabricated Bleichenbacher reference.

The precision that almost every retelling gets wrong

A repeated nonce leaks the private key with certainty from just two signatures. A few-bit-biased nonce is different: a statistical lattice attack that needs many signatures, not one. Conflating repeat with bias is the single most corrected misconception in this corner of cryptography.

AttackSignatures neededMethodCertaintyCanonical example
Repeated nonceTwoElementary algebra, two linear equationsExact, deterministicPS3 (2010); Android wallets (2013)
Biased nonceMany (tens to thousands)Hidden Number Problem, lattice reductionStatisticalPuTTY (roughly 60); LadderLeak (under one bit)
The lattice attack, in one paragraph

Each biased signature gives a linear relation of the form kiai+bid(modn)k_i \equiv a_i + b_i\,d \pmod n where the unknown nonce kik_i is known to be small (its top bits are zero). Stack these relations as rows of a lattice whose short vectors correspond to the small nonces. Running LLL or BKZ finds a short vector, which reveals the nonces and hence dd. The fewer bits each signature leaks, the more signatures and the more lattice-reduction effort you need -- hence "statistical, and it needs many."

Two root causes hide under the word "bias"

There is a second fork that decides which cure you need. A generation failure -- a bad RNG that repeats or biases the nonce -- is cured by not depending on the RNG at all, which is the deterministic signing of the next section. But a usage failure is different: even a perfectly generated nonce leaks if the code that consumes it, the scalar multiplication [k]G[k]G, runs in time or draws power that depends on the nonce's bit-length. That is a side channel, and no amount of clever nonce generation closes it.

In 2019, both Minerva and TPM-Fail recovered ECDSA keys from exactly this timing leak, then finished the job with the same lattice machinery as the bias case [26], [27]. The cure there is constant-time scalar multiplication.

Ctrl + scroll to zoom
The nonce is one secret with two independent failure modes and two independent cures

So the random-number generator was the enemy in three of these four stories. The obvious fix is a better RNG. The actual fix, the one the whole field converged on, was to use no randomness at all.

6. The Fix for a Randomness Disaster Was Less Randomness

The counterintuitive move: if a bad random nonce is what kills you, stop rolling the dice. Derive the nonce deterministically from the one thing that is already secret and the one thing that is already unique.

RFC 6979, the retrofit

Thomas Pornin's RFC 6979 does exactly that. It derives the nonce as a deterministic function of the private key and the message hash, driving an HMAC-based deterministic random bit generator so that signing consumes no runtime entropy. A broken system RNG can no longer cause a repeat or a generation bias, because there is no RNG in the signing path [28].

The elegance is that nothing downstream changes: a deterministic signature verifies under the same verifier as a randomized one, so this is a drop-in with zero protocol change. The RFC states the goal plainly -- signers "do not need access to a source of high-quality randomness" -- and warns that even slight biases in nonce generation may be turned into attacks, exactly the HNP lineage from the previous section [28].

Deterministic signing (RFC 6979)

Deriving the per-signature nonce as a deterministic function of the private key and the message, via an HMAC-based deterministic random bit generator, so that signing needs no runtime entropy and a failing RNG can neither repeat nor bias the nonce. The resulting signature verifies under the ordinary verifier.

But determinism is not unconditionally safer

Determinism trades one threat model for another. A fully deterministic signer is a fixed, replayable target. Feed it the same key and message twice and it does exactly the same computation, which is the ideal setup for a differential fault attack: run the signer twice, glitch one of the two runs with a voltage or clock disturbance, and diff the correct output against the faulted one to recover the key.

Poddebniak and colleagues demonstrated this against deterministic signature schemes in 2018 [29]. NIST took the point: FIPS 186-5 approves deterministic ECDSA yet explicitly flags deterministic schemes as being of particular concern for fault attacks [30].

The resolution: hedged signing

Hedged signing mixes a little fresh randomness back in on top of the deterministic derivation. RFC 6979's own section on variants sanctions adding extra input to the nonce derivation, noting that the result is then no longer deterministic (EC)DSA [28]. The payoff is that a hedged signer survives both failure modes: if the RNG dies, the deterministic core still produces a safe, distinct nonce; if the RNG works, the fresh entropy makes each signing unrepeatable and defeats the differential fault attack.

This is where modern libraries land by default. Go's crypto/ecdsa hedges: its documentation says signatures "are not deterministic, but entropy is mixed with the private key and the message," and that "if rand is nil, Sign will produce a deterministic signature according to RFC 6979" [31]. BoringSSL mixes in additional entropy the same way [32], and the security analysis of hedged Fiat-Shamir signatures under faults gives this posture a formal footing [33].

Hedged signing

Mixing a small amount of fresh randomness into the deterministic nonce derivation, so the signer survives both RNG failure and single fault attacks. It is explicitly not deterministic (EC)DSA, and it is the default in libraries such as Go crypto/ecdsa and BoringSSL.

One caution: it fixes only the generation surface. The usage leak from the previous section -- the timing side channel during scalar multiplication -- is untouched by how you derive the nonce, and its cure remains constant-time code. Three cures, three distinct threats.

Nonce strategyNonce sourceSurvives RNG failure?Resists the fault attack?Where it lands
Randomized (classic ECDSA)Fresh RNG each signatureNo, the RNG is the whole riskYes, runs differThe PS3 and Android failure mode
Deterministic (RFC 6979)HMAC-DRBG of key and messageYesNo, a replayable targetVerifies under the ordinary verifier
Hedged (RFC 6979 variants)Deterministic core plus fresh entropyYesYesGo and BoringSSL default

RFC 6979 pulled surface 1 back inside the scheme, but only surface 1, and only as a patch bolted onto a design that still leaks the other two. A cleaner scheme would make deterministic nonces, a fixed encoding, and a byte-exact verifier all native. That scheme already existed. It had been waiting on a patent to expire for two decades.

7. The Breakthrough: Schnorr Done Right

Everything RFC 6979 retrofitted, one scheme had baked in from birth. It was invented in 1989 and could not be deployed until 2008, because it was patented.

Why Schnorr is clean

Recall Schnorr's response, s=k+exs = k + ex. That single linear equation is what makes the scheme provable, batchable, and aggregatable. Provable, because the linear structure is what the Pointcheval-Stern forking lemma needs to reduce forgery to the discrete-log problem in the random-oracle model [34]. Batchable, because a linear verification equation lets you check many signatures as one combined equation, the subject of a later section. Aggregatable, because linear things add, which is why threshold and multi-signature schemes like FROST and MuSig2 build directly on Schnorr.

The Fiat-Shamir transform is still the engine turning the underlying identification protocol into a signature; Schnorr is simply the cleanest identification protocol to feed it.

EdDSA and Ed25519 pull all three surfaces inside

In 2011, Bernstein, Duif, Lange, Schwabe, and Yang published EdDSA, and its edwards25519 instantiation, Ed25519, is the scheme that pulls all three surfaces inside the definition by design [35].

Surface 1, the nonce, is native and deterministic. Ed25519 computes the nonce as r=H(prefixM)modLr = H(\text{prefix} \mathbin{\|} M) \bmod L, hashing a secret key-derived prefix together with the message. There is no runtime RNG in the signing path, so the entire PS3 and Android failure class is structurally impossible rather than merely discouraged. The designers said so directly, and named the incident:

Signatures are generated deterministically ... directly relevant to the recent collapse of the Sony PlayStation 3 security system.

Surface 2, the encoding, is fixed. An Ed25519 signature is a fixed 64-byte string, a point encoding followed by a scalar, and RFC 8032 mandates a strict range check that the scalar satisfy 0S<L0 \le S < L on decode. Enforcing that check makes a strict Ed25519 implementation strongly unforgeable, closing the malleability surface at the encoding level [36].

Surface 3, the arithmetic, is safe by construction. edwards25519 uses a complete twisted-Edwards addition law with no exceptional cases, so the constant-time implementation is the natural one, and there are no special points where a naive verifier misbehaves [35]. Determinism here is structural, not a patch bolted on afterward, which is the real reason "why determinism helps" is a property of the design rather than a library option.

EdDSA (Schnorr over Edwards curves)

A Schnorr signature instantiated on a complete twisted-Edwards curve with a key-prefixed deterministic nonce and a fixed encoding. Ed25519 is its edwards25519 instantiation: constant-time by construction, misuse-resistant by design, and strongly unforgeable under a strict verifier.

Key-prefixed nonce

A nonce derived by hashing a secret key-derived prefix together with the message, so it is deterministic, unique per message, and never drawn from a runtime random-number generator. Hashing the public key into the challenge additionally hardens the scheme in multi-user and related-key settings.

Key-prefixing -- folding the public key into the hash that produces the challenge -- is a small design choice with outsized value: it hardens the scheme against multi-user and related-key attacks that a bare Schnorr challenge would leave open.
Ctrl + scroll to zoom
The defensive mirror of the ECDSA diagram: EdDSA and BIP-340 pull all three surfaces inside the scheme, leaving the caller no dangerous choices

BIP-340: Schnorr over secp256k1, with the verifier pulled inside

Bitcoin needed Schnorr on its own curve, secp256k1, and in 2020 BIP-340 delivered it: 64-byte signatures, 32-byte x-only public keys, and, most importantly for surface 3, a verifier specified down to the byte. The specification states that the verification algorithm is "completely specified ... at the byte level," the guarantee whose full payoff we reach when we return to verifier strictness later [3].

BIP-340 also adopts the hedged idea natively: it derives a synthetic nonce and notes that the added randomness is only supplemental to security, so a faulty RNG cannot break it. Bitcoin's Taproot upgrade deployed it in November 2021 [37].

Now the punchline. The scheme that makes deterministic nonces, a fixed encoding, and a byte-exact verifier native is Schnorr, invented in 1989. It could not be deployed until its patent expired in 2008, which is exactly why the worse-behaved ECDSA shipped to the entire internet two decades before its clean successor. Ed25519 arrived in 2011, BIP-340 in 2020. The best-behaved design was first on paper and last in production.

The two-decade gap between the clean scheme's invention (US 4,995,082, 1989) and its deployment -- Ed25519 in 2011, BIP-340 in 2020 -- is a patent artifact, not a technical one.

One honest caveat keeps this from being a silver bullet. Plain Ed25519 has no hedging knob: it is purely deterministic, so on hardware where an attacker can inject faults it is the harder-hit fault target, and hardened embedded implementations re-inject randomness exactly as the hedged-signing analysis recommends [29], [33]. This is coexistence, not a coronation. Ed25519 and BIP-340 close all three surfaces on the discrete-log track. But the other 1976 track, RSA, had its own reckoning with the form of a signature, and its answer came with something the discrete-log schemes still lack: a tight proof.

8. RSA-PSS: Probabilistic Signing with a Tight Proof

On the discrete-log track, determinism was the virtue. On the RSA track, the opposite move -- adding randomness -- bought the best security proof any deployed signature has.

PSS, mechanically

Never sign the bare message. The EMSA-PSS encoding hashes the message, mixes in a fresh random salt, and builds a full-width encoded message before the RSA private-key operation. Concretely, it forms H=Hash(paddingHash(M)salt)H = \mathrm{Hash}(\text{padding} \mathbin{\|} \mathrm{Hash}(M) \mathbin{\|} \text{salt}), masks the salt-bearing data block against a mask generated from HH, and assembles the encoded message as maskedDB followed by HH followed by the trailer byte 0xbc. The signature is that encoded message raised to the private exponent modulo nn [15], [16]. Verification recomputes the whole structure and checks it exactly, rejecting anything that does not fit the padding shape.

Ctrl + scroll to zoom
The EMSA-PSS encoding pipeline: a random salt turns a deterministic pad into a probabilistic one, which is what makes the proof tight

Why probabilistic buys a tight proof

Bellare and Rogaway proved PSS existentially unforgeable with a tight reduction to the RSA problem in the random-oracle model: a forger against PSS can be turned into an algorithm that inverts RSA with essentially the same success probability and running time [16].

That word tight is the whole prize. A tight reduction loses almost nothing between the scheme's security and the underlying hard problem, so a concrete key size gives you concrete confidence; a loose reduction loses a large factor, so you either accept a weaker guarantee or inflate parameters to compensate. By contrast, PKCS#1 v1.5's signature padding has only a heuristic argument, not a tight proof. Among deployed signatures, PSS's guarantee is the gold standard, and it sets up the proof-quality spectrum we return to in the limits section.

RSA-PSS (probabilistic RSA signature)

The Probabilistic Signature Scheme encoding for RSA, which injects a fresh random salt into the padding before the RSA private-key operation and has the verifier recompute and check that structure exactly. The salt is what makes its security reduction to the RSA problem tight, unlike the deterministic PKCS#1 v1.5 padding.

Full-Domain Hash was PSS's provable but loose predecessor: hash the message across the full width of the modulus, then apply the private operation. PSS keeps that idea and adds the random salt, and the salt is precisely what upgrades the reduction from loose to tight.

The deployment reality, stated exactly

"Is RSA-PSS widely deployed?" has a split answer, and blurring the split is a common error. TLS 1.3 makes RSA-PSS mandatory to implement for the online handshake signature: the CertificateVerify message uses the rsa_pss_rsae_* schemes, and a compliant implementation must support them [38]. That is a specification requirement.

Separately, as a matter of deployment, most Web-PKI certificates -- the long-lived signatures a certificate authority puts on the certs in the chain -- are still PKCS#1 v1.5. So the handshake signature your browser makes live and the certificate-chain signatures it validates are different signatures with different padding, and the honest answer separates them.

The cost profile that decides where PSS fits

RSA's economics are lopsided and they determine where it belongs. Verification uses a tiny public exponent, usually 65537, so it is very fast. Signing uses the full-width private exponent, so it is slow, and the signatures are large: 256 bytes at RSA-2048, 384 bytes at RSA-3072, an order of magnitude bigger than a 64-byte elliptic-curve signature. That makes RSA-PSS excellent where you verify far more often than you sign, such as certificates and firmware images, and painful where you sign constantly. We put real numbers on this in the state-of-the-art section.

PSS pinned RSA's form with a proof. But the discrete-log schemes still had an unresolved question about form, one that let anyone alter a signature without the key and briefly threatened to break Bitcoin.

9. Malleability, Canonicalization, and Strong Unforgeability

Recall the promise EUF-CMA does not make: that there is only one valid signature per message. For ECDSA there are always at least two, and the caller was left to notice.

Surface 2: ECDSA malleability, mechanically

Take any valid ECDSA signature (r, s). Now negate the scalar: (r, n - s) also verifies, and it is a different signature on the same message, producible by anyone with no private key at all. The reason is visible in the verification equation. Replacing ss with nsn - s is replacing it with smodn-s \bmod n, which flips the signs of both u1u_1 and u2u_2, negating the recovered point to R-R. On these curves a point and its negation share an xx-coordinate, so x(R)modn=x(R)modn=rx(-R) \bmod n = x(R) \bmod n = r, and the check still passes.

BIP-340 states the fact plainly: "If (r,s) is a valid ECDSA signature then (r,n-s) is also valid" [3]. So standard ECDSA meets EUF-CMA but not SUF-CMA -- exactly why that one-word distinction was worth planting seven sections ago.

Signature malleability

The existence of a second valid signature on an already-signed message that anyone can derive without the private key. For ECDSA, whenever (r, s) is valid so is (r, n - s). It is the reason plain ECDSA satisfies EUF-CMA but fails SUF-CMA.

The protocol fallout: Bitcoin transaction malleability

Malleability is harmless until a protocol treats the signature as an identifier. Bitcoin did. A transaction id is a hash computed over the whole transaction including its signatures, so flipping s to n - s changes the txid without changing what the transaction does. Anything that referenced an unconfirmed transaction by its id -- a chain of dependent spends, a naive payment tracker -- could be broken by a third party rewriting the signature in flight [39].

The honest Mt. Gox nuance: transaction malleability was real and was publicly blamed for the 2014 collapse, but Decker and Wattenhofer measured the malleability activity on the network and found it insufficient to account for the losses, and later analysis attributes most of the missing coins to a wallet compromise around 2011. Real and blamed, but not the sole cause.

The fix: low-s canonicalization restores SUF-CMA

If two signatures differ only by ss versus nsn - s, pick one. The low-s rule requires sn/2s \le n/2, so exactly one of the twins is standard and the other is rejected on sight. Bitcoin moved this from proposal to policy across BIP-62 and BIP-146, and it restores strong unforgeability in the system that needed it most [40], [41]. Ed25519's analogue is the strict S < L range check that RFC 8032 mandates on decode, which is what makes a strict Ed25519 implementation SUF-CMA [36].

Surface 3: the verifier, which closed last and most embarrassingly

The third surface failed in two distinct shapes. The first is a permissive verifier. In 2022, Java's ECDSA verification accepted the all-zero signature (r, s) = (0, 0) for any message and any key, because it skipped the range check that forbids zero. "Psychic Signatures," CVE-2022-21449, scored CVSS 7.5 and forged anything built on Java's signatures: TLS, signed JWTs, SAML assertions, OIDC id tokens, and WebAuthn responses [4], [5].

The second shape is more subtle: honest disagreement. "Taming the Many EdDSAs" showed that verifiers all conforming to RFC 8032 nonetheless split on adversarial inputs -- cofactored versus cofactorless verification equations, non-canonical point encodings, small-order points -- so the same signature could be valid to one library and invalid to another [42]. For a consensus system that is a disaster, and ZIP-215 answers it by pinning a byte-exact validation profile on which single and batch verification always agree [43].

Edwards curves have a cofactor, so the verification equation can be written to multiply through by it (cofactored) or not (cofactorless). RFC 8032 notes the cofactorless check is sufficient but not required, and that latitude is exactly what let conformant verifiers disagree until ZIP-215 fixed a single byte-exact rule.

BIP-340 treats this surface as an engineering requirement rather than an afterthought, which is why its verifier is specified to the byte:

The verification algorithm must be completely specified at the byte level. This guarantees that nobody can construct a signature that is valid to some verifiers but not all.

The evidence, in one table

Every named break in this article splits cleanly across the three surfaces. Read the "Surface" column and the thesis stops being a slogan and becomes a body count.

BreakYearSurfaceSub-typeRoot causeThe rule it teaches
PlayStation 320101. NonceRepeatOne constant nonce across all signaturesNever reuse a nonce; two signatures leak the key
Android Bitcoin wallets20131. NonceGenerationBroken SecureRandom repeated the nonceDo not trust the RNG; derive the nonce
Bitcoin txid, Mt. Gox era20142. Canonical formMalleability(r, n - s) is a free second signatureEnforce low-s; treat SUF-CMA as the bar
Minerva, TPM-Fail20191. NonceUsage, timingNonce bit-length leaked during scalar multConstant-time scalar multiplication
Many EdDSAs, ZIP-21520203. VerifierDisagreementConformant verifiers split on edge casesSpecify the verifier at the byte level
Psychic Signatures20223. VerifierPermissiveVerifier accepted (0, 0) for any messageRange-check the signature; reject zero
PuTTY20241. NonceBiasTop 9 bits of each P-521 nonce were zeroUnbiased or deterministic nonce generation

Notice what is missing from the root-cause column: not once did anyone solve an elliptic-curve discrete logarithm or factor a modulus. That is Aha 1, complete. Fix the nonce, fix the form, fix the verifier, and you have a signature you can trust one at a time. But the modern world verifies millions at once, and the obvious way to batch them is quietly forgeable.

10. Batch Verification, and the One Condition That Makes It Safe

Schnorr's linearity offers a tempting shortcut: instead of checking a thousand signatures one by one, check their sum once. Done naively, that shortcut lets an attacker slip forgeries past you.

The technique

Because Schnorr, EdDSA, and BIP-340 verification is a single linear equation, a batch of uu signatures can be checked as one random linear combination of those equations. That collapses uu separate double-scalar multiplications into a single large multi-scalar multiplication, whose cost is sublinear in the number of distinct bases, which is where the throughput win comes from. The original Ed25519 paper reports a batch of 64 signatures verifying at under 134,000 cycles per signature, against 273,364 cycles for a single verification, roughly a twofold speedup [35].

Batch verification

Checking many signatures with one combined equation instead of one equation each, by exploiting the linearity of Schnorr-type verification. It is safe only when each signature's contribution is weighted by an independent random coefficient; the naive equal-weight sum is forgeable.

The non-negotiable safety condition

The coefficients must be randomized. Here is why the naive all-ones sum fails. A signature verifies exactly when its verification residual is zero. If you add the residuals with equal weight, an attacker can submit two invalid signatures whose residuals are equal and opposite, so they cancel in the sum: the batch equation holds even though neither signature is valid.

Weight each residual by an independent random coefficient and the errors no longer cancel except with negligible probability. BIP-340 derives its batch coefficients from a CSPRNG seeded over all of the inputs, so an attacker cannot predict the weights and engineer a set of residuals that sums to zero without each signature being individually valid [3].

JavaScript All-ones batching accepts a forgery; randomized coefficients reject it
// Illustrative model. A signature is VALID iff its verification residual is 0.
const n = 1000003n;
const mod = (a, m) => ((a % m) + m) % m;
// Attacker forges two invalid signatures whose residuals are equal and opposite.
const D = 777n;                 // the cancelling error the attacker chooses
const e1 = mod(D, n);           // residual of forged signature 1 (nonzero: invalid)
const e2 = mod(-D, n);          // residual of forged signature 2 (nonzero: invalid)
console.log('signature 1 valid on its own? ' + (e1 === 0n));   // false
console.log('signature 2 valid on its own? ' + (e2 === 0n));   // false
// Naive all-ones batch: accept iff the plain sum of residuals is 0
const allOnes = mod(e1 + e2, n);
console.log('all-ones batch residual = ' + allOnes + (allOnes === 0n ? '  -> ACCEPTED, forgery slips through' : '  -> rejected'));
// Randomized batch: weight each residual by a per-input random coefficient
const a1 = 31337n, a2 = 424242n;   // seeded by a CSPRNG over ALL inputs
const rand = mod(a1 * e1 + a2 * e2, n);
console.log('randomized batch residual = ' + rand + (rand === 0n ? '  -> accepted' : '  -> REJECTED, forgery caught'));

Press Run to execute.

Ctrl + scroll to zoom
Batch verification is safe with random per-input coefficients and forgeable with equal weights

What batching does not give you, and where it is not used

A failed batch tells you only that some signature in it is bad, not which one, so you must fall back to individual verification to find the culprit -- a real cost when batches are large. Batching is also a Schnorr-family privilege: BIP-340 notes that standardized ECDSA "cannot be verified more efficiently in batch," so the ECDSA deployments that dominate the web get no speedup here [3]. And adoption is narrower than the technique's fame suggests.

Bitcoin Core does not batch-verify signatures in consensus validation as of 2024 through 2026: the determinism and simplicity of validating each signature independently outweigh the throughput gain. Batch verification is a real optimization for specific high-volume verifiers, not a universal default.

That is the deployed toolkit: ECDSA, Ed25519, BIP-340 Schnorr, and RSA-PSS, each with its surfaces pulled in to a different degree. Which one should you reach for in 2026? The honest answer is not a single winner.

11. State of the Art and Competing Approaches (2024 to 2026)

There is no single best signature scheme to crown. The state of the art is four deployed constructions, each dominant in a niche, plus a set of signposts pointing at the frontier. This is coexistence with selective supersession, not a ladder where each rung replaces the last.

The four, per niche

Deterministic or hedged ECDSA leads by raw deployment. It is what FIPS, TLS, and the secp256k1 chains run, and modern libraries hedge it by default [28], [31]. Ed25519 is the misuse-resistant greenfield default: deterministic nonce, fixed encoding, constant-time by construction [36], [35]. BIP-340 Schnorr leads for consensus and threshold work, being byte-exact, SUF-CMA by design, and linear enough to aggregate [3]. RSA-PSS leads verify-heavy and interoperability-bound settings with its tight proof and cheap verification [15], [38].

Of the classical schemes, only finite-field DSA is withdrawn for new signatures by FIPS 186-5; deterministic ECDSA is approved, which is not the same as mandated [30].

PropertyECDSA (hedged)Ed25519BIP-340 SchnorrRSA-PSS
HardnessECDLP (P-256, secp256k1)ECDLP (edwards25519)ECDLP (secp256k1)RSA, related to factoring
Signature size64 to 72 bytes (DER)64 bytes64 bytes256 bytes at 2048, 384 at 3072
Public key size33 bytes compressed32 bytes32 bytes, x-only256 to 384 bytes
Nonce or randomnessHedged or RFC 6979Native deterministicSynthetic, hedgedFresh random salt
Malleable by default?Yes, enforce low-sNo under strict S rangeNo, byte-exactNo
Batch verificationNoYesYesNo
Proof qualityIdealized onlyLoose, forking lemmaLoose, forking lemmaTight
Sign versus verifyBalancedBalancedBalancedSlow sign, fast verify
Best forFIPS, secp256k1 chainsGreenfield defaultConsensus, thresholdRSA interop, verify-heavy

Benchmarks, read correctly

The reference measurements everyone quotes for Ed25519 come from the eBATS and eBACS public benchmarking effort [35], [44].

Ed25519 operationCost, eBATS reference measurement
Sign one message87,548 cycles
Verify one signature273,364 cycles
Verify in a batch of 64under 134,000 cycles per signature

Signposts at the frontier

Four constructions sit just outside the four-scheme core and deserve a pointer rather than a section. XEdDSA lets you sign with an X25519 Diffie-Hellman key, a specialized key-reuse trick that is deployed at scale in the Signal protocol and the applications built on it, so it is peripheral by role but anything but academic [45].

MuSig2 and FROST are two-round multi-signature and threshold-Schnorr protocols that produce an ordinary 64-byte signature indistinguishable from a single-signer one [46], [47]. BLS offers pairing-based aggregation and anchors Ethereum consensus; a companion part in this series on hashing to curves covers it.

And the horizon is post-quantum: NIST finalized ML-DSA in FIPS 204 and SLH-DSA in FIPS 205 in August 2024, both with signatures ranging from kilobytes to tens of kilobytes, an order of magnitude or more larger than anything in the table above [48], [49].

XEdDSA is de-randomized like plain EdDSA, so absent hedging it inherits the same differential-fault exposure, which the hedged Fiat-Shamir analysis addresses [33].

Every row of those tables assumes the hardness holds. That assumption has a precise shape, and a known expiration date.

12. Theoretical Limits

Here is what a first course skips: none of these schemes has an unconditional proof, their proofs differ enormously in quality, and every one of them dies to the same quantum algorithm.

Conditional security, three assumptions

Every guarantee in this article is conditional. The elliptic-curve schemes rest on the hardness of the elliptic-curve discrete logarithm; RSA-PSS rests on the RSA problem, which is no harder than factoring; and all of the Fiat-Shamir schemes rest additionally on the random-oracle model, a heuristic that proves security while treating the hash function as an ideal random function that no real hash exactly is. "Provably secure" here always means "secure if these assumptions hold." That is not a weakness peculiar to signatures; it is the honest status of essentially all deployed public-key cryptography.

The tightness spectrum

The interesting frontier is not whether the proofs exist but how much they lose. A reduction converts an attacker on the scheme into an algorithm against the hard problem, and the tightness of that conversion is how much security leaks in the translation.

SchemeReduction (random-oracle model)TightnessWhat it means
RSA-PSSTo the RSA problem, Bellare-RogawayTightThe best guarantee of any deployed signature
Schnorr, EdDSATo discrete log via the forking lemma, Pointcheval-SternLoose, quadratic lossSeurin showed the loss is essentially optimal, a barrier not a gap
(EC)DSAOnly with an idealized conversion function, Fersch-Kiltz-PoetteringIdealizedSecure because ECDLP holds, not because the scheme is clean

RSA-PSS has a tight reduction to RSA [16]. Schnorr and EdDSA have only a loose, quadratic-loss reduction through the forking lemma [34], and Seurin proved that this loss is essentially the best any algebraic reduction can do, so it is a genuine barrier rather than a proof waiting to be improved [50]. Later work made the multi-user Schnorr reduction explicit, with a loss on the order of the number of hash queries [51]. And (EC)DSA has the weakest guarantee of all: the only known proofs must model its conversion function as an idealized, bijective random oracle [52].

Deployment and proof quality are inversely correlated here. The most-deployed signature in the world, ECDSA, has the least satisfying proof: it is secure because the elliptic-curve discrete logarithm is hard, not because the scheme is clean. And tight proof or loose, every scheme in this article falls to Shor's algorithm. The destination is post-quantum, not a better curve.

The classical hardness bounds are near-optimal but unproven. Elliptic-curve discrete log costs about 2^128 operations for a 256-bit curve by Pollard's rho, which is optimal in the generic-group model, while factoring costs sub-exponential effort by the general number field sieve. Neither hardness is proven, and RSA inversion is not even proven equivalent to factoring.

The one bound that is not conjectural

There is exactly one limit in this section that is not an open question. Shor's algorithm solves both factoring and the discrete logarithm in quantum polynomial time, so a cryptographically relevant quantum computer breaks every scheme in this article at once [53]. No curve size and no modulus length helps, because Shor's cost is polynomial in the key size. The elliptic-curve schemes and RSA-PSS fall together.

If the theory is this settled -- conditional proofs of differing quality and a known quantum cliff -- then everything still up to you lives in the code. Here is that part, compressed into rules you can apply on Monday.

13. The Practical Guide: Decision Rules

Every rule below is one row of the failure catalog, inverted. If you remember nothing else, remember the decision tree.

Ctrl + scroll to zoom
Choosing a signature scheme from your constraints, with the parameters each choice implies

Use X, with these parameters, in this case

Greenfield, no FIPS constraint. Reach for Ed25519, verified with a strict profile that enforces the canonical S < L range and a ZIP-215-style byte-exact rule [36], [43]. You get deterministic nonces, a fixed encoding, and constant-time arithmetic for free.

FIPS-constrained. Use deterministic or hedged ECDSA on P-256 following RFC 6979 and its hedged variant, or FIPS 186-5-approved Ed25519. Enforce low-s, and insist on a constant-time library so you do not reopen the Minerva timing surface [28], [30].

RSA interoperability for a new design. Use RSA-PSS (the PS256 scheme), never PKCS#1 v1.5 for new work. Set the salt length equal to the hash length, use a matching MGF hash, and choose at least RSA-3072 for 128-bit security [15].

Bitcoin or byte-exact consensus. Use BIP-340 Schnorr, as deployed in Taproot. If you are stuck with legacy ECDSA, enforce low-s and strict DER encoding so transactions are not malleable [3], [41].

Threshold or multisig. Use FROST or MuSig2 over BIP-340, and never use deterministic nonces in multi-party signing -- a deterministic nonce in an interactive protocol can be replayed across differing co-signer inputs and leak the share [47], [46], [3].

Always. Hedge the nonce whenever the platform can face fault injection. Domain-separate your keys per scheme: BIP-340 warns that reusing one key across RFC-6979 ECDSA and BIP-340 can leak it through cross-scheme nonce coincidences [3]. Verify strictly, and when any part of your protocol hashes over signatures, treat SUF-CMA, not merely EUF-CMA, as the bar.

ConstraintUseKey parametersBecause of (named break)
Greenfield, no FIPSEd25519Strict S < L, ZIP-215 verifierPsychic Signatures, Many EdDSAs
FIPS-constrainedHedged ECDSA P-256, or FIPS Ed25519RFC 6979 or hedged, low-s, constant-timePS3, PuTTY, Minerva
RSA interop, new designRSA-PSS as PS256Salt length equals hash length, RSA-3072 or largerv1.5 low-exponent forgeries
Bitcoin or consensusBIP-340 Schnorr (Taproot)Or low-s and strict DER if legacy ECDSABitcoin txid malleability
Threshold or multisigFROST or MuSig2Never deterministic nonces in multi-partyReused-nonce key recovery
OpenSSL commands you can try

Generate an Ed25519 keypair, then sign and verify a message, with OpenSSL 3.x:

  • Create the private key: openssl genpkey -algorithm ed25519 -out sk.pem
  • Extract the public key: openssl pkey -in sk.pem -pubout -out pk.pem
  • Sign: openssl pkeyutl -sign -inkey sk.pem -rawin -in message.txt -out sig.bin
  • Verify: openssl pkeyutl -verify -pubin -inkey pk.pem -rawin -in message.txt -sigfile sig.bin

To force RSA-PSS rather than PKCS#1 v1.5 when signing with an RSA key: openssl dgst -sha256 -sign rsa.pem -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -out sig.bin message.txt

Turn each of those rules around and you get the antipatterns that keep showing up in real code review: the misuse catalog.

14. Common Misuse, and the One Sentence Underneath

Every break in this article was a violated rule from the last section. Here they are as the antipatterns a reviewer actually finds in real code.

  • A caller-supplied nonce from a weak or predictable RNG. This is the Android wallets and, in its biased form, PuTTY [19], [2].
  • A nonce reused across messages or keys. This is the PS3, and it is certain from two signatures [1].
  • Non-constant-time scalar multiplication. This is Minerva and TPM-Fail: even a perfect nonce leaks through timing [26], [27].
  • Skipping the range, subgroup, or canonical-s checks. This reopens malleability, and for a permissive verifier it reopens forgery [3].
  • Treating EUF-CMA as if it meant non-malleability. This is Bitcoin transaction-id malleability: the scheme was unforgeable and the protocol still broke [3].
  • Naive all-ones batch coefficients. A forgeable batch, defeated by errors that cancel in the sum [3].
  • A lax or permissive verifier. This is Psychic Signatures, which accepted the all-zero signature for any message [4].
  • PKCS#1 v1.5 for new designs, or blurring the encryption-versus-signature split. Use RSA-PSS, and never confuse the v1.5 decryption oracle with the unbroken v1.5 signature scheme [15].
  • Signing without domain separation. One key across two schemes can leak through cross-scheme nonce coincidences [3].

Frequently asked questions

Does one biased nonce leak my private key?

No, and this is the most repeated mistake in the area. A repeated nonce leaks the key with certainty from just two signatures -- that is the PS3 break. A biased nonce, where the top few bits are always zero, is a statistical attack: it takes many signatures and lattice reduction, framed as the Hidden Number Problem, to recover the key, as PuTTY's roughly-sixty-signature break showed. "One few-bit-biased signature leaks your key" is false.

Is deterministic signing always safer?

No. Deriving the nonce deterministically removes the RNG-failure disaster, but it turns the signer into a fixed, replayable target for fault attacks: glitch one of two identical signings and diff the outputs. The resolution is hedged signing -- mix a little fresh randomness back in -- which most modern libraries do by default.

Does Ed25519 malleability mean it is broken?

No, but it is nuanced. Standard Ed25519 can be malleable at the group level unless the verifier enforces the canonical S < L range check that RFC 8032 mandates on decode. Enforce it, as strict libraries do, and Ed25519 is strongly unforgeable; skip it and you inherit a malleability surface.

Which PKCS#1 v1.5 is broken, encryption or signatures?

Encryption. The v1.5 encryption padding is the classic Bleichenbacher decryption oracle. The v1.5 signature scheme is not broken; its real failures were implementation bugs in lax verifiers, such as low-exponent forgeries, not a break of the signature math. Even so, use RSA-PSS for new designs.

ECDSA or Ed25519 for a new project?

Ed25519 for anything greenfield: deterministic nonces, a fixed 64-byte encoding, constant-time arithmetic, and strong unforgeability under strict verification. Use ECDSA only where a standard or platform compels it, such as FIPS environments or secp256k1 chains, and then with RFC 6979 or hedged nonces, low-s enforcement, and a constant-time library.

Is EUF-CMA enough, or do I need SUF-CMA?

If any part of your protocol hashes over or deduplicates by the signature itself -- transaction ids, caches, replay checks -- you need SUF-CMA, because plain EUF-CMA lets an attacker produce a different valid signature on the same message. Enforce low-s or a strict S < L range, or choose a SUF-CMA-by-design scheme like BIP-340.

Are these signatures quantum-safe?

No. Shor's algorithm breaks both discrete log and factoring in polynomial time, so ECDSA, EdDSA, BIP-340, and RSA-PSS all fall to a cryptographically relevant quantum computer, and no curve or modulus size helps. The destination is post-quantum signatures such as ML-DSA and SLH-DSA, finalized in August 2024 and being adopted first for long-lived keys.

The one sentence underneath

Return to that slide at 27C3. Sony's curve was pristine; two signatures gave up the master key [1]. Now line up the rest of the body count. Across three decades, almost no deployed break ever solved an elliptic-curve discrete logarithm or factored a modulus. Attackers reused a nonce, biased one [2], leaked one through timing [26], flipped a signature's s to n - s, or accepted the all-zero signature for any message [4]. The hardness assumption sat untouched through all of it.

That is why "signing done right" is not a single choice but a stack: the right scheme for the job, a nonce you do not have to trust the RNG for, a canonical form, and a byte-exact verifier -- and, the deepest lesson the evolution kept teaching, a preference for schemes where the dangerous case simply cannot be reached, which is what Ed25519 and BIP-340 buy you. Remove any one layer and a surface reopens.

The horizon does not change the shape of the problem, only its arithmetic: post-quantum signatures like ML-DSA and SLH-DSA will hand the same three surfaces to the same callers, at ten to a hundred times the signature size [48]. The nonce, the form, and the verifier will still be where the security lives.

A signature is only as safe as the nonce, the form, and the verifier the scheme hands you. The math held; the interface leaked.

Using a signature safely, in the end, is the discipline of never handing an attacker a value your scheme forgot to own.

Study guide

Key terms

Per-signature nonce
The fresh secret a discrete-log signature draws for each signature; reusing or biasing it leaks the private key.
EUF-CMA
Unforgeability against any new message, even after an adversary obtains signatures on messages of its choice.
SUF-CMA
A stronger goal that also forbids a new signature on an already-signed message; the property malleability violates.
Signature malleability
A second valid signature anyone can derive without the private key, such as the pair with n minus s for ECDSA.
Hidden Number Problem
The lattice problem behind biased-nonce key recovery, and the reason a bias is statistical rather than certain.
Deterministic signing (RFC 6979)
Deriving the nonce from the private key and the message so signing needs no runtime randomness.
Hedged signing
Mixing fresh randomness into a deterministic nonce so the signer survives both RNG failure and fault attacks.
Low-s canonicalization
Requiring the s value to lie in the lower half of its range so only one of the malleable twins is standard.

References

  1. fail0verflow (2010). Console Hacking 2010: PS3 Epic Fail (27C3). https://media.ccc.de/v/27c3-4087-en-console_hacking_2010
  2. Fabian Baeumer & Marcus Brinkmann (2024). CVE-2024-31497: PuTTY ECDSA P-521 Biased Nonce. https://www.openwall.com/lists/oss-security/2024/04/15/6
  3. Pieter Wuille, Jonas Nick, & Tim Ruffing (2020). BIP-340: Schnorr Signatures for secp256k1. https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
  4. National Vulnerability Database (2022). CVE-2022-21449: Psychic Signatures in Java. https://nvd.nist.gov/vuln/detail/CVE-2022-21449
  5. Neil Madden (2022). Psychic Signatures in Java. https://neilmadden.blog/2022/04/19/psychic-signatures-in-java/
  6. Shafi Goldwasser, Silvio Micali, & Ronald L. Rivest (1988). A Digital Signature Scheme Secure Against Adaptive Chosen-Message Attacks. https://doi.org/10.1137/0217017
  7. Don Johnson, Alfred Menezes, & Scott Vanstone (2001). The Elliptic Curve Digital Signature Algorithm (ECDSA). https://doi.org/10.1007/s102070100002
  8. Accredited Standards Committee X9 (1999). ANSI X9.62-1999: Public Key Cryptography for the Financial Services Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA). - Normative ECDSA standard, paywalled; cited via the open Johnson-Menezes-Vanstone description
  9. Whitfield Diffie & Martin E. Hellman (1976). New Directions in Cryptography. https://doi.org/10.1109/TIT.1976.1055638
  10. Ronald L. Rivest, Adi Shamir, & Leonard Adleman (1978). A Method for Obtaining Digital Signatures and Public-Key Cryptosystems. https://doi.org/10.1145/359340.359342
  11. Taher ElGamal (1985). A Public Key Cryptosystem and a Signature Scheme Based on Discrete Logarithms. https://doi.org/10.1109/TIT.1985.1057074
  12. Amos Fiat & Adi Shamir (1986). How to Prove Yourself: Practical Solutions to Identification and Signature Problems. https://doi.org/10.1007/3-540-47721-7_12
  13. Claus-Peter Schnorr (1991). Efficient Signature Generation by Smart Cards. https://doi.org/10.1007/BF00196725
  14. Claus-Peter Schnorr (1991). US Patent 4,995,082: Method for Identifying Subscribers and for Generating and Verifying Electronic Signatures. https://patents.google.com/patent/US4995082A/en
  15. Kathleen Moriarty, Burt Kaliski, Jakob Jonsson, & Andreas Rusch (2016). RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2. https://datatracker.ietf.org/doc/html/rfc8017
  16. Mihir Bellare & Phillip Rogaway (1996). The Exact Security of Digital Signatures: How to Sign with RSA and Rabin. https://doi.org/10.1007/3-540-68339-9_34
  17. Wikipedia contributors (2026). Digital Signature Algorithm. https://en.wikipedia.org/wiki/Digital_Signature_Algorithm
  18. David W. Kravitz (1993). US Patent 5,231,668: Digital Signature Algorithm. https://patents.google.com/patent/US5231668A/en
  19. Bitcoin Project (2013). Android Security Vulnerability. https://bitcoin.org/en/alert/2013-08-11-android
  20. Alex Klyubin (2013). Some SecureRandom Thoughts. https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
  21. Wikipedia contributors (2026). PlayStation 3 Jailbreak. https://en.wikipedia.org/wiki/PlayStation_3_Jailbreak
  22. Dan Boneh & Ramarathnam Venkatesan (1996). Hardness of Computing the Most Significant Bits of Secret Keys in Diffie-Hellman and Related Schemes. https://doi.org/10.1007/3-540-68697-5_11
  23. Nick A. Howgrave-Graham & Nigel P. Smart (2001). Lattice Attacks on Digital Signature Schemes. https://doi.org/10.1023/A:1011214926272
  24. Phong Q. Nguyen & Igor E. Shparlinski (2003). The Insecurity of the Elliptic Curve Digital Signature Algorithm with Partially Known Nonces. https://doi.org/10.1023/A:1025436905711
  25. Diego F. Aranha, Felipe Rodrigues Novaes, Akira Takayasu, Yuval Yarom, & Nicola Tuveri (2020). LadderLeak: Breaking ECDSA with Less than One Bit of Nonce Leakage. https://doi.org/10.1145/3372297.3417268
  26. Jan Jancar, Vladimir Sedlacek, Petr Svenda, & Marek Sys (2019). Minerva: The Curse of ECDSA Nonces. https://minerva.crocs.fi.muni.cz/
  27. Daniel Moghimi, Berk Sunar, Thomas Eisenbarth, & Nadia Heninger (2019). TPM-FAIL: TPM meets Timing and Lattice Attacks. https://tpm.fail/
  28. Thomas Pornin (2013). RFC 6979: Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA). https://datatracker.ietf.org/doc/html/rfc6979
  29. Damian Poddebniak, Juraj Somorovsky, Sebastian Schinzel, Manfred Lochter, & Paul Rosler (2018). Attacking Deterministic Signature Schemes Using Fault Attacks. https://doi.org/10.1109/EuroSP.2018.00031
  30. National Institute of Standards and Technology (2023). FIPS 186-5: Digital Signature Standard (DSS). https://csrc.nist.gov/pubs/fips/186-5/final
  31. The Go Authors (2025). Go Standard Library: crypto/ecdsa (go1.24.0). https://github.com/golang/go/blob/go1.24.0/src/crypto/ecdsa/ecdsa.go
  32. BoringSSL Authors (2026). BoringSSL: ECDSA Nonce Generation (crypto/fipsmodule/ecdsa/ecdsa.cc.inc). https://github.com/google/boringssl/blob/main/crypto/fipsmodule/ecdsa/ecdsa.cc.inc
  33. Diego F. Aranha, Claudio Orlandi, Akira Takahashi, & Greg Zaverucha (2020). Security of Hedged Fiat-Shamir Signatures Under Fault Attacks. https://eprint.iacr.org/2019/956
  34. David Pointcheval & Jacques Stern (2000). Security Arguments for Digital Signatures and Blind Signatures. https://doi.org/10.1007/s001450010003
  35. Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter Schwabe, & Bo-Yin Yang (2011). High-Speed High-Security Signatures. https://doi.org/10.1007/978-3-642-23951-9_9
  36. Simon Josefsson & Ilari Liusvaara (2017). RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA). https://datatracker.ietf.org/doc/html/rfc8032
  37. Bitcoin Optech (2021). Bitcoin Optech Newsletter: Taproot Activated (Block 709,632). https://bitcoinops.org/en/newsletters/2021/11/17/
  38. Eric Rescorla (2018). RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3. https://datatracker.ietf.org/doc/html/rfc8446
  39. Christian Decker & Roger Wattenhofer (2014). Bitcoin Transaction Malleability and MtGox. https://arxiv.org/abs/1403.6676
  40. Pieter Wuille (2014). BIP-62: Dealing with Malleability. https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki
  41. Johnson Lau & Pieter Wuille (2017). BIP-146: Dealing with Signature Encoding Malleability. https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki
  42. Konstantinos Chalkias, Francois Garillot, & Valeria Nikolaenko (2020). Taming the Many EdDSAs. https://eprint.iacr.org/2020/1244
  43. Henry de Valence (2020). ZIP-215: Explicitly Defining and Modifying Ed25519 Validation Rules. https://zips.z.cash/zip-0215
  44. Daniel J. Bernstein & Tanja Lange (2026). eBACS: ECRYPT Benchmarking of Cryptographic Systems (results-sign). https://bench.cr.yp.to/results-sign.html
  45. Trevor Perrin (2016). The XEdDSA and VXEdDSA Signature Schemes. https://signal.org/docs/specifications/xeddsa/
  46. Jonas Nick, Tim Ruffing, & Yannick Seurin (2021). MuSig2: Simple Two-Round Schnorr Multi-Signatures. https://doi.org/10.1007/978-3-030-84242-0_8
  47. Deirdre Connolly, Chelsea Komlo, Ian Goldberg, & Christopher A. Wood (2024). RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol. https://datatracker.ietf.org/doc/html/rfc9591
  48. National Institute of Standards and Technology (2024). FIPS 204: Module-Lattice-Based Digital Signature Standard (ML-DSA). https://csrc.nist.gov/pubs/fips/204/final
  49. National Institute of Standards and Technology (2024). FIPS 205: Stateless Hash-Based Digital Signature Standard (SLH-DSA). https://csrc.nist.gov/pubs/fips/205/final
  50. Yannick Seurin (2012). On the Exact Security of Schnorr-Type Signatures in the Random Oracle Model. https://doi.org/10.1007/978-3-642-29011-4_33
  51. Eike Kiltz, Daniel Masny, & Jiaxin Pan (2016). Optimal Security Proofs for Signatures from Identification Schemes. https://eprint.iacr.org/2016/191
  52. Manuel Fersch, Eike Kiltz, & Bertram Poettering (2016). On the Provable Security of (EC)DSA Signatures. https://doi.org/10.1145/2976749.2978413
  53. Peter W. Shor (1997). Polynomial-Time Algorithms for Prime Factorization and Discrete Logarithms on a Quantum Computer. https://doi.org/10.1137/S0097539795293172