Chapter 10 // Protocols

Digital
Signatures

Encryption from Chapter 9 lets you send secrets. But it does not prove who sent them. Anyone with Bob's public key can encrypt a message pretending to be Alice. Digital signatures solve this: the signer's private key creates a proof that anyone with the public key can verify, but nobody can forge.

Scroll to explore
01 // The Problem

Who sent this?

Encryption ensures only the intended recipient can read a message. But it says nothing about the sender. Alice can encrypt a message to Bob, and so can Eve. Bob has no way to tell them apart.

The authentication gap

Asymmetric encryption from Chapter 9 provides confidentiality. Bob decrypts a message and reads it. But nothing in the ciphertext proves Alice wrote it. Eve could have encrypted the same message with Bob's public key, and Bob would have no way to distinguish the two.

MACs from Chapter 3 solved the authentication problem for shared-key settings. If Alice and Bob share a secret key, a MAC proves the message came from someone who knows that key. But MACs have a fundamental limitation: both sides hold the same secret. Both can create and verify tags. There is no way for a third party to confirm who actually authored the message.

From MACs to signatures

Digital signatures use asymmetric keys to solve this. Only the signer can create a signature (private key), but anyone can verify it (public key). If Alice signs a contract, Bob can prove to Charlie that Alice signed it. Alice cannot deny having signed it, because only her private key could have produced that signature.

This property is called non-repudiation. It is something MACs cannot provide, because both parties hold the shared key. With MACs, Bob could have forged the tag himself. With signatures, only Alice's private key could have produced the proof.

Signatures are the mirror image of encryption. In encryption, the public key locks and the private key unlocks. In signatures, the private key signs and the public key verifies. Same key pair, opposite directions.

02 // The Concept

Signing and verifying

A signature is a value computed from a message and a private key. Anyone with the corresponding public key can verify the signature is genuine. No one without the private key can produce a valid signature.

Private key = your pen

Only Alice has her private key. The signature she produces is mathematically bound to both the message and her key. Nobody else can create it.

Public key = your identity

Bob, Charlie, anyone can verify Alice's signature using her public key. The verification is a mathematical check, not a secret.

Tamper-evident seal

Change even one bit of the message, and the signature no longer verifies. Signatures bind the signer's identity to the exact content.

Signatures give you two guarantees at once: authentication (the signer has the private key) and integrity (the message has not been modified). Combined with encryption, you get confidentiality, integrity, and authentication.

03 // Hash-Then-Sign

Why sign a hash, not the message

RSA signatures operate on numbers smaller than the modulus. A real message might be megabytes. The solution: hash the message first, then sign the fixed-length digest.

The size problem

RSA can only operate on values smaller than nn (typically 256 bytes for a 2048-bit key). You cannot sign a 10 MB file directly. Even for elliptic curve schemes, the input must be a fixed-size scalar.

The solution is the hash-then-sign paradigm. Hash the message with SHA-256 to get a 32-byte digest. Sign the digest. To verify: hash the received message, then check the signature against that hash. If the signature matches, the message is authentic.

The equations

Sign: σ=Signsk(SHA-256(m))\text{Sign: } \sigma = \text{Sign}_{sk}(\text{SHA-256}(m))
Verify: Verifypk(σ,m)σ matches SHA-256(m)\text{Verify: } \text{Verify}_{pk}(\sigma, m) \Leftrightarrow \sigma \text{ matches } \text{SHA-256}(m)

Because the hash function is collision-resistant (Chapter 2), finding a different message with the same hash is infeasible. A signature on the hash is as good as a signature on the full message.

Hash, Then Sign

Watch the two-step process: first hash the message to a fixed-length digest, then sign the digest.

Message: 38 bytesHash: 32 bytes
Step 1: SHA-256 Hash
Step 2: ECDSA Signature
04 // RSA Signatures

The first digital signature

RSA signatures use the same math as RSA encryption, but in reverse. The private key exponent signs, the public key exponent verifies. Walk through the process with small numbers.

Sign with private key
σ=H(m)dmodn{\color{#8b5cf6}\sigma} = H(m)^{\color{#ef4444}d} \bmod n
Verify with public key
H(m)=?σemodnH(m) \stackrel{?}{=} {\color{#8b5cf6}\sigma}^{\color{#00e5a0}e} \bmod n

Why it works

The signer raises the hash to the private exponent d{\color{#ef4444}d}. The verifier raises the signature to the public exponent e{\color{#00e5a0}e}. If the result equals the hash, the signature is valid. This works because of the same RSA identity from Chapter 9:

σe=(H(m)d)e=H(m)deH(m)(modn)\sigma^e = (H(m)^d)^e = H(m)^{d \cdot e} \equiv H(m) \pmod{n}

RSA Signatures with Small Numbers

Walk through RSA signing step by step. Choose primes, build a key pair, sign a number, and verify the signature.

Choose prime p
Choose prime q
1
Multiply the primes to get the modulus
n=p×q=61×53=3233n = p \times q = {\color{#8b5cf6}61} \times {\color{#f59e0b}53} = 3233
2
Compute the totient (how many numbers are coprime to n)
3
Pick public exponent e, coprime to ϕ(n)\phi(n)
4
Compute private exponent d, the modular inverse of e

Just like RSA encryption, textbook RSA signatures need padding to be secure. RSASSA-PKCS#1 v1.5 adds deterministic padding. RSA-PSS adds randomized padding for stronger security guarantees. Never implement textbook RSA signatures in production.

05 // Real Signatures

RSA-PSS in the browser

The demo above used tiny primes. Real RSA signatures use 2048-bit keys and PSS padding. Try signing a message with the Web Crypto API, then modify it and watch verification fail.

PSS adds randomness

RSA-PSS includes random salt in the padding. The same message produces a different signature each time, preventing certain attacks on deterministic schemes.

Signature = key size

An RSA-2048 signature is always 256 bytes. An RSA-4096 signature is 512 bytes. The signature size depends only on the key, not on the message.

Sign and Verify

Sign a message with RSA-PSS 2048-bit. Then modify the received message and try to verify. Any change invalidates the signature.

06 // ECDSA

Smaller, faster

Elliptic Curve Digital Signature Algorithm uses the same curve math from Chapter 8. A P-256 signature is 64 bytes instead of 256 for RSA-2048, with equivalent security. ECDSA powers most TLS certificates today.

How ECDSA works

The signer has a private key scalar d{\color{#8b5cf6}d} and a public key point Q=dG{\color{#f59e0b}Q} = d \cdot G. To sign a message:

1. Hash the message: h=SHA-256(m)h = \text{SHA-256}(m)

2. Pick a random per-signature nonce k{\color{#00e5a0}k}

3. Compute the curve point R=kGR = {\color{#00e5a0}k} \cdot G, take r=Rxmodnr = R_x \bmod n

4. Compute s=k1(h+rd)modns = {\color{#00e5a0}k}^{-1}(h + r \cdot {\color{#8b5cf6}d}) \bmod n

5. The signature is the pair (r,s)(r, s)

R=kG,r=Rxmodn,s=k1(h+rd)modnR = {\color{#00e5a0}k} \cdot G, \quad r = R_x \bmod n, \quad s = {\color{#00e5a0}k}^{-1}(h + r \cdot {\color{#8b5cf6}d}) \bmod n

The nonce is critical

If the per-signature nonce k{\color{#00e5a0}k}is reused or predictable, the private key can be recovered. This is exactly what happened to Sony's PlayStation 3 ECDSA implementation in 2010: they used the same kk for every signature, and hackers extracted the private key from two signatures.

The math is straightforward. Given two signatures (r,s1)(r, s_1) and (r,s2)(r, s_2) on different messages (same rr because same kk):

k=h1h2s1s2modnd=s1kh1rmodn{\color{#00e5a0}k} = \frac{h_1 - h_2}{s_1 - s_2} \bmod n \quad \Rightarrow \quad {\color{#8b5cf6}d} = \frac{s_1 \cdot {\color{#00e5a0}k} - h_1}{r} \bmod n

Once k{\color{#00e5a0}k} is known, recovering the private key d{\color{#8b5cf6}d} is just arithmetic. A single reused nonce compromises the key forever.

ECDSA is the most widely deployed signature algorithm. Bitcoin uses it (secp256k1). TLS certificates use it (P-256). But its reliance on a random nonce per signature is a source of implementation risk. This is the problem Schnorr and EdDSA solve.

07 // Schnorr & Ed25519

From elegant math to modern standard

The Schnorr signature scheme is the simplest discrete-log-based signature. Ed25519 is its modern instantiation on Curve25519, with deterministic nonces that eliminate the ECDSA nonce problem entirely.

The Schnorr protocol

Alice has private key x{\color{#8b5cf6}x} and public key P=xG{\color{#f59e0b}P} = x \cdot G. To sign a message mm:

1
Commit

Pick a random nonce kk, compute the commitment point R=kG{\color{#00e5a0}R} = k \cdot G.

2
Challenge

Hash the commitment, public key, and message together: e=H(RPm)e = H({\color{#00e5a0}R} \| {\color{#f59e0b}P} \| m).

3
Response

Compute s=k+exmodns = k + e \cdot {\color{#8b5cf6}x} \bmod n. The signature is (R,s)({\color{#00e5a0}R}, s).

Verify: sG=?R+eP\text{Verify: } s \cdot G \stackrel{?}{=} {\color{#00e5a0}R} + e \cdot {\color{#f59e0b}P}

Verification works because sG=(k+ex)G=kG+exG=R+ePs \cdot G = (k + e \cdot x) \cdot G = k \cdot G + e \cdot x \cdot G = R + e \cdot P.

Why Schnorr matters

The response equation s=k+exs = k + e \cdot x is linear. This seemingly simple property has profound consequences. If Alice and Bob both produce Schnorr signatures on the same message, their signatures can be added together to form a single valid multi-signature. The combined signature is the same size as a single one.

This linearity makes multi-signatures, threshold signatures, and adaptor signatures possible. ECDSA does not have this property because its equation involves k1k^{-1}, which breaks linearity.

Ed25519: Schnorr on a modern curve

Ed25519 is a Schnorr signature scheme instantiated on Curve25519 (in twisted Edwards form). Its critical improvement over classical Schnorr: the nonce is derived deterministically as a hash of the private key and message, not picked randomly.

k=H(prefixm)k = H(\text{prefix} \| m)

No random number generator is involved in signing. Different messages produce different nonces by construction. Nonce reuse is impossible.

Ed25519 parameters
CurveCurve25519 (Edwards)
Security level~128 bits
Private key32 bytes
Public key32 bytes
Signature64 bytes
Why Ed25519 over ECDSA

Deterministic: No RNG in signing. No nonce-reuse risk.

Faster: Edwards curves allow constant-time arithmetic optimized for speed.

Simpler: Fewer implementation choices, fewer ways to get it wrong.

Smaller: 32-byte keys vs 33-byte compressed ECDSA keys.

Signature Algorithm Showdown

The same message, three algorithms. Compare key sizes, signature sizes, and speed.

Schnorr patented his scheme in 1989 (US Patent 4,995,082). The patent expired in 2008. During those 19 years, ECDSA was designed specifically to work around the patent. After it expired, Dan Bernstein designed Ed25519 (2011) for Curve25519, optimized for security, performance, and resistance to side-channel attacks. It has since become the recommended signature scheme for new systems, and powers Bitcoin's Taproot (BIP-340) and many modern protocols.

08 // The Attacks

What can go wrong

Digital signature schemes are mathematically sound. But implementation mistakes, nonce reuse, and malleability can break them in practice.

Signature malleability

Given a valid ECDSA signature (r,s)(r, s), the pair (r,ns)(r, n - s) is also a valid signature on the same message. This does not break authentication, but it can break systems that use the signature as a unique identifier.

Bitcoin experienced this firsthand. Before the SegWit upgrade, transaction IDs were computed from the full transaction including the signature. An attacker could take a valid transaction, replace ss with nsn - s, and create a different transaction ID for the same payment. This “transaction malleability” caused real losses.

Tamper Detection

A signed message arrives. Try these attacks and see what happens.

Preparing...

Ed25519 solves the nonce-reuse problem by design. RSA-PSS is resistant to malleability. When choosing a signature algorithm, the question is not just “is the math secure?” but “how hard is it to use correctly?”

09 // Real-World Usage

Signatures everywhere

Digital signatures are one of the most widely deployed cryptographic primitives. Every HTTPS connection, every software update, every cryptocurrency transaction relies on them.

Where signatures appear

TLS certificates. Every HTTPS certificate is signed by a certificate authority. Your browser verifies the CA's signature to trust the server's public key. This chain of trust is the subject of Chapter 11.

Code signing. Operating systems verify cryptographic signatures on software updates and applications. Apple, Microsoft, and Linux distributions all sign their packages. An unsigned or incorrectly signed binary is rejected.

Git commits. Git supports GPG and SSH signatures on commits and tags. GitHub shows a “Verified” badge on signed commits. This proves the commit was created by the key holder.

JWT (JSON Web Tokens). JWTs used in web authentication are signed with HMAC (symmetric) or RSA/ECDSA (asymmetric). The signature ensures the token has not been tampered with and was issued by the expected server.

Blockchain. Every Bitcoin or Ethereum transaction is signed with the sender's private key. The network verifies the signature before accepting the transaction. No valid signature, no transfer.

Signatures in the Wild

Digital signatures appear in protocols you use every day. Examine their structure.

Header
{
  "alg": "ES256",
  "typ": "JWT"
}
Payload
{
  "sub": "alice@example.com",
  "iat": 1711929600,
  "exp": 1712016000,
  "role": ""
}
Signature
Generating...
Computed over: base64url(header).base64url(payload)
Full JWT
..
10 // Best Practices

Using digital signatures correctly

Digital signatures are powerful but require careful implementation. These guidelines reflect how modern systems use them safely.

🛡️

Prefer Ed25519

Ed25519 is faster, has smaller signatures, and eliminates nonce-reuse risk through deterministic signing. Unless you need compatibility with existing ECDSA systems, Ed25519 is the default choice for new projects.

🔐

Always Hash-Then-Sign

Never sign raw messages. Always hash the message with SHA-256 (or the hash built into the scheme) before signing. This is handled automatically by Web Crypto and all reputable libraries, but matters if you build from primitives.

Use PSS for RSA Signatures

RSA-PSS with SHA-256 is the recommended RSA signature padding. PKCS#1 v1.5 signatures are still widely used and not broken the way PKCS#1 v1.5 encryption padding is, but PSS provides stronger security proofs.

🚫

Never Reuse ECDSA Nonces

A single reused nonce in ECDSA leaks the private key. Use a cryptographically secure random number generator, or better yet, use EdDSA which derives nonces deterministically and cannot suffer from this attack.

Digital signatures solve the authentication problem for public-key cryptography. But one question remains: how do you know the public key you are verifying against actually belongs to Alice and not Eve? That is the problem of trust and public key infrastructure, the subject of Chapter 11.

11 // What You Learned

From encryption to authentication

This chapter introduced digital signatures: the ability to prove authorship of a message using a private key, in a way that anyone with the public key can verify. Combined with encryption from Chapter 9, you now have confidentiality, integrity, and authentication.

The story so far

Digital signatures solve the authentication problem. The private key creates a proof that anyone with the public key can verify, but nobody can forge. Unlike MACs, signatures provide non-repudiation.

Hash-then-sign makes signatures practical. Hash the message to a fixed-size digest, sign the digest. The collision resistance of the hash function guarantees this is as secure as signing the full message.

RSA signatures were the first practical scheme. Sign with private exponent dd, verify with public exponent ee. PSS padding provides the strongest security guarantees.

ECDSA provides equivalent security with much smaller signatures (64 bytes vs 256 bytes for RSA-2048). It powers most TLS certificates and blockchain transactions. But it requires a fresh random nonce per signature, and nonce reuse is catastrophic.

Schnorr signatures are the simplest discrete-log scheme. Their linear structure enables multi-signatures. Ed25519 is Schnorr on Curve25519, with deterministic nonces that eliminate the most dangerous implementation pitfall. Faster, simpler, and harder to misuse than ECDSA. The recommended choice for new systems.

You can now sign and verify messages. But verification only works if you trust the public key. How do you know a public key belongs to Alice and not to an attacker? Binding identities to public keys through certificates and chains of trust is the subject of Chapter 11.

Up Next

Chapter 11 // Trust and PKI

Continue Learning