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
👉 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.
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:
- Compute (t): XOR the private key (d) with a tagged hash of auxiliary random data.
- Generate a random value (rand) using the public key, message, and auxiliary data.
- 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:
- The signature is valid.
- The message was signed by Alice.
- 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
👉 Decoding Bitcoin - Schnorr Signature