Bitcoin Vault Covenants
An Empirical Evaluation

The first empirical comparison of four Bitcoin covenant vault designs, measured head-to-head on real nodes. 15 experiments, 11 threat models, and a finding that changes the debate: the safest vault depends on the fee environment.

Praneeth Gunasekaran
MS CS, Virginia Tech · Research Assistant, Commonwealth Cyber Initiative
Research Contributions
Prior work compared vault designs qualitatively or analyzed them in isolation. This is the first study to build all four, run them on real Bitcoin nodes, and measure the results.
Novel

First empirical four-way comparison

5 vault implementations (CTV, CCV, OP_VAULT, CAT+CSFS, Simplicity) tested across 15 experiments on regtest. All prior comparisons were qualitative or feature-matrix based.

Novel Finding

Security rankings invert with fees

At low fees, CCV/OP_VAULT are safer. At high fees, CTV is safer. The crossover occurs at 50-100 sat/vB. No prior work identified this inversion.

First Measurements

Concrete lifecycle costs

First published vsize data for all four designs. Corrected BIP-345 hand-estimates by 30-46%. OP_VAULT's fee-input overhead (80-90 vB/tx) was previously unquantified.

Implementation

Two original vault implementations

Built the first working CAT+CSFS vault (dual Schnorr verification) and a Simplicity vault on Elements. Plus Alloy formal verification models for all five designs.

Eight Insights From Regtest
01

Safety rankings flip based on fees

Low fees (<50 sat/vB) → CCV and OP_VAULT are safer (pinning is cheap, splitting is infeasible). High fees (>100 sat/vB) → CTV is safer (watchtower exhaustion becomes viable against the others). The crossover occurs around 50–100 sat/vB. There is no universally safest vault.

02

Griefing resistance and fund safety are mutually exclusive

No vault can simultaneously achieve permissionless recoverability (fund safety under key loss) and griefing resistance (bounded adversary advantage without keys). OP_VAULT blocks griefing best (authorized recovery) but key loss disables recovery. CCV protects funds best under key loss (keyless recovery) but anyone can grief. This is a necessary design tradeoff, not an implementation gap.

03

OP_VAULT's fee-input overhead costs 36% more per lifecycle

BIP-345's value preservation rule requires exogenous fee payment via a separate input, adding 80–90 vB to every transaction. Trigger: 292 vB vs CCV's 154. Recovery: 246 vB vs CCV's 122. This is inherent to the design, not an implementation artifact — and the gap compounds in multi-round scenarios.

04

CCV mode values are a developer footgun

CCV mode flags outside {-1, 0, 1, 2} trigger OP_SUCCESS — specified BIP-443 behavior for forward-compatible soft-fork extensions. We verified this on a production-shaped vault taptree: mode=3 bypasses all covenant checks. 110 vB, no signature required. The pymatt library prevents misuse via named constants, but raw script authors must validate mode values explicitly.

05

Composability comes at the cost of destination flexibility

CAT+CSFS builds a vault from general-purpose opcodes — no dedicated opcode needed. But the destination is baked into the script as a hash constant. Changing where funds go requires recovery + re-vaulting. Purpose-built opcodes (CCV, OP_VAULT) allow trigger-time destination choice.

06

CAT+CSFS recovery is the weakest of all four designs

The recovery leaf is a bare cold_pk OP_CHECKSIG — no output constraints, no timelock, no introspection. A compromised cold key means immediate, unrestricted theft indistinguishable from legitimate recovery. CCV (keyless, constrained) and OP_VAULT (keyed, constrained) both survive cold key loss.

07

Single-use addresses disqualify two vaults from deposit systems

CTV and CAT+CSFS permanently lose funds on address reuse — CTV at the script level, CAT+CSFS at the signature level. For any customer-facing deposit system, only CCV and OP_VAULT are viable without strict wallet-layer enforcement of single-use discipline.

08

Constraining both spending paths costs witness size

Simplicity's 865 vB lifecycle (on Elements) is 2.4x CTV's, but every spending path — trigger and recovery — is output-locked via jet::outputs_hash(). CAT+CSFS achieves hot-key safety with similar composability but leaves recovery unconstrained. The witness-size cost of typed functional programs is the price of comprehensive output enforcement.

Fee-Dependent Security Inversion

How each vault's danger level shifts with fee environment. Higher = more vulnerable.

0% 25% 50% 75% 100% Danger Level 1 10 50 100 300 500 Fee Rate (sat/vB) crossover zone CTV CCV OP_VAULT CAT+CSFS
📄 Paper (PDF) 💻 GitHub 📑 Design Doc 📚 References
CTV · BIP 119

The Deterministic One

Pre-commits the entire transaction tree at vault creation. No partial withdrawals, no batching. Simple and rigid.

368
vB lifecycle
2
keys
0
revaults
CCV · BIP 443

The Flexible One

Contract verification for state transitions. Partial withdrawals via revault, batched triggers, keyless recovery. The measured lifecycle includes a trigger-and-revault step unique to CCV.

565
vB lifecycle
1
key
revaults
OP_VAULT · BIP 345

The Purpose-Built One

Dedicated opcode pair for vaults. Authorized recovery blocks griefing, but three keys means three things that can break.

567
vB lifecycle
3
keys
revaults
CAT+CSFS · BIP 347+348

The Composed One

General-purpose opcodes (OP_CAT + OP_CSFS) composed into a vault via dual Schnorr verification. Destination locked at creation. Conservative and introspective.

553
vB lifecycle
2
keys
0
revaults
Vault Lifecycles
The CTV vault lifecycle is entirely deterministic. When you create the vault, you commit to every possible future transaction upfront by hashing a template that locks in the outputs, amounts, and destinations. Funds enter through a deposit to a P2WSH address whose script contains a CTV hash. To withdraw, you broadcast the pre-signed unvault transaction that moves funds into a timelocked intermediate state. During the timelock window, a watchtower can broadcast the pre-signed cold sweep to recover funds if the withdrawal looks unauthorized. If no one intervenes, the hot wallet withdrawal completes after the delay. There is no partial withdrawal — the entire vault balance moves as a single unit every time. This rigidity is what makes CTV auditable: you can regenerate the full transaction tree from the initial parameters and verify that no unauthorized paths exist. The total lifecycle costs 368 vB across three transactions (deposit 122 vB, trigger 94 vB, withdraw 152 vB). CTV uses two keys — a hot key for spending and a cold key for recovery — making it the simplest key management model of the three designs.
CTV vault lifecycle
Under the hood, CTV vaults use bare CTV scripts wrapped in P2WSH — no Taproot involved. The core opcode OP_CHECKTEMPLATEVERIFY takes a 32-byte hash on the stack and verifies that the spending transaction matches the committed template exactly: same outputs, same amounts, same sequence numbers. The vault script encodes two spending paths. The first is the unvault path, which requires the CTV hash to match and the hot key signature. The second is the cold sweep path, which requires only the cold key signature with no template check, allowing emergency recovery to any destination. The unvault output itself contains another CTV-locked script with its own two paths: a timelocked hot withdrawal (requiring CSV delay plus hot key) and a cold sweep. This creates a hash-chain of pre-committed transactions where every state transition is fully specified at vault creation time. The P2WSH approach means witness scripts are revealed only at spend time, but the entire tree structure is knowable from the root hash. No script path is hidden — there is no Taproot key-path shortcut, no internal key optimization, just bare script verification against committed templates.
CTV mechanism
The safety model of a CTV vault emerges from its nesting structure. Each transaction is built backwards — the innermost withdrawal is constructed first, then wrapped by the trigger, then wrapped by the vault deposit. The entire execution path is cryptographically committed before any funds enter the system. The ephemeral signing key used during construction is destroyed immediately after, making the commitment permanent and irreversible. During execution, the flow reverses inward: the outer vault layer is spent first, then the middle trigger layer after a time delay, and finally the inner withdrawal completes. Recovery exists as a bypass that can interrupt this inward flow at any point, sweeping funds to cold storage. The rigidity is what makes this a safety property rather than just an implementation detail — no transaction can deviate from the pre-committed template, which means no fee adjustment, no partial withdrawal, and no destination change after vault creation. Every lock between layers is enforced by the CTV hash matching the exact transaction that follows. The safety guarantee is structural: if the hash chain is valid at creation time, no future execution can violate it.
CTV safety model — concentric rings showing backwards construction and inward execution
CCV vaults store state inside Taproot output tweaks, which lets them do something CTV cannot: partial withdrawals. When you deposit into a CCV vault, your funds land in a P2TR output whose internal key is a NUMS point (nothing-up-my-sleeve, meaning no one can spend via the key path). The spending rules live entirely in Taproot script leaves. To trigger a withdrawal, you provide a signature from the trigger key and the CCV opcode verifies that the spending transaction creates valid successor outputs — a timelocked withdrawal output and optionally a change output that returns remaining funds to a new vault with the same contract rules. This change-back mechanism is the revault: you can withdraw 0.5 BTC from a 10 BTC vault and the other 9.5 BTC stays vaulted under identical protections. Recovery is keyless — anyone who knows the vault address can broadcast the recovery transaction, which sends all funds to the pre-committed recovery address. The measured lifecycle costs 565 vB across three transactions (deposit 300 vB, trigger-and-revault 154 vB, withdraw 111 vB), reflecting CCV's ability to trigger a partial withdrawal and return the remainder to a new vault in a single transaction. CCV uses only one key for the trigger, with recovery requiring no key at all.
CCV vault lifecycle
CCV's internal machinery relies on OP_CHECKCONTRACTVERIFY to enforce state transitions across transactions. Each vault output is a P2TR address with a NUMS internal key (specifically the generator point negated so no discrete log is known). The contract rules live in Taproot leaf scripts. When a trigger transaction spends the vault, CCV checks that the outputs conform to the contract: the withdrawal amount goes to a timelocked script, and any change goes back to a new vault output with the same Taptree structure. The mode flags in CCV control what gets verified — mode 0 checks the output's scriptPubKey matches a committed template, mode 1 verifies amounts, mode 2 checks both. These mode bytes are critical because any value outside [0, 1, 2] causes the interpreter to execute OP_SUCCESS, which makes the script trivially spendable by anyone. The minivault variant uses CCV alone without CTV, while the full vault combines both opcodes. State is carried forward through Taproot tweaks: the contract's Taptree is reattached to each successor output, ensuring the same spending rules apply to change outputs across an unlimited number of revault cycles.
CCV mechanism
At the opcode level, OP_CHECKCONTRACTVERIFY performs bilateral introspection — it sits between the input and output sides of a transaction and verifies that the output's structure mirrors the input's contract rules. When a vault UTXO is spent, CCV inspects the spending transaction's outputs and checks three things depending on its mode flag: that the output scriptPubKey matches the committed template (mode 0), that the output amount satisfies the contract (mode 1), or both (mode 2). The input taptree — with its trigger and recovery leaves — must be carried forward to the output taptree intact, preserving the contract across state transitions. State data shifts through CCV as the input's internal key tweak is replaced by the output's tweak, carrying the vault balance and withdrawal parameters forward. The mode byte is the critical execution detail: CCV treats any value outside [0, 1, 2] as OP_SUCCESS, which makes the entire script trivially true — no signature needed, no covenant check, no constraints. This is not a bug but an intentional forward-compatibility mechanism. At the opcode level, it means a single byte controls whether CCV acts as a verification gate or an open door.
CCV opcode logic — bilateral lens showing input-output introspection
OP_VAULT uses a dedicated opcode pair — OP_VAULT and OP_VAULT_RECOVER — purpose-built for vault contracts, unlike CTV and CCV which are general-purpose covenant opcodes adapted for vault use. The lifecycle begins with a deposit to a P2TR address whose internal key is the recovery pubkey. The trigger key holder starts a withdrawal by broadcasting a trigger transaction that invokes OP_VAULT, which enforces a timelock delay and commits to a specific withdrawal destination. During the delay, a watchtower can broadcast an authorized recovery transaction using OP_VAULT_RECOVER, which requires the recoveryauth key signature. If no recovery happens, the withdrawal completes after the timelock expires. OP_VAULT's distinctive feature is authorized recovery: unlike CCV where anyone can trigger recovery, here only the recoveryauth key holder can do it. This prevents griefing attacks where random observers force funds back to cold storage. The cost is a three-key model — trigger, recoveryauth, and recovery address — which is the most complex key management of the three designs. The lifecycle costs 567 vB (deposit 154 vB, trigger 292 vB, withdraw 121 vB), roughly 36% more than CCV, largely due to the 2-input fee wallet pattern that adds 80–90 vB to trigger and recovery transactions.
OP_VAULT lifecycle
OP_VAULT's internal structure uses P2TR with the recovery pubkey as the Taproot internal key. This is a deliberate design choice: if all three keys are available and cooperating, a key-path spend (using the recovery pubkey) can bypass the script entirely. The Taptree contains leaf scripts for OP_VAULT (trigger path) and OP_VAULT_RECOVER (recovery path). When OP_VAULT executes, it verifies that the spending transaction creates an output with a specific structure — a timelocked script committing to the declared withdrawal destination. The opcode enforces the delay parameter and output matching in consensus, meaning a miner cannot forge a valid trigger. OP_VAULT_RECOVER checks the recoveryauth signature and ensures funds move to the committed recovery address. The recovery address is baked into the vault at creation and is immutable — even with both the trigger key and recoveryauth key compromised, an attacker cannot redirect recovery funds. This is why dual-key compromise (TM6) results in denial-of-service rather than theft: the attacker can trigger and then recover in a loop, but funds always land at the legitimate recovery address. The fee wallet pattern uses a separate UTXO to pay transaction fees, avoiding the need to deduct fees from the vault amount, but adding an extra input to every transaction.
OP_VAULT mechanism
At the opcode level, OP_VAULT performs consensus-enforced taproot tree surgery — it directly modifies the spending UTXO's taptree structure within the transaction validation rules. The vault UTXO is a taproot output with two script leaves: a vault-spend leaf (containing the OP_VAULT opcode) and a recovery leaf. When the vault-spend leaf is executed, OP_VAULT reads the trigger parameters from the witness stack and does three things in a single validation pass: it prunes the vault-spend leaf from the taptree, grafts a new CTV-locked leaf in its place that commits to the declared withdrawal destination and timelock, and copies the recovery leaf through to the output taptree unchanged. The opcode validates this surgery by recomputing the expected output scriptPubKey from these components and checking it against the actual transaction output — if the recomputed taptree doesn't match, the transaction is invalid at the consensus level. The three keys occupy distinct execution tiers: the trigger key sits in the vault-spend leaf and is checked by script during the spend path, the recovery authorization key gates the recovery leaf and must sign to exercise that path, and the recovery destination is baked into the taproot internal key at construction time — not in any script leaf, but in the key-path tweak itself, which means no script execution can alter where recovery funds land. This separation is enforced by the opcode's tree surgery: because OP_VAULT only replaces its own leaf while preserving everything else, the recovery path and its embedded destination survive every state transition untouched.
OP_VAULT opcode logic — tree surgery with pruning and grafting
The CAT+CSFS vault takes a fundamentally different approach from the other three designs: instead of a purpose-built opcode, it composes a vault from two general-purpose primitives — OP_CAT (BIP 347) for concatenating stack items and OP_CHECKSIGFROMSTACK (BIP 348) for verifying signatures against arbitrary messages. The lifecycle begins with a deposit to a P2TR address whose internal key is a NUMS point (unspendable key path), with two Taproot leaf scripts: a trigger leaf containing the CSFS+CAT introspection logic, and a recover leaf with a simple cold key OP_CHECKSIG. To trigger a withdrawal, the hot key holder broadcasts a transaction that passes dual Schnorr verification — the same signature is checked against both the real transaction sighash (via OP_CHECKSIGVERIFY) and a witness-provided sighash preimage (via OP_CHECKSIGFROMSTACK). If both pass, the preimage is proven authentic, and the script verifies that the output matches the expected vault-loop address. Funds then sit in the vault-loop state, protected by a CSV timelock. After the delay, the same dual-verification mechanism enforces that funds go to the pre-committed destination — which is locked at vault creation time as a sha_single_output constant embedded in the script. The destination cannot be changed without recovering to cold storage and creating a new vault. Recovery uses the cold key via a simple OP_CHECKSIG in the recover leaf — no introspection needed, no constraints on where funds go. The total lifecycle costs 553 vB across three transactions (deposit 122 vB, trigger 221 vB, withdraw 210 vB). Like CTV, it uses two keys (hot + cold) and does not support partial withdrawals or revaulting.
CAT+CSFS vault lifecycle
The dual Schnorr verification at the heart of CAT+CSFS is an elegant trick: the witness provides a decomposed sighash preimage (prefix, sha_single_output, suffix) and a copy of the signature. The script first runs OP_CHECKSIGVERIFY to verify the signature against the actual transaction sighash — this is normal Bitcoin signature verification. Then OP_CAT concatenates the witness-provided preimage pieces into a single message on the stack. OP_CHECKSIGFROMSTACK verifies the same signature against this assembled message. Because a Schnorr signature can only be valid for one message under the same key (discrete log uniqueness), the assembled preimage must be the real sighash. The script then extracts the sha_single_output field from the proven preimage and compares it to a hash constant embedded in the script at vault creation. If they match, the transaction output is guaranteed to pay the pre-committed destination. The sighash type SIGHASH_SINGLE|ANYONECANPAY (0x83) covers only one input and its corresponding output, which means additional fee-paying inputs can be attached without invalidating the covenant signature — a cleaner fee management approach than CTV's CPFP anchors. The tradeoff is that the destination is permanently fixed: the embedded hash cannot change without destroying and re-creating the vault.
CAT+CSFS dual verification mechanism
At the opcode level, the CAT+CSFS vault script is a verification pipeline. The Taproot output has a NUMS internal key (preventing key-path spends) and a two-leaf taptree. The trigger/withdraw leaf contains the pipeline: OP_CHECKSIGVERIFY verifies the signature against the real transaction, two OP_CAT operations concatenate the preimage fragments (prefix + sha_single_output + suffix), then OP_CHECKSIGFROMSTACK verifies the same signature against the assembled preimage, and finally OP_EQUALVERIFY confirms the output hash matches the embedded constant. The recover leaf is deliberately simple — just cold_pk OP_CHECKSIG with no introspection, no constraints, and no output restrictions. This asymmetry is the design's security model: the trigger path is computationally constrained (outputs must match embedded hashes), while the recovery path is unconstrained (cold key can sweep anywhere). The SIGHASH_SINGLE|ANYONECANPAY flag is critical at this level — it means the sighash preimage only commits to one input and one output, allowing fee-paying inputs to be added freely. This is why CAT+CSFS vaults don't need anchor outputs or CPFP: the covenant signature remains valid regardless of what other inputs or outputs exist in the transaction, as long as the constrained output matches the embedded hash.
CAT+CSFS opcode logic — verification pipeline
The timelock race is the fundamental security mechanism shared by all four vault designs. When an unauthorized party triggers a withdrawal — whether through key theft, malware, or coercion — a clock starts. The withdrawal is timelocked: it cannot complete until a specified number of blocks have been mined. During this window, a watchtower (software monitoring the blockchain for vault-related transactions) detects the unauthorized trigger and broadcasts a recovery transaction to sweep funds back to cold storage. The attacker's only option is to try to prevent the recovery transaction from confirming before the timelock expires. In CTV, the attacker can attempt fee pinning — chaining descendant transactions off the unvault output to block CPFP fee bumping, exploiting the 25-transaction descendant limit. In CCV and OP_VAULT, the attacker can attempt watchtower exhaustion — splitting the vault into many small UTXOs and triggering them all, forcing the watchtower to pay recovery fees for each one. The race outcome depends on the fee environment: at low fees, pinning is cheap and CTV is most vulnerable; at high fees, recovery is expensive and CCV/OP_VAULT watchtowers can be bled dry. This fee-dependent inversion means no single vault design wins the race under all conditions.
Timelock race
Where the Vulnerabilities Are
CRITICAL Fee Pinning (TM1)
Fee pinning exploits CTV's transaction structure to block emergency recovery. When the unvault transaction broadcasts, its output can be spent by anyone who knows the pre-committed template — because CTV scripts are public once revealed. An attacker chains 25 low-fee descendant transactions off the unvault output, hitting Bitcoin Core's descendant limit (MAX_DESCENDANT_COUNT). The cold sweep transaction, which needs to spend that same output via CPFP, is rejected by mempools because the descendant chain is full. The watchtower cannot bump fees, cannot replace the junk transactions (they don't signal RBF), and cannot get the recovery transaction into any block. When the timelock expires, the attacker's hot withdrawal confirms and the funds are gone. This attack costs almost nothing — the 25 junk transactions can pay minimum relay fees. It is unique to CTV because its P2WSH structure exposes the unvault output to third-party spending, and the pre-committed transaction template cannot include anchor outputs or other fee-management mechanisms added after vault creation. CCV and OP_VAULT are immune because their Taproot structures don't expose intermediate outputs to third-party descendant chaining.
Measured on Regtest
Descendant Chain
25 txs
2,750 vB total (25 × 110)
Capital Needed
~550 sats
Anchor output dust
Defender Blocked
133 vB
Cold sweep rejected — desc limit full
Attack Cost
< 0.05%
Of vault balance at any fee rate
CTV only — P2WSH exposes the unvault output to third-party descendant chaining. CCV and OP_VAULT are immune (Taproot key-path spend).
Fee pinning attack
CRITICAL CCV Mode Bypass (TM8)
CCV mode bypass is the most consequential developer footgun we documented. The CCV opcode accepts a mode byte that controls verification behavior: mode 0 checks scriptPubKey, mode 1 checks amount, mode 2 checks both. Any mode value outside this set — 3, 4, 255, anything — triggers OP_SUCCESS, a consensus rule designed for future soft-fork extensibility. OP_SUCCESS makes the entire script evaluate to true unconditionally: no signature needed, no covenant check, no constraints at all. We built a structurally complete vault contract with one leaf script accidentally using mode=3 and drained it with a 110 vB transaction containing no signature. The funds moved to an arbitrary destination with zero authentication. This is not a bug in the CCV specification — it is the intended behavior for forward compatibility. But it means a single byte error in vault construction creates a script that looks correct, passes every static analysis check, deploys successfully, accepts deposits normally, and then allows anyone who notices the mode flag to steal everything. The attack surface exists only in CCV because CTV has no mode flags and OP_VAULT uses dedicated opcodes with no extensibility trap.
Bypass Modes Tested
Mode Behavior Result
0, 1, 2 Normal CCV check Validates correctly
3 OP_SUCCESS (undefined) Theft — 110 vB
4 OP_SUCCESS (undefined) Theft — 110 vB
7 OP_SUCCESS (undefined) Theft — 110 vB
128 OP_SUCCESS (undefined) Theft — 110 vB
255 OP_SUCCESS (undefined) Theft — 110 vB
5/5 undefined modes accepted. Zero signatures required. Funds sent to arbitrary address. Control vault (mode 0) correctly rejected the same spend.
CCV mode bypass attack
SEVERE Trigger Key Theft (TM3 + TM5)
Trigger key theft is the canonical vault attack: an adversary compromises the hot key used to initiate withdrawals and attempts to steal funds before the watchtower can react. In all four vault designs, the attack follows the same pattern — the attacker triggers an unauthorized withdrawal, the timelock delay begins, and the watchtower races to broadcast recovery. The difference is recovery cost. CTV recovery uses a pre-signed cold sweep at 133 vB. CCV recovery is the cheapest at 122 vB because keyless recovery requires no signature, just knowledge of the vault address. OP_VAULT recovery is the most expensive at 246 vB because the 2-input fee wallet pattern adds overhead and the recoveryauth signature adds witness data. Across all three designs, the watchtower wins this race as long as it is online and funded — the timelock gives it blocks, not seconds, to respond. The real danger is trigger key theft combined with watchtower failure, which escalates to fund theft in CTV (attacker completes the hot withdrawal) and CCV (attacker completes withdrawal to their chosen destination). In OP_VAULT, even with watchtower failure, the attacker cannot redirect recovery funds because the recovery address is immutable.
Recovery Cost Comparison
CTV CCV OP_VAULT CAT+CSFS
Recovery tx 133 vB 122 vB 246 vB 125 vB
Mechanism Pre-signed cold sweep Keyless (no sig) 2-input + auth sig Cold key CHECKSIG
Cost vs attacker 1.41× 1.26× 1.19× ~0.57×
Watchtower wins the race in all cases — timelocks give blocks, not seconds, to respond. The cost difference matters in sustained multi-round attacks (see TM4). CAT+CSFS recovery is cheap because the recover leaf is a simple CHECKSIG — no introspection overhead.
Trigger key theft attack
SEVERE Recovery Griefing (TM2)
Recovery griefing is the direct consequence of CCV's keyless recovery design. Since anyone can trigger recovery without any key or signature — they just need to know the vault's address and construct a valid recovery transaction — a griefer can watch for trigger transactions and immediately broadcast recovery, sending funds back to cold storage before the legitimate withdrawal completes. No funds are stolen, but the vault owner is permanently denied access to their hot wallet. Every withdrawal attempt gets front-run by the griefer, creating an infinite denial-of-service loop. The griefer pays only the recovery transaction fee (122 vB × fee rate), which is cheap compared to the damage inflicted. CTV has moderate griefing exposure because the cold sweep requires a cold key signature — only someone with the cold key can grief. OP_VAULT has the best griefing resistance because recovery requires the recoveryauth key signature, making anonymous griefing impossible. The structural tradeoff is that CCV's keyless recovery is simultaneously its greatest strength (funds recoverable even if all keys are lost) and its greatest weakness (anyone can trigger recovery). You cannot have both open recovery access and griefing resistance — they are fundamentally opposed design goals.
Cost Asymmetry per Round
CTV CCV OP_VAULT CAT+CSFS
Trigger tx 94 vB 154 vB 292 vB 221 vB
Recovery tx 133 vB 122 vB 246 vB 125 vB
Asymmetry 0.71× 1.26× 1.19× 1.77×
Grief barrier Cold key required None (keyless) Auth key required Cold key required
Asymmetry > 1× means the defender pays more per round than the griefer. CCV is worst: zero barrier (keyless recovery) + unfavorable cost ratio. OP_VAULT is best: requires auth key, making anonymous griefing impossible. CAT+CSFS is similar to CTV: cold key required for recovery, favorable cost ratio for the defender.
Recovery griefing attack
SEVERE Watchtower Exhaustion (TM4 + TM7)
Watchtower exhaustion turns CCV and OP_VAULT's partial withdrawal feature into an attack vector. The attacker, holding the trigger key, splits the vault into hundreds or thousands of small UTXOs using repeated partial withdrawals, each creating a new independent vault. Then the attacker triggers withdrawals on all of them simultaneously. The watchtower must now broadcast a separate recovery transaction for every single UTXO, paying fees on each one. At 122 vB per recovery for CCV and 246 vB per recovery for OP_VAULT, the watchtower's fee budget is quickly exhausted. Once the budget runs out, remaining triggered UTXOs complete their unauthorized withdrawals uncontested. OP_VAULT fails roughly twice as fast as CCV because its recovery transactions cost twice as much. CTV is completely immune to this attack because it does not support partial withdrawals — there is no way to split a CTV vault into smaller pieces. The attacker cannot create the initial UTXO fragmentation that the attack requires. This is the clearest example of the fee-dependent security inversion: at low fees, the splitting phase is cheap and the attack is viable against CCV and OP_VAULT. At high fees, splitting is expensive but recovery is also expensive, creating a complex cost tradeoff.
Fee Sensitivity — Splits to Exhaust 0.5 BTC Vault
1 sat/vB ~410,000 splits needed Infeasible
10 sat/vB ~41,000 splits needed Hard
50 sat/vB ~8,200 splits needed Feasible
300 sat/vB ~1,400 splits needed Viable
500 sat/vB ~820 splits needed Easy
Per Split
162 vB
Trigger + revault (constant)
Per Recovery (CCV)
122 vB
Keyless, per-UTXO
Per Recovery (OPV)
246 vB
Fails 2× faster than CCV
50 actual splits executed on regtest — vsize constant across all rounds. Batched recovery saves 40–45% but cannot prevent exhaustion at sustained high fees. CTV is immune (no partial withdrawals).
Watchtower exhaustion attack
HIGH Dual-Key Compromise (TM6)
Dual-key compromise examines what happens when an attacker obtains both the trigger key and the recoveryauth key in an OP_VAULT system. This sounds like it should be game over — and in CTV it is, because holding both the hot key and cold key gives the attacker complete control. But OP_VAULT's design produces a surprising result: denial-of-service, not theft. The attacker can trigger a withdrawal and then immediately use the recoveryauth key to invoke authorized recovery, sending funds back to the recovery address. They can repeat this loop indefinitely, preventing the legitimate owner from ever completing a withdrawal. However, they cannot redirect funds because the recovery address was set at vault creation and is immutable — it is embedded in the Taproot internal key structure and cannot be changed by anyone, including someone holding all three keys. The attacker is stuck in a trigger-recover loop where funds always return to the legitimate recovery address. To actually steal funds, the attacker would need to compromise the recovery address itself (a separate key or multisig), making this effectively a three-key attack threshold. CCV's single-key model means this specific scenario does not apply — there is only one trigger key and recovery is keyless. Simplicity (on Elements) constrains both spending paths via jet::outputs_hash(), so dual-key compromise produces DoS only — matching OP_VAULT's outcome through a different mechanism.
Compromise Outcomes
CTV CCV OP_VAULT CAT+CSFS
Keys compromised Hot + cold N/A (single key) Trigger + auth Hot + cold
Outcome Fund theft DoS only Fund theft
Why Full control of both paths No second key exists Recovery addr is immutable Cold key bypasses all constraints
OP_VAULT's immutable recovery address (embedded in the taproot internal key tweak) means dual-key compromise produces denial-of-service, not theft. CTV and CAT+CSFS both allow fund theft when both keys are compromised — the cold key recovery path has no output constraints. CAT+CSFS cold key theft directly enables an attacker to sweep vault funds since the recover leaf is an unconstrained CHECKSIG.
Dual key compromise attack
HIGH Cold Key Recovery Theft (TM11)
This is the most severe CAT+CSFS vulnerability. The recovery leaf uses a simple cold_pk OP_CHECKSIG with SIGHASH_DEFAULT — there is no CAT, no CSFS, no output introspection of any kind. A compromised cold key can construct a recovery transaction sending funds to any arbitrary address, immediately, with no timelock delay and no output constraints. Compare this to the other three designs: CCV recovery is keyless and output-constrained (funds always go to the pre-committed recovery address), OP_VAULT recovery requires the recoveryauth key and is output-constrained (funds always go to the recovery SPK hash), and CTV recovery uses a pre-committed CTV template that locks the destination at vault creation. CAT+CSFS ranks last in recovery security — cold key compromise means immediate, unrestricted, total theft. The 125 vB recovery transaction looks identical to a legitimate cold sweep on-chain; there is no way for a watchtower to distinguish theft from legitimate recovery. Poelstra's recursive reset model (from "CAT and Schnorr Tricks II") would upgrade this to liveness denial only, matching OP_VAULT's security profile, but is not implemented in the current design. Simplicity constrains recovery outputs via jet::outputs_hash(), making cold key compromise recovery-address-locked — matching CCV and OP_VAULT, not CAT+CSFS.
Recovery Security Ranking
Covenant Recovery Model Cold Key Compromise Result
CCV Keyless, output-constrained N/A (no key) Safest
OP_VAULT Keyed, output-constrained Grief only (recovery addr immutable) Grief only
CTV CTV-constrained template Wallet key → theft of recovered funds Moderate
CAT+CSFS Unconstrained OP_CHECKSIG Immediate total theft — any address Critical
Recovery vsize
125 vB
From vault or vault-loop
Output constraint
None
cold_pk CHECKSIG only
Timelock
None
No CSV on recovery leaf
Distinguishable
No
Theft looks identical to legitimate recovery
CAT+CSFS only. Recovery leaf script: cold_pk OP_CHECKSIG. No CAT, no CSFS, no output introspection. Cold key holder has unconstrained control over recovery destination.
Cold key recovery theft attack
IMPOSSIBLE Hot Key Theft — Output Redirection (TM9)
CAT+CSFS's strongest defensive property: even with a fully compromised hot key, the attacker cannot redirect vault funds to an attacker-controlled address. The trigger leaf embeds sha_single_output as a script constant — the SHA256 hash of the expected output. The dual CSFS+CHECKSIGVERIFY verification creates an inseparable binding: CHECKSIGVERIFY checks the signature against the real transaction sighash (which includes the actual output), while CSFS checks the same signature against a preimage assembled from witness data that includes the embedded sha_single_output. If the attacker changes the output, the real sighash changes but the CSFS preimage doesn't — the same signature cannot satisfy both checks. This is enforced at the consensus level (not relay policy). The attacker's only option is to trigger the vault to the pre-embedded vault-loop address repeatedly — pure griefing with no theft path. This makes CAT+CSFS the only vault design where the hot key holder cannot influence the withdrawal destination at trigger time. CTV commits to the full transaction template (including destination) but through a different mechanism; CCV and OP_VAULT both allow the trigger key holder to choose the destination at trigger time.
Output Redirection Attempts
Attack Method Result
Redirect output Change output to attacker address REJECTED (consensus)
Extra output Add output via SIGHASH_SINGLE Accepted but funded by extra inputs
Legitimate trigger Trigger to embedded vault-loop Accepted — griefing only
Trigger vsize
221 vB
Normal trigger transaction
Mutated trigger
REJECTED
Consensus-level enforcement
Theft path
None
Hot key → griefing only
CAT+CSFS only. Dual CSFS+CHECKSIGVERIFY creates an inseparable binding to the pre-embedded destination. The hot key can trigger repeatedly (griefing) but cannot change where funds go.
Hot key theft impossibility
IMPOSSIBLE Witness Manipulation — Preimage Forgery (TM10)
Tests whether an attacker can tamper with the sighash preimage components to bypass the CAT+CSFS covenant. The preimage is split into three witness items: prefix (untrusted, ~94 bytes), sha_single_output (trusted, 32 bytes, script-embedded), and suffix (untrusted, ~37 bytes). CAT concatenates them, CSFS verifies the signature against the assembled hash, and CHECKSIGVERIFY verifies the same signature against the real transaction. Three independent tampering vectors were tested: modifying the nVersion byte in the prefix (0x02 → 0x03), modifying codesep_pos in the suffix (0xFFFFFFFF → 0x00000000), and changing the hash type from SIGHASH_SINGLE|ANYONECANPAY to SIGHASH_ALL. All three are rejected at the consensus level — any modification to prefix or suffix causes the CSFS-computed sighash to diverge from the real sighash, and the same signature cannot satisfy both checks. The total preimage is 227 bytes, well within the 520-byte OP_CAT stack element limit. For any transaction T with embedded hash S, there exists exactly one valid (prefix, suffix) pair — finding a second requires breaking SHA256.
Tampering Vectors Tested
Vector Modification Result
Prefix nVersion 0x02 → 0x03 REJECTED (consensus)
Suffix codesep_pos 0xFFFFFFFF → 0x00000000 REJECTED (consensus)
Hash type SIGHASH_SINGLE|ACP → SIGHASH_ALL REJECTED (consensus)
Prefix
~94 B
Witness-provided (untrusted)
sha_single_output
32 B
Script-embedded (trusted)
Suffix
~37 B
Witness-provided (untrusted)
Total / Limit
227 / 520 B
OP_CAT stack limit ✓
All tampering vectors rejected at consensus level. For any transaction T with embedded hash S, exactly one valid (prefix, suffix) pair exists. Finding a second requires breaking SHA256.
Witness manipulation impossibility
Structural Differences That Matter
DESIGN Address Reuse — Single-Use vs Multi-Deposit
What happens when a user accidentally sends a second deposit to the same vault address? CTV and CAT+CSFS have single-use addresses — the second deposit is permanently stuck (CTV because the CTV hash commits to exact output amounts at creation time; CAT+CSFS because the CSFS signature commits to the deposit amount). CCV and OP_VAULT handle multiple deposits safely — each deposit creates an independent contract/UTXO that can be spent on its own terms. This is not an adversarial attack but a user-error footgun. For customer-facing systems (e-commerce, deposit addresses), CTV and CAT+CSFS are disqualified unless wallet software strictly enforces single-use address discipline. With CAT+CSFS there is a nuance: if the signers cooperate, a new signature can be computed for the new amount (the commitment is in the signature at spend-time, not in the script at creation-time). Without signer cooperation, funds are stuck just like CTV.
Second Deposit Behavior
Covenant Second Deposit Unvault Attempt Result
CTV Same scriptPubKey bad-txns-in-belowout Funds permanently lost
CCV Independent contract Both withdraw independently Both safe
OP_VAULT Independent UTXO Both withdraw independently Both safe
CAT+CSFS Same P2TR address Signature amount mismatch Stuck (recoverable with cooperation)
CTV commitment is at creation time (script-level). CAT+CSFS commitment is at spend time (signature-level) — more flexible but still single-use in practice. CCV and OP_VAULT are inherently multi-deposit safe.
Address reuse comparison across four vaults
CAPABILITY Revault Amplification — Partial Withdrawal Chaining
CCV supports native partial withdrawals via its trigger_and_revault clause — a single trigger splits the vault into an unvaulting output (for withdrawal) and a new vault output (holding the remainder). This can be chained repeatedly without recreating the vault. OP_VAULT similarly supports partial withdrawal through OP_VAULT's built-in excess handling. CTV and CAT+CSFS have no native partial withdrawal — every withdrawal requires destroying the entire vault and recreating with new parameters, paying the full lifecycle cost each time. For N partial withdrawals from a 0.5 BTC vault, CCV's cumulative cost scales sub-linearly (the revault output shrinks with each step), while CTV/CAT+CSFS scale linearly at N × full_cycle_cost. This capability gap is also relevant to griefing economics: an attacker triggering CCV/OP_VAULT vaults can use partial triggers to split UTXOs, multiplying the watchtower's recovery burden (see TM4/TM7).
Partial Withdrawal Cost Model (5M sat steps from 50M sat vault)
CCV per step
~162 vB
trigger_and_revault (sub-linear)
CTV per step
~368 vB
Full cycle: destroy + recreate
CAT+CSFS per step
~553 vB
Full cycle: destroy + recreate
10-step savings (CCV)
~56%
vs CTV's 10 × full cycle
CCV and OP_VAULT support native partial withdrawal. CTV and CAT+CSFS require full vault destruction and recreation for each partial withdrawal. 10 actual revault steps executed on regtest — vsize constant per step.
CAPABILITY Multi-Input Batching — Trigger Scaling
CCV and OP_VAULT can batch multiple vault UTXOs into a single trigger transaction, reducing per-vault marginal cost as N increases. CTV and CAT+CSFS cannot batch — each vault UTXO requires its own trigger transaction. At N=50 inputs, CCV reaches a per-vault cost of ~101 vB (34% savings vs N=1), while CTV and CAT+CSFS remain constant regardless of count. OP_VAULT batching is also sub-linear with ~94 vB marginal cost per additional input vs CCV's ~106 vB). CCV has a DEDUCT footgun: if multiple inputs use DEDUCT mode pointing to the same revault output, the accounting creates contradictory constraints and the transaction is rejected. Safe patterns include single-input DEDUCT, mixed trigger+trigger_and_revault, or separate revault outputs per DEDUCT input. The standardness ceiling (~400k weight units) projects a maximum of ~1,600 vaults per batched CCV trigger transaction; the block weight ceiling (4M WU) allows ~16,000 in theory.
CCV DEDUCT Footgun
Pattern Config Result
Safe: mixed 1× DEDUCT + 1× preserve ACCEPTED
Safe: all-trigger All preserve (no revault) ACCEPTED
Unsafe: dual DEDUCT 2× DEDUCT → same revault output REJECTED (accounting)
CCV-specific footgun. Multiple DEDUCT inputs pointing to the same revault output create contradictory amount constraints. Safe coordinator patterns exist but require careful implementation.
Simplicity on Elements
Simplicity is a typed functional language for blockchain covenants, deployed on Elements/Liquid — a federated sidechain. It is not a Bitcoin opcode proposal. We include it as a reference implementation to show how a fundamentally different programming model and trust architecture affect vault design. The measurements below are from Elements regtest and are not directly comparable to Bitcoin regtest due to differences in fee markets, witness structure, and consensus model.
Simplicity Elements / Liquid

The Typed One

Pure functional programs compiled to a directed acyclic graph (DAG). Covenant enforcement via native jet::outputs_hash() introspection — both the trigger path and recovery path are output-constrained. Runs on a federated sidechain with explicit fee outputs, eliminating fee pinning structurally rather than through script design.

865
vB lifecycle
2
keys
0
revaults
The Simplicity vault lifecycle operates on Elements regtest. Funds enter the vault through a deposit to a P2TR output whose spending conditions are defined by a Simplicity program — a typed functional DAG rather than a stack-based Bitcoin Script. The vault program embeds two BIP-340 Schnorr public keys (hot and cold, derived from separate BIP-39 mnemonics) and two pre-computed output hashes as compile-time parameters. To trigger a withdrawal, the hot key holder signs a transaction that is validated by the Simplicity program: jet::bip_0340_verify() checks the signature, and jet::outputs_hash() verifies that the spending transaction's outputs match the pre-committed hash. After a CSV timelock delay enforced by jet::check_lock_distance(), the withdrawal completes to the pre-committed destination. Recovery uses the cold key but is also output-constrained — unlike CAT+CSFS where the recovery leaf is an unconstrained OP_CHECKSIG, Simplicity's recovery path runs the same jet::outputs_hash() check, ensuring funds can only move to the pre-committed recovery address. The total lifecycle costs 865 vB across three transactions (deposit 269 vB, trigger 298 vB, withdraw 298 vB). The larger witness size reflects Simplicity's bit-oriented DAG encoding, which includes the pruned program, Merkle proof, and serialized witness data. Elements uses explicit fee outputs rather than the implicit fee model (input sum minus output sum) used in Bitcoin, which eliminates descendant-chain fee pinning at the protocol level.
Simplicity vault lifecycle on Elements
The covenant enforcement mechanism in Simplicity centers on jet::outputs_hash() — a native jet (optimized built-in function) that computes the Merkle hash of the spending transaction's outputs at consensus time. The vault program is a DAG with two branches selected by the witness spend-path: Left for the trigger (hot key) and Right for recovery (cold key). Both branches execute the same verification pipeline: jet::bip_0340_verify() checks the Schnorr signature against the appropriate public key, then jet::outputs_hash() computes the actual output hash and compares it against the pre-committed parameter (param::TRIGGER_OUTPUTS_HASH or param::RECOVER_OUTPUTS_HASH). If the hashes do not match, the program evaluates to false and the transaction is invalid. This is the key structural difference from CAT+CSFS: in a CAT+CSFS vault, the trigger leaf uses dual CSFS+CHECKSIG verification to constrain outputs, but the recovery leaf is a bare cold_pk OP_CHECKSIG with no introspection — a compromised cold key can sweep funds to any address. In Simplicity, both paths are output-constrained by the same mechanism. The cost of this comprehensive enforcement is witness size: Simplicity's trigger and withdraw transactions are each 298 vB, compared to CAT+CSFS's 221 vB and 210 vB respectively.
Simplicity covenant mechanism — jet::outputs_hash() enforcement

Cross-Chain Comparison

Simplicity operates on a fundamentally different chain and trust model. This table shows where the designs align structurally and where they diverge.

CTV CCV OP_VAULT CAT+CSFS Simplicity Elements
Chain Bitcoin Bitcoin Bitcoin Bitcoin Elements (federated)
Trust model PoW miners PoW miners PoW miners PoW miners Federation (11-of-15)
Script model P2WSH P2TR (Tapscript) P2TR (Tapscript) P2TR (Tapscript) P2TR (Simplicity DAG)
Covenant mechanism CTV template hash CCV opcode OP_VAULT opcode CSFS + CAT jet::outputs_hash()
Lifecycle cost 368 vB 565 vB 567 vB 553 vB 865 vB
Recovery constraint Template-locked Output-constrained Output + key None (unconstrained) Output-constrained (both paths)
Partial withdrawal No Yes (revault) Yes No No
Key model 2 keys (hot + cold) 1 key (trigger) 3 keys (trigger + auth + recovery) 2 keys (hot + cold) 2 keys (hot + cold)
Fee management CPFP anchor Integrated Fee wallet (2-input) Extra input (SIGHASH_SINGLE) Explicit fee output
01

Output-constrained recovery on both paths

Both trigger and recovery paths enforce jet::outputs_hash(). A compromised cold key can only recover funds to the pre-committed recovery address — it cannot sweep to an arbitrary destination. This matches CCV and OP_VAULT's recovery security, unlike CAT+CSFS where the cold key has unconstrained control.

02

Explicit fee outputs eliminate fee pinning

Elements replaces Bitcoin's implicit fee model (input sum minus output sum) with explicit fee outputs. There are no anchor outputs and no descendant chains to pin. Fee pinning is not just mitigated by script design — it is architecturally impossible at the protocol level.

03

Typed functional programs with formal verification

Simplicity programs are directed acyclic graphs with denotational semantics and a Coq-verified type system. Covenant properties can be verified as language-level guarantees, not testing outcomes. The tradeoff is witness size: the bit-oriented DAG encoding produces 298 vB transactions where Bitcoin Script equivalents use 94–221 vB.

Choosing the Right Vault
Choosing a vault isn't just about fees and transaction sizes. It's about your operational reality — how many keys you can manage, whether you can tolerate downtime, what your regulatory environment looks like, and what keeps you up at night.

Individuals

Long-term hodler

Cold storage inheritance vault

You're holding bitcoin for years, maybe decades. You want a dead-simple vault that your heirs can figure out. You don't need partial withdrawals — when you move, you move everything. Key management needs to be minimal because you're doing this yourself with no IT team.

Best fit: CTV — simplest key setup (2 keys), deterministic paths your estate lawyer can follow, immune to splitting attacks that require ongoing watchtower funding. No partial withdrawal is actually a feature here — prevents accidental fragmentation of an inheritance plan.
Active self-custodian

Spending vault with regular withdrawals

You use bitcoin regularly — paying rent, buying things, moving between wallets. You need partial withdrawals without destroying and recreating the vault each time. You're technically savvy enough to run a watchtower but want fund safety above all else.

Best fit: CCV — native partial withdrawal via revault, moderate per-transaction cost (565 vB lifecycle including revault step), keyless recovery means even if you lose your trigger key your funds are never permanently stuck. Tradeoff: you need to accept occasional griefing risk from anyone who knows your vault address.

Businesses

Bitcoin-native startup

Operational treasury with regular payroll

You pay contractors in bitcoin, fund operations from your vault, and need to move money weekly without touching your entire balance. Batching multiple payouts into a single trigger saves money. You have a small engineering team that can manage infrastructure but can't afford a dedicated security org.

Best fit: CCV — batched triggers across multiple vault UTXOs in a single transaction. Partial withdrawal means payroll doesn't require a full vault cycle. 106 vB per additional vault in a batch vs OP_VAULT's 94 vB. Your team needs to audit CCV mode flags carefully (TM8), but the operational savings are substantial at scale.
E-commerce company

Customer-facing deposit system

Customers send bitcoin to your deposit addresses. You can't control how many times someone sends to the same address — and if they do it twice with CTV, the second deposit is permanently lost. You need a vault that gracefully handles address reuse because your customers will inevitably do it.

Best fit: CCV or OP_VAULT — both handle address reuse safely (each deposit creates an independent contract). CTV is disqualified here — a second deposit to the same vault address creates a permanently unspendable UTXO. For customer-facing systems, this is a dealbreaker.

Exchanges & Custodians

Centralized exchange

Hot/warm wallet with SLA requirements

You manage customer withdrawals 24/7. Liveness denial is not an option — if withdrawals stop, regulators notice, customers panic, and you're on the front page. A griefing attack that blocks withdrawals for even a few hours costs you more than a fee overhead ever would. You have a dedicated security team managing HSMs and key ceremonies.

Best fit: OP_VAULT — authorized recovery means no anonymous entity can grief your withdrawal pipeline. The 36% overhead (567 vB lifecycle) is an acceptable insurance premium when your SLA is measured in minutes. Three-key management (trigger, recoveryauth, recovery) maps naturally to exchange key ceremony practices — different teams hold different keys.
Institutional custodian

Deep cold storage for large holdings

You hold bitcoin for pension funds, family offices, or sovereign wealth. Withdrawals happen quarterly at most. The absolute priority is fund safety under any key compromise scenario — not speed, not flexibility, not liveness. You can tolerate days of recovery time if it means funds are never at risk.

Best fit: CCV — keyless recovery means even if your entire trigger key infrastructure is compromised, anyone (including your disaster recovery partner) can invoke recovery without needing a special key. For a fund holding client assets, "recoveryauth key got destroyed in the office fire" is an existential risk that CCV eliminates entirely.

Government & Sovereign Entities

Central bank / Strategic reserve

National bitcoin reserve with multi-agency oversight

Multiple government agencies need to authorize withdrawals. The recovery path must be invocable by any authorized agency without depending on another agency's key — because inter-agency key sharing is a political impossibility. The vault may not be touched for years. Simplicity and auditability matter more than flexibility.

Best fit: CTV — the entire transaction tree is deterministic and auditable from day one. An oversight committee can independently verify every possible spending path by regenerating the template hashes. No partial withdrawals is actually desirable — it prevents any single agency from skimming small amounts. The vault is a commitment device: when you move, you move everything, and everyone can see exactly where it goes.
Municipal government

City fund with budget-cycle withdrawals

A city holds bitcoin as part of a diversified treasury. They need quarterly withdrawals for operational spending without liquidating the whole position. The IT department is competent but not specialized in cryptography. Griefing is a real concern — political opponents might use keyless recovery to lock up the city's funds as a protest tactic.

Best fit: OP_VAULT — authorized recovery blocks political griefing (no anonymous parties can freeze the city's funds). Partial withdrawal supports budget-cycle spending. The three-key model maps to municipal separation of duties: treasurer holds trigger key, city council holds recoveryauth, recovery address is a multisig controlled by an independent oversight board.
Priority CTV CCV OP_VAULT CAT+CSFS
Simplicity / auditability Best Good Complex Moderate (composed)
Partial withdrawals Not supported Native Native Not supported
Batched operations Not supported Best (106 vB/input) Supported (94 vB/input) Not supported
Address reuse safety Funds lost Safe Safe Single use
Fund safety under key loss Moderate Best (keyless) Worst (key required) Moderate (cold key)
Griefing resistance Moderate Worst (keyless) Best (auth required) Moderate (cold key)
Watchtower cost Immune to splitting 122 vB/recovery 246 vB/recovery (2×) Immune to splitting
Destination flexibility Two paths (hot/cold) Trigger-time choice Trigger-time choice Locked at creation
Developer risk surface Low (simple scripts) High (mode flags, sentinels) Moderate (API instability) High (sighash preimage)
Key management burden 2 keys 1 key 3 keys 2 keys
On-chain cost (lifecycle) 368 vB 565 vB 567 vB (+55%) 553 vB (+51%)

All measurements from regtest. Transaction sizes (vsize) are structurally valid. 15 experiments, 11 threat models, 5 vault implementations — 4 Bitcoin covenant designs plus Simplicity on Elements regtest (federated sidechain).