freecoding.school100% FREE · NO SIGNUP
Proof PeaksISSUE #5 of 38

schnorr signatures · linearity · musig2

ZeekaVSThe Collision
Zeeka saysSchnorr signatures are linear and simple: a commitment, a challenge, a response — verified by one group equation. That linearity is what enables MuSig key aggregation.

Schnorr is the clean cousin of ECDSA. To sign: pick a random nonce k, publish the commitment R = g^k, compute the challenge e = H(R, m), and answer with s = k + e·x where x is the secret key. Verification is one line: g^s == R · y^e. No malleability, smaller than ECDSA, and — crucially — linear, so multiple signers can combine their pieces into a single signature (MuSig2).

The one rule you cannot break: never reuse or leak a nonce. Two signatures with the same k expose the private key via simple algebra. Bitcoin enabled Schnorr through the Taproot upgrade, unlocking compact multisig that looks identical to a single-key spend on-chain. The demo signs and verifies over a real order-11 subgroup of GF(23).

Power-ups you unlock

The Collision attacks — common mistakes

Boss battleSign a message with Schnorr over GF(23) (the order-11 subgroup) and verify g^s == R · y^e.

Example code

<!doctype html><html><head><meta charset="utf-8"></head>
<body style="background:#06040d;color:#e6e0ff;font-family:monospace;padding:20px"><pre id="o"></pre>
<script>
// REAL Schnorr over a small prime-order group (toy scale, exact math).
const p = 23, q = 11, g = 2;                       // g has order q=11 in GF(23)*
const pw=(a,e,m)=>{ let r=1; a%=m; while(e>0){ if(e&1) r=(r*a)%m; a=(a*a)%m; e>>=1; } return r; };
const H = (R,m)=> (R*7 + m*13) % q;                // toy hash → exponent mod q
const x = 6, y = pw(g, x, p);                      // secret key x, public key y = g^x
const m = 4, k = 9;                                // message, nonce
const R = pw(g, k, p);
const e = H(R, m);
const s = (k + e * x) % q;                         // s = k + e·x  (mod q)
const lhs = pw(g, s, p), rhs = (R * pw(y, e, p)) % p;
document.getElementById('o').textContent = [
  'Schnorr over GF(23), subgroup order 11',
  'pubkey y = g^x = ' + y,
  'sig (R, s) = (' + R + ', ' + s + ')   e = H(R,m) = ' + e,
  'verify  g^s = ' + lhs + '   R·y^e = ' + rhs,
  'valid? ' + (lhs === rhs)
].join('\n');
</script></body></html>
▶ Open the interactive comic issue
‹ Bls Signatures · Aggregation · Validator KeysThreshold Signatures · T-Of-N Signing ›