Greenpaper SPV Implementation Guide
The original can be found at Zenon Developer Commons .
ZENON GREENPAPER SPV IMPLEMENTATION GUIDE
Practical Companion for Builders
Status: Exploratory / Research Draft
Purpose
This guide provides a practical, builder-oriented companion to the Zenon Greenpaper’s SPV sections. It bridges the gap between theoretical feasibility and actual implementation by offering concrete specifications, code patterns, and decision frameworks.
Audience: Developers implementing Bitcoin SPV verification on Zenon
Prerequisites: Understanding of Bitcoin SPV basics, Zenon account-chain model
1. What You’re Building
The Core Function
VerifySPV(proof) -> bool
Input: SPV proof package (headers, merkle branch, tx hash)
Output: true if tx is validly included, false otherwiseWhat This Proves
A successful verification proves:
- Transaction was included in a Bitcoin block
- Block has valid proof-of-work
- Block is part of a chain with specified cumulative work
- Transaction has at least N confirmations
What This Does NOT Prove
- Transaction script executed correctly
- Transaction is on the current canonical Bitcoin chain
- Transaction will remain confirmed (finality is probabilistic)
2. Data Structures
Bitcoin Header (80 bytes)
type BitcoinHeader struct {
Version uint32 // 4 bytes, little-endian
PrevBlock [32]byte // 32 bytes
MerkleRoot [32]byte // 32 bytes
Timestamp uint32 // 4 bytes, little-endian
Bits uint32 // 4 bytes, little-endian (difficulty target)
Nonce uint32 // 4 bytes, little-endian
}Merkle Branch
type MerkleBranch struct {
Siblings [][32]byte // Sibling hashes at each level
Positions []uint8 // 0 = sibling on left, 1 = sibling on right
}SPV Proof Package
type SPVProof struct {
Headers []BitcoinHeader // Chain of headers (oldest first)
TxHash [32]byte // Transaction to verify
MerkleBranch MerkleBranch // Inclusion proof
BlockIndex uint16 // Which header contains the tx
}3. Verification Algorithm
Step 1: Validate Header Chain
func ValidateHeaderChain(headers []BitcoinHeader) error {
for i := 1; i < len(headers); i++ {
prevHash := DoubleSHA256(headers[i-1])
if headers[i].PrevBlock != prevHash {
return ErrBrokenChain
}
}
return nil
}Step 2: Verify Proof-of-Work
func VerifyPoW(header BitcoinHeader) error {
hash := DoubleSHA256(header)
target := BitsToTarget(header.Bits)
if BytesToBigInt(hash) > target {
return ErrInvalidPoW
}
return nil
}Step 3: Verify Merkle Inclusion
func VerifyMerkle(txHash [32]byte, root [32]byte, branch MerkleBranch) error {
current := txHash
for i, sibling := range branch.Siblings {
if branch.Positions[i] == 0 {
// Sibling on left
current = DoubleSHA256(concat(sibling, current))
} else {
// Sibling on right
current = DoubleSHA256(concat(current, sibling))
}
}
if current != root {
return ErrMerkleMismatch
}
return nil
}Step 4: Combined Verification
func VerifySPV(proof SPVProof, minDepth int) error {
// Check we have enough headers for depth
if len(proof.Headers) - proof.BlockIndex - 1 < minDepth {
return ErrInsufficientDepth
}
// Validate chain linkage
if err := ValidateHeaderChain(proof.Headers); err != nil {
return err
}
// Verify PoW for all headers
for _, h := range proof.Headers {
if err := VerifyPoW(h); err != nil {
return err
}
}
// Verify Merkle inclusion
targetHeader := proof.Headers[proof.BlockIndex]
if err := VerifyMerkle(proof.TxHash, targetHeader.MerkleRoot, proof.MerkleBranch); err != nil {
return err
}
return nil // Verification successful
}4. Critical Implementation Details
Double SHA256
Bitcoin uses SHA256(SHA256(data)) throughout. Don’t forget the double hash.
func DoubleSHA256(data []byte) [32]byte {
first := sha256.Sum256(data)
return sha256.Sum256(first[:])
}Endianness
Bitcoin uses little-endian for most values. Be careful when:
- Parsing header fields
- Comparing hashes (treated as big integers)
- Displaying hashes (usually shown big-endian)
Bits to Target Conversion
func BitsToTarget(bits uint32) *big.Int {
exponent := bits >> 24
mantissa := bits & 0x007fffff
target := big.NewInt(int64(mantissa))
target.Lsh(target, uint(8*(exponent-3)))
return target
}5. Recommended Defaults
Confirmation Depth
| Use Case | Recommended Depth | Rationale |
|---|---|---|
| Low value | 1-3 | Fast, acceptable risk |
| Medium value | 6 | Bitcoin standard |
| High value | 12+ | Extra security |
| Critical | 100+ | Near-final |
Header Chain Length
Minimum: depth + 1 (tx block + confirmations) Recommended: depth + 6 (buffer for tip changes)
Proof Size Limits
- Max headers: 2016 (one difficulty period)
- Max Merkle depth: 14 (covers ~16,000 tx/block)
6. Error Handling
Error Types
var (
ErrInsufficientDepth = errors.New("not enough confirmations")
ErrBrokenChain = errors.New("header chain broken")
ErrInvalidPoW = errors.New("proof-of-work invalid")
ErrMerkleMismatch = errors.New("merkle root mismatch")
ErrInvalidProofSize = errors.New("proof exceeds size limits")
)Handling Failures
- ErrInsufficientDepth: Wait for more blocks, resubmit proof later
- ErrBrokenChain: Proof is invalid or corrupted; obtain new proof
- ErrInvalidPoW: Header is fake; reject and possibly ban source
- ErrMerkleMismatch: Wrong branch or wrong tx; obtain correct proof
7. Testing Strategy
Test Vectors
Use real Bitcoin mainnet data for test vectors:
- Known transaction with known Merkle proof
- Headers from specific heights
- Edge cases (single-tx blocks, max-size blocks)
Fuzz Testing
Fuzz all parsing code:
- Malformed headers
- Invalid lengths
- Extreme values for bits field
Integration Testing
- Verify against Bitcoin full node
- Cross-check with multiple SPV implementations
- Test with testnet transactions
8. What’s NOT in This Guide
This guide covers verification only. NOT covered:
- Header sourcing: How to get Bitcoin headers
- Eclipse resistance: How to avoid header source attacks
- Incentives: How to pay for header relay
- State storage: How to store verified facts
These are covered in separate specifications.
9. Implementation Checklist
- Double SHA256 implemented correctly
- Endianness handled in all conversions
- Header parsing handles all fields
- Chain linkage verified
- PoW verified for ALL headers
- Merkle verification handles both positions
- Depth calculation correct
- Size limits enforced
- Error handling complete
- Test vectors pass
- Fuzz testing clean
References
- Bitcoin Protocol: https://developer.bitcoin.org/reference/
- BIP 37 (Merkle Branch Format): https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki
- Zenon Greenpaper SPV Sections
- Bitcoin SPV Verifier Specification (companion doc)
Document Status: Implementation Guide Version: Draft