ECDSA vs Schnorr is mostly a Bitcoin question today, because Taproot (BIPs 340–342, activated in November 2021) added Schnorr signatures next to ECDSA on the same curve, secp256k1. The two schemes use the same keys and the same hard problem, but Schnorr's linear structure makes multi-signatures, threshold signing and batch verification natural, while ECDSA's structure makes them awkward.
At a glance
| ECDSA (secp256k1) | Schnorr (BIP-340, secp256k1) | |
|---|---|---|
| Signing equation | s = k⁻¹·(z + r·d) mod n | s = k + e·d mod n, e = H(R ‖ P ‖ m) |
| Public key | 33 bytes compressed (65 uncompressed) | 32 bytes, x-only |
| Signature | 64 bytes compact; 70–72 bytes DER in Bitcoin scripts | 64 bytes |
| Malleability | (r, n − s) also valid; Bitcoin enforces low-S | None with BIP-340 verification |
| Public key recovery | Possible (Ethereum's ecrecover) | Not possible |
| Key aggregation | Needs multi-party computation protocols | Native (MuSig2, BIP-327) |
| Threshold signing | Complex protocols (GG18/20, CGGMP) | FROST (RFC 9591) |
| Batch verification | No | Yes |
| Security proof | Generic group model only | Random oracle model, discrete log |
| Standards | FIPS 186-5, SEC 1 | BIP-340; EdDSA (RFC 8032) is a Schnorr variant |
| Used by | Bitcoin legacy and SegWit v0, Ethereum, most EVM chains | Bitcoin Taproot, Nostr, FROST deployments |
How they differ
Both sign with a secret nonce k and its point R = k·G. ECDSA mixes the hash z, the private key d and r (the x-coordinate of R) through a modular inverse of k. Schnorr instead hashes the commitment, the public key and the message into a challenge e and responds with s = k + e·d, which the verifier checks as s·G = R + e·P.
That one design choice drives everything else:
- Linearity. Schnorr signatures add up. Several signers can combine nonces and partial responses into one signature that verifies under the sum of their keys. MuSig2 (BIP-327) does this in two rounds for n-of-n signing; FROST (RFC 9591) does t-of-n threshold signing. With ECDSA the inverse of
kbreaks linearity, so threshold ECDSA requires heavy multi-party protocols, which wallets and custodians use but which have had serious bugs. - Batch verification. Many Schnorr signatures can be checked together faster than one by one, which matters for block validation. ECDSA has no such shortcut.
- Key commitment. Because
ehashes the public key, a Schnorr signature cannot be reused under a different key, and the key cannot be recovered from the signature. ECDSA allows public key recovery, which Ethereum depends on to save bytes; with Schnorr you must transmit or know the key. - Malleability. ECDSA's
(r, s)and(r, n − s)both verify, so Bitcoin enforces low-S and strict DER. BIP-340 fixes one encoding, so third parties cannot change a valid signature. - History. Claus Schnorr's 1989 scheme was patented, and DSA (and later ECDSA) was designed to avoid the patent; it expired in 2008, after ECDSA was entrenched. EdDSA (2011) is a deterministic Schnorr variant on Edwards curves.
What Taproot changed in practice
A Taproot output commits to a single 32-byte x-only key. Spending by key path needs one 64-byte Schnorr signature, whether that key belongs to one person or is a MuSig2 aggregate of several, so a 2-of-2 or 3-of-3 multisig spend looks like any single-signature spend on chain. Alternative spending conditions sit in a Merkle tree of scripts that is revealed only when used. The SegWit v0 equivalent of a single-key spend carries a DER ECDSA signature of up to 72 bytes plus a sighash byte and a 33-byte public key in the witness.
The script below, run with @noble/curves 2.3.0 on Node.js 26.10, shows the size difference for the same secret key.
import { secp256k1, schnorr } from "@noble/curves/secp256k1.js";
import { sha256 } from "@noble/hashes/sha2.js";
import { utf8ToBytes } from "@noble/hashes/utils.js";
const secretKey = secp256k1.utils.randomSecretKey();
const msg = sha256(utf8ToBytes("pay 0.01 BTC to bc1p..."));
// ECDSA: 33-byte compressed public key, 64-byte compact (r, s) signature.
const ecdsaPub = secp256k1.getPublicKey(secretKey, true);
const ecdsaSig = secp256k1.sign(msg, secretKey, { prehash: false });
// BIP-340 Schnorr: 32-byte x-only public key, 64-byte (R.x, s) signature.
const schnorrPub = schnorr.getPublicKey(secretKey);
const schnorrSig = schnorr.sign(msg, secretKey);
console.log("ECDSA public key:", ecdsaPub.length, "bytes, signature:", ecdsaSig.length, "bytes, valid:", secp256k1.verify(ecdsaSig, msg, ecdsaPub, { prehash: false }));
console.log("Schnorr public key:", schnorrPub.length, "bytes, signature:", schnorrSig.length, "bytes, valid:", schnorr.verify(schnorrSig, msg, schnorrPub));
ECDSA public key: 33 bytes, signature: 64 bytes, valid: true
Schnorr public key: 32 bytes, signature: 64 bytes, valid: true
The compact ECDSA form is 64 bytes too, but Bitcoin scripts carry ECDSA in DER, and Ethereum adds a recovery byte; the Schnorr form is what goes on chain as is.
Shared pitfalls
Neither scheme forgives a bad nonce: reusing k for two messages, or leaking a few bits of it repeatedly, reveals the private key in both. BIP-340 recommends deriving the nonce from the key and message mixed with 32 bytes of fresh auxiliary randomness. Multi-party Schnorr adds a new rule: MuSig2 nonces must never be derived deterministically from the message alone, because an attacker who controls another participant can make the same nonce sign two different aggregate challenges. Use audited implementations such as libsecp256k1's MuSig2 module rather than composing primitives yourself.
When to choose which
- New Bitcoin wallets and outputs: Taproot key-path spends with Schnorr; MuSig2 for multi-party keys where the participants can coordinate, script paths for fallbacks.
- Bitcoin message signing: BIP-322 for Taproot addresses, since the older BIP-137 format only knows ECDSA.
- Ethereum and EVM chains: ECDSA, because transactions,
ecrecoverand wallets expect it; smart accounts can verify other schemes in contract code. - Nostr: BIP-340 Schnorr, as NIP-01 requires.
- Threshold custody: FROST where verifiers accept Schnorr or EdDSA signatures; threshold ECDSA only where the target chain requires ECDSA.
- Non-blockchain systems: Ed25519 gives you the Schnorr design with a standard (RFC 8032), library support and deterministic nonces.
Migration notes
On Bitcoin, the same secret key can produce both kinds of signature, but outputs determine what is required: moving funds from P2WPKH or P2PKH outputs to P2TR outputs is the migration.
- Upgrade wallet software and hardware to versions that support Taproot (BIP-86 derivation path
m/86'/0'/0') and PSBT Taproot fields. - Use x-only keys correctly: BIP-340 keys drop the parity byte, and keys are tweaked with the script tree commitment; do not reuse ECDSA public key encodings.
- Switch message signing to BIP-322 so Taproot addresses can prove ownership.
- For multisig, decide between MuSig2 key-path aggregation (most private and cheapest, but interactive) and Tapscript
OP_CHECKSIGADDscript paths (non-interactive, reveals the policy when used). - Keep verifying ECDSA for older outputs; consensus rules support both indefinitely.