Skip to content
ecdsa.com

ECDSA vs Schnorr signatures: what Taproot changed

Schnorr is the older, simpler and more provable design; ECDSA exists largely because of a patent. BIP-340 brought Schnorr to Bitcoin in 2021, and EdDSA brought it everywhere else.

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 equations = k⁻¹·(z + r·d) mod ns = k + e·d mod n, e = H(R ‖ P ‖ m)
Public key33 bytes compressed (65 uncompressed)32 bytes, x-only
Signature64 bytes compact; 70–72 bytes DER in Bitcoin scripts64 bytes
Malleability(r, n − s) also valid; Bitcoin enforces low-SNone with BIP-340 verification
Public key recoveryPossible (Ethereum's ecrecover)Not possible
Key aggregationNeeds multi-party computation protocolsNative (MuSig2, BIP-327)
Threshold signingComplex protocols (GG18/20, CGGMP)FROST (RFC 9591)
Batch verificationNoYes
Security proofGeneric group model onlyRandom oracle model, discrete log
StandardsFIPS 186-5, SEC 1BIP-340; EdDSA (RFC 8032) is a Schnorr variant
Used byBitcoin legacy and SegWit v0, Ethereum, most EVM chainsBitcoin 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 k breaks 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 e hashes 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.

@noble/curves: ECDSA and BIP-340 Schnorr with one secp256k1 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));
Output
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, ecrecover and 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.

  1. Upgrade wallet software and hardware to versions that support Taproot (BIP-86 derivation path m/86'/0'/0') and PSBT Taproot fields.
  2. 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.
  3. Switch message signing to BIP-322 so Taproot addresses can prove ownership.
  4. For multisig, decide between MuSig2 key-path aggregation (most private and cheapest, but interactive) and Tapscript OP_CHECKSIGADD script paths (non-interactive, reveals the policy when used).
  5. Keep verifying ECDSA for older outputs; consensus rules support both indefinitely.

References

All comparisons