Architecture
Key Components
- Bitcoin RPC: Monitors Bitcoin blockchain for deposits
- Signer: Actor instance for cryptographic operations
- Database: Stores operator keys, deposit data, and signatures
- Nonce Sessions: Manages MuSig2 nonces for parallel signing
- Citrea Client: Validates N-of-N public key correctness
Core Responsibilities
1. Operator Registration
Verifiers accept operators into the protocol viaset_operator():
Validate Collateral
Check that the operator’s collateral UTXO exists on-chain and contains the correct amount
2. Deposit Validation
Before signing any deposit, verifiers perform comprehensive validation:Security Council Check
Watchtower Limits
- Maximum extra watchtowers:
MAX_EXTRA_WATCHTOWERS - Total watchtowers cannot exceed
MAX_NUMBER_OF_WATCHTOWERS
Uniqueness Validation
- All verifiers must be unique
- All watchtowers must be unique
- All operators must be unique
Operator Verification
For each operator in the deposit:- Check if operator exists in verifier’s database
- Verify collateral UTXO is still unspent on-chain
- Ensure operator is not included if collateral was spent
- Reject deposit if unknown operators are included
Script Validation
Amount and Confirmation Checks
- Deposit amount must match
bridge_amountfrom protocol parameters - Deposit must be confirmed in a block at height ≥
start_height
3. Nonce Generation
Verifiers generate nonces for MuSig2 signing:- Validate
num_nonces ≤ NUM_NONCES_LIMIT - Generate secret and public nonce pairs using MuSig2
- Create a nonce session with random ID
- Add session to
AllSessions(evicting oldest if needed) - Return session ID and public nonces
- Sessions are stored in a HashMap with random 128-bit IDs
- Maximum total byte size:
MAX_ALL_SESSIONS_BYTES - Maximum number of sessions:
MAX_NUM_SESSIONS - Old sessions are evicted FIFO when limits are exceeded
4. Deposit Signing
Verifiers provide partial signatures for all deposit transactions:- N-of-N signatures for all kickoff transactions
- Signatures for each operator’s challenge transactions
- Signatures for slash/take transactions
- Additional signatures for move transaction and emergency stop
5. Deposit Finalization
After all partial signatures are collected:-
Verify N-of-N Signatures
- Stream sighashes for all transactions
- Receive aggregated signatures from aggregator
- Verify each signature against expected sighash
- Store valid signatures in database
-
Verify Operator Signatures
- For each operator, generate sighash stream
- Receive signatures from aggregator
- Verify signatures match operator’s public key
- Tag and store signatures by transaction type
-
Sign Move Transaction
- Receive aggregated nonce for move tx
- Calculate sighash for deposit → vault movement
- Generate partial signature using preserved nonce
-
Sign Emergency Stop
- Receive aggregated nonce for emergency stop
- Calculate sighash with
SinglePlusAnyoneCanPay - Generate partial signature
-
Persist to Database
- Save all verified signatures
- Store kickoff transaction IDs
- Mark deposit as finalized
(move_tx_partial_sig, emergency_stop_partial_sig)
Background Tasks (Automation)
The following features are only available when compiled with the
automation feature flag.State Manager
Monitors operator state transitions:- Tracks operator round progression
- Detects when operators end rounds
- Monitors kickoff transaction confirmations
- Triggers automated responses
Transaction Sender
Automatically broadcasts signed transactions:- Manages RBF (Replace-By-Fee) logic
- Handles CPFP (Child-Pays-For-Parent) fee bumping
- Retries failed broadcasts
- Monitors mempool and confirmation status
Bitcoin Syncer
Maintains a view of Bitcoin blockchain:- Syncs blocks from Bitcoin node
- Stores block headers for SPV proofs
- Updates deposit confirmation status
- Triggers state changes on confirmations
Finalized Block Fetcher
Processes blocks once they reach finality depth:- Reads from database consumer queue
- Processes deposits at finality threshold
- Triggers reimbursement flows
- Updates operator collateral status
Entity Metric Publisher
Publishes metrics about verifier health:- Wallet balance
- Sync status (Bitcoin tip vs local)
- Transaction sender queue depth
- State manager progress
State Transitions
Operator Lifecycle
Deposit Lifecycle
Database Schema
Verifiers maintain several key tables:operators
xonly_pk: Operator’s X-only public keyreimburse_addr: Address for operator reimbursementcollateral_funding_outpoint: UTXO locking operator’s collateral
operator_kickoff_winternitz_pks
operator_xonly_pk: Foreign key to operatorswinternitz_pks: Serialized vector of Winternitz public keys
deposits
deposit_outpoint: Unique identifierdeposit_data: Serialized DepositDatastatus: Pending, Signed, Finalized, Confirmed
signatures
deposit_id: Foreign key to depositssignature_id: Identifies which transaction inputsignature: 64-byte Schnorr signatureoperator_idx,round_idx,kickoff_idx: Indexing fields
Error Handling
Deposit Validation Errors
- Error message includes detailed reason
- Deposit is NOT stored in database
- No signatures are generated
- Aggregator is notified of failure
Signature Verification Errors
If a signature from the aggregator fails verification:- Log the specific signature that failed
- Include sighash and public key in error
- Stop processing immediately
- Do not store any signatures from this deposit
Security Properties
Deposit Validation
✅ Prevents:- Signing for unknown operators
- Accepting deposits with spent collateral
- Processing deposits with invalid scripts
- Signing before sufficient confirmations
Nonce Management
✅ Prevents:- Nonce reuse across sessions
- Memory exhaustion from unlimited sessions
- Nonce prediction via sequential IDs
Signature Safety
✅ Ensures:- All signatures are verified before storage
- Correct tweak data is used (key path vs script path)
- Signatures match expected transactions
- No signature is used in multiple contexts
Related Documentation
Actor Overview
Learn about the actor model architecture
Operator
Understand how operators work with verifiers
Aggregator
See how aggregators coordinate verifiers