pull down to refresh

Hands-On Schnorr: Sign and Verify Bitcoin Transactions


For a full hands-on experience, including the code to generate and verify Schnorr signatures, check the complete content and source code here:
👉 Decoding Bitcoin - Schnorr Signature

We have two main characters to help us understand how Schnorr signatures work:
Alice (The signer): wants to sign a message using Schnorr and send it to Bob.
Bob (The verifier): wants to verify that the message is truly signed and comes from Alice.

The interaction between Alice and Bob involves two key steps: Signature Generation and Signature Verification.

Signature Generation (Alice)

Step 1: Generate Key Pair (d, P)

Alice generates a private key (d), then calculates her public key (P) by multiplying her private key with the generator point (G):
P = d × G

Step 2: Generate Nonce and Nonce Commitment (k, R)

The nonce (k) is a random value Alice generates during the signature process. The Nonce Commitment (R) is then calculated as:
R = k × G
Why do we need a nonce?
The nonce ensures that even if Alice signs the same message multiple times, each signature will be unique. This prevents attackers from reverse-engineering Alice’s private key.
Note: In Taproot, BIP340 requires that the (y)-coordinate of (R) is even.

Step 3: Challenge Computation (h)

Alice computes the challenge hash (h) using:
h = H(R || P || message)
Where:
  • (R): Nonce commitment
  • (P): Alice's public key
  • (message): The signed message

Step 4: Challenge Response (s)

Alice calculates the challenge response (s) as:
s = k + h × d
Where:
  • (k): The nonce
  • (h): The challenge hash
  • (d): Alice’s private key

Step 5: Create the Signature

The final signature is the pair ((R, s)). Alice sends the message and the signature ((R, s)) to Bob.

Nonce Generation for Schnorr Signatures

Nonce generation is critical for security. If the randomness of (k) is compromised, the private key can be revealed.
BIP340 recommends a deterministic method for generating nonces:
  1. Compute (t): XOR the private key (d) with a tagged hash of auxiliary random data.
  2. Generate a random value (rand) using the public key, message, and auxiliary data.
  3. Calculate (k): (k = rand \mod n), where (n) is the curve order.

Verification Process (Bob)

Bob verifies the signature by checking the following equation:
s × G = R + h × P
Where:
  • (s): Challenge response from Alice
  • (G): Generator point (constant)
  • (R): Nonce commitment from the signature
  • (h): Bob computes (h = H(R || P || message))
  • (P): Alice’s public key
If the equation holds, Bob can be confident that:
  1. The signature is valid.
  2. The message was signed by Alice.
  3. The message has not been tampered with.

Hands-On Practice

For a full hands-on experience, including the code to generate and verify Schnorr signatures, check the complete content and source code here:
👉 Decoding Bitcoin - Schnorr Signature