Beersy
BRC-215

Block-Height Deadline Covenant Templates (OP_PUSH_TX)

On BSV, the usual "spend after a certain block height" protections in Bitcoin scripts have been turned off, so there was no safe way to give one person a key that right away and another person a key that only works after a deadline. Anyone trying to build this by hand could accidentally create a lock that looks safe but can actually be spent immediately, or one that can be used to jam the other party's ability to act before the deadline.

About Covenants, a script that constrains how its own coins may be spent next.

AlsoLockingNotarization

RexStarBSVchanged 20 Oct 202639 min read

Reference for an AI

Everything an assistant needs to answer questions about BRC-215 accurately, including what it depends on.

Summary

Why
Bitcoin's built-in time-lock opcodes no longer enforce anything on BSV, so a script-level deadline has to be rebuilt by reading transaction data directly, and a hand-rolled version of this is easy to get wrong in ways that silently defeat the deadline or let one party block the other.
What
BRC-215 defines an exact, byte-specified script template, called the deadline gate, that only lets a transaction spend an output if that transaction's lock time and sequence number genuinely prove it cannot be mined before a stated block height.
How
A wallet builds an output using one of three fixed templates (a gate alone, a gate plus one key, or an anytime branch alongside a gated after-deadline branch), and a spender satisfies the gate by pushing the transaction's own signature preimage so the script can check the lock time and sequence number using the Push…

What this lets you do

  • Lock an output so it cannot be spent before a specific block height
  • Give one key anytime access and another key access only after a deadline
  • Build vaults with a recovery key and a time-delayed hot key
  • Build pooled funds that contributors can reclaim after a deadline
  • Recognise and read deadline terms from an output as an indexer or client

Written by claude-sonnet-5 from the specification text. Where the two differ, the original is correct.

spend txlock-time + semined after D

The specification

Abstract

This BRC defines a deadline gate: a fixed sequence of script opcodes, parameterised by one block height D, that lets an output be spent through it only by a transaction that has that one input, whose nLockTime is a block height of at least D, and whose input's sequence number is 0xFFFFFFFE, so that lock-time enforcement is in force. The gate reads these from the transaction's own signature preimage, which the pushes and the gate authenticates with the Push TX technique of BRC-21. It refuses the two values that make a bare nLockTime >= D comparison worthless: an input sequence number of 0xFFFFFFFF, which makes the transaction final at once, and an nLockTime of 500,000,000 or more, which consensus reads as a Unix time. Consensus then refuses to mine the spend before height D + 1. The one-input rule and the one sequence number keep a spend through the gate, broadcast early and held by nodes as non-final, from blocking the other branch's spend until the deadline. Three templates use the gate. Two place it in one branch of a two-branch script, beside a branch that spends at any time: one key now and another key after D (a vault's recovery key and its time-gated hot key, an owner and a beneficiary), or m of n keys now and one key after D (a pooled fund that its contributors can reclaim); the third is the gate on its own, for a lock with no early exit. Every byte of the gate and the templates is specified, so a wallet can build them and recognise them, and the test vectors were checked against two interpreters that share no code.

Motivation

For an output created after the Genesis upgrade, OP_CHECKLOCKTIMEVERIFY and OP_CHECKSEQUENCEVERIFY are OP_NOP2 and OP_NOP3: they enforce nothing, and a node's default policy refuses a script that executes them ([GENESIS]). What remains is the transaction-level lock: a transaction whose nLockTime lies in the future, with at least one input whose sequence number is below 0xFFFFFFFF, cannot be mined until the chain reaches it. That lock serves two parties who sign a transaction together in advance. It cannot serve an asymmetric arrangement, in which one party may spend at any time and another only after a height, because the second party would sign alone, after the fact, and nothing in a plain locking script stops them choosing nLockTime = 0.

Push TX (BRC-21) closes that gap. A locking script that authenticates the spending transaction's signature preimage can read nLockTime and the input's sequence number from it and refuse a spend whose lock does not reach the deadline. BRC-21 describes the technique and names time-based restrictions as one use, and it leaves the script to each implementer. A deadline check written by each implementer invites three errors, none of which fails visibly. The first two turn the deadline off; the third shuts the other branch until the deadline:

  1. The finality bypass. Consensus ignores nLockTime when every input's sequence number is 0xFFFFFFFF. A gate that compares nLockTime with the deadline and stops there is satisfied by a transaction carrying the deadline in nLockTime and 0xFFFFFFFF in its one sequence number. That transaction is final and can be mined at once.
  2. The type confusion. Consensus reads an nLockTime of 500,000,000 or more as a Unix time. A gate that compares nLockTime >= D against a block height D is satisfied by 500,000,001, a moment in 1985 that has long passed, so the transaction is final at once. [BIP65] avoided this in OP_CHECKLOCKTIMEVERIFY by requiring the two values to be of the same type; a gate in script has to state that rule itself.
  3. The pin. A node holds a transaction that is not yet final in a pool of its own, relays it, and refuses a final transaction that spends one of its inputs unless that transaction spends exactly the same inputs, every one with sequence number 0xFFFFFFFF, and it charges every such replacement, of the held transaction by one with the same inputs and higher sequence numbers included, to an allowance per held transaction ([NONFINAL]). If the gate allows other inputs, the holder of the after-deadline key can broadcast, long before D, a spend through the gate that also spends a coin of their own: every node that holds it refuses the anytime branch's spend, which cannot spend that coin. If the gate allows any non-final sequence number, they can instead keep re-sending a one-input spend with rising sequence numbers until its allowance is spent, and the anytime branch's spend, itself a replacement, is refused while it is. At D the held spend becomes final and is mined. The deadline still holds in consensus, and the anytime branch, which exists to act first (a clawback, a check-in), is shut until it has passed.

Other standards already need an output that "cannot be spent before a stated height": BRC-190 section 4.5 grades a reader by the they have locked until a height, and BRC-210 section 7.4 lets a require a timelocked . Neither says which script makes the lock genuine. A shared template, specified to the byte, lets a wallet build such an output, lets an indexer or a client recognise one and read its deadline and keys, and lets every implementation carry the three guards above because the template carries them.

Scope and conformance

Section 2 specifies the deadline gate, section 3 the three templates that use it (two with an anytime branch, and the gate on its own), section 4 how each branch is spent and when the spend can be mined, sections 5 and 6 how a deadline is moved and which of the gate's two forms to use, and section 7 lists every requirement by role. Out of are how the parties exchange keys and deadlines, what the outputs of a spend pay to, the fee rate, and any record that announces a template output to an . The least value a template output needs in order to be spendable at all (section 3.5) is in scope, because an output funded below it is stranded.

The gate enforces two things: that a spend through it has that one input, and that it carries a block-height nLockTime of at least D and leaves that lock in force. It does not constrain the outputs of the spend, and the branch beside it constrains nothing beyond its signatures. The templates therefore give the after-deadline key a delay and the anytime keys a window in which to act first; they do not stop a holder of the anytime keys from spending at any moment.

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as described in RFC 2119 and RFC 8174 when, and only when, they appear in capitals. Three roles are used: a builder creates a template output, a spender builds a transaction that spends one, and a reader recognises template outputs and reports their terms (an indexer, a client checking a BRC-190 timelock, the receiving side of a payment).

Relationship to existing standards

Push TX: BRC-21

BRC-21 standardises the technique: the unlocking script pushes the signature preimage, the locking script computes a signature over it with a key it knows and checks that signature with OP_CHECKSIG, which succeeds only if the preimage is the real one. This BRC is one application of that technique, with its script fixed to the byte. Section 2.1 is the Push TX step; sections 2.2 and 2.3 are what this BRC adds.

Covenants that use Push TX: BRC-226, BRC-171 and BRC-172

BRC-226 uses Push TX to make a token re-create itself and pay fixed royalties on every transfer. BRC-171 keeps a 's state in its own locking script, and BRC-172 lets a covenant pay its own fees and observes that a covenant has no clock but nLockTime. All three constrain what a spend creates. The gate here constrains when a spend can be mined, and it composes with them: a covenant that carries its own state can include the gate in a branch, as the templates of section 3 do.

An in-script height gate inside a token family: BRC-197

BRC-197 lets anyone retire an expired listing with an authenticated nLockTime of at least the expiry height and below 500,000,000 and a non-final sequence number on the listing input, and states the same strict finality boundary as section 4.3. That gate is part of one token family's rules. This BRC states the gate on its own, adds the one-input rule, and fixes its bytes so that other templates can carry it.

Outputs locked until a height: BRC-190 and BRC-210

BRC-190 section 4.5 requires a timelock condition to read an output "encumbered so that it cannot be spent before a stated height" and to verify that the encumbrance is genuine. A two-key template output whose anytime key is the reader's own and whose after-deadline key is also theirs locks nothing (the anytime branch spends at once), so the template a BRC-190 lock can use is the gate alone, followed by the reader's key (section 3.3). A reader that recognises it (section 3.4) can read the height and the key from the script.

Prior art outside the BRC series

[BIP65] defines OP_CHECKLOCKTIMEVERIFY for chains on which it is enforced, including the type-match rule that section 2.3 restates. [WP-1605] is the paper behind BRC-21 and describes the construction of section 2.1: a signature with a fixed private key and a fixed , so that its r is a constant and its s is an affine function of the preimage's hash that a script can compute. This BRC fixes the private key at 2 and the nonce at 3.

Specification

1. Terminology

  • Preimage: the byte string whose double SHA-256 is the message an signature for an input signs, for the signature hash type SIGHASH_ALL | SIGHASH_FORKID (0x41), laid out as in [SIGHASH]: version (4 bytes), hashPrevouts (32), hashSequence (32), the input's (36), the scriptCode with its length, the input's value (8), the input's sequence number (4), (32), nLockTime (4) and the hash type (4), integers little-endian. With no OP_CODESEPARATOR in the locking script, the scriptCode is the whole locking script.
  • Deadline D: a block height, an integer with 1 <= D < 500,000,000.
  • Gate: the script of section 2 for a deadline D, written GATE(D).
  • Anytime branch: the branch of a template (section 3) that spends without the gate.
  • After-deadline branch: the branch of a template that spends through the gate.
  • NUM(x): the minimal push of the integer x as a : OP_0 for 0, OP_1 to OP_16 for 1 to 16, otherwise the shortest little-endian sign-magnitude encoding, pushed with the shortest push opcode.
  • PUSH(b): the minimal push of the byte string b.

Hex strings below are byte strings in the order they appear in a script.

2. The deadline gate

GATE(D) expects the preimage on top of the stack and leaves one boolean in its place: true if and only if its nLockTime lies in [D, 500,000,000) and its sequence number is 0xFFFFFFFE. The script fails at once if the preimage is not the genuine preimage of the input being evaluated, or if the transaction has another input. It is the concatenation

GATE(D) = OP_DUP || PART_A || ONE_INPUT || X || OP_BIN2NUM || NUM(D) || NUM(500000000) || OP_WITHIN || OP_VERIFY || Y

where PART_A (section 2.1) and ONE_INPUT (section 2.2) are fixed, and X and Y are fixed for each of the two forms of section 2.3. A conforming gate contains exactly these bytes.

2.1 Part A: authenticating the preimage

PART_A consumes the copy of the preimage that OP_DUP made and leaves the stack as it was before the gate, or fails. It computes, in script, the ECDSA signature over the preimage with private key d = 2 and nonce k = 3, and checks it with OP_CHECKSIGVERIFY against the public key P = 2G. The interpreter checks that signature against the real signature hash of the input it is evaluating. With r fixed, a passing check means the double SHA-256 of the pushed bytes equals that signature hash, short of a SHA-256 second-preimage of a fixed target (the Mathematical and cryptographic basis gives the precise statement), so the preimage is genuine. The constants are:

N  = fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141   (the secp256k1 group order)
r  = f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9   (x-coordinate of 3G, mod N)
A  = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9d1c9e899ca306ad27fe1945de0242b81   (k^-1 mod N)
B  = 50cb06abb6e5d76030cd8a595068e1718fe6e68c1d32310c6ebb2bde3883643b   (k^-1 * r * d mod N)
P  = 02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5

PART_A is, in order:

  1. OP_HASH256, which leaves the 32-byte digest z.
  2. REVERSE32, which is (OP_1 OP_SPLIT) repeated 31 times followed by (OP_SWAP OP_CAT) repeated 31 times, then PUSH(00) OP_CAT OP_BIN2NUM: together these read z as an unsigned big-endian integer Z.
  3. NUM(A) OP_MUL NUM(B) OP_ADD NUM(N) OP_MOD: s = (Z * A + B) mod N.
  4. OP_DUP NUM(N >> 1) OP_GREATERTHAN OP_IF NUM(N) OP_SWAP OP_SUB OP_ENDIF: the low-S form of s, which is also below 2^255, so that the next step yields a positive 32-byte value.
  5. PUSH(20) OP_NUM2BIN REVERSE32: s as 32 bytes, big-endian.
  6. 31 repetitions of OP_1 OP_SPLIT OP_SWAP OP_DUP PUSH(00) OP_EQUAL OP_IF OP_DROP OP_ELSE OP_SWAP OP_CAT OP_ENDIF, which remove leading zero bytes (a byte comparison, since 0x80 is a negative zero as a number).
  7. OP_DUP OP_1 OP_SPLIT OP_DROP PUSH(80) OP_AND PUSH(00) OP_EQUAL OP_NOT OP_IF PUSH(00) OP_SWAP OP_CAT OP_ENDIF: a zero byte in front when the leading byte has its top bit set, as DER requires.
  8. OP_SIZE OP_2 OP_SWAP OP_CAT OP_SWAP OP_CAT, then PUSH(02 21 || 00 || r) OP_SWAP OP_CAT, then OP_SIZE PUSH(30) OP_SWAP OP_CAT OP_SWAP OP_CAT, then PUSH(41) OP_CAT: the DER signature 30 len 02 21 00 r 02 slen s and the hash type 0x41.
  9. PUSH(P) OP_CHECKSIGVERIFY.

Its 942 bytes are, in hex, with SHA-256 a7689b1f7f38b3a10b1581998d4ffa957a72ebdd371d0a723a3caab29fbbd42b:

aa517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e01007e8121812b24e05d94e17fd26a30ca99e8c9d1a9aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0095203b648338de2bbb6e0c31321d8ce6e68f71e16850598acd3060d7e5b6ab06cb509321414136d08c5ed2bf3ba048afe6dcaebafeffffffffffffffffffffffffffffff00977620a0201b68462fe9df1d50a457736e575dffffffffffffffffffffffffffffff7fa06321414136d08c5ed2bf3ba048afe6dcaebafeffffffffffffffffffffffffffffff007c9468012080517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f517f7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e7c7e517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e68517f7c760100876375677c7e6876517f75018084010087916301007c7e6882527c7e7c7e23022100f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f97c7e8201307c7e7c7e01417e2102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5ad

Step 3 multiplies two 256-bit numbers, so the product can need 65 bytes as a script number. An interpreter or a policy that caps script numbers at 64 bytes refuses about one honest spend in four (section 7, requirement R7).

2.2 The one-input rule

ONE_INPUT leaves the preimage on the stack, or fails. It requires the preimage's hashPrevouts (bytes 4 to 35) to equal the double SHA-256 of the input's own outpoint (bytes 68 to 103), which holds exactly when the transaction has this one input:

OP_DUP OP_4 OP_SPLIT OP_NIP PUSH(20) OP_SPLIT PUSH(20) OP_SPLIT OP_NIP PUSH(24) OP_SPLIT OP_DROP OP_HASH256 OP_EQUALVERIFY

which is 76547f7701207f01207f7701247f75aa88 (17 bytes). With the sequence rule of section 2.3 it is what keeps the anytime branch open (Motivation, item 3; section 4.3): a spend through the gate that is broadcast early can only be a one-input transaction with no valid replacement, and a node replaces it with a final one-input spend of the same output.

2.3 Part B: the deadline and the finality guard

After ONE_INPUT the stack holds the preimage. Part B reads its nLockTime and the input's sequence number from their fixed offsets at the end of the preimage: nLockTime is bytes -8 to -5, the sequence number bytes -44 to -41. It requires

D <= nLockTime < 500,000,000      and      sequence number == 0xFFFFFFFE

The first is one OP_WITHIN, whose upper bound is the type-match rule of [BIP65]: below 500,000,000, consensus reads nLockTime as a block height, as D is. OP_BIN2NUM reads the four bytes as a sign-magnitude number, so a value with its top bit set comes out negative and fails the lower bound. The second keeps the transaction's lock in force: a transaction is final whatever its nLockTime when every input's sequence number is 0xFFFFFFFF, and this input's is not. It takes one value, the highest below 0xFFFFFFFF, so that a spend through the gate held as non-final has no replacement: the only higher sequence number is 0xFFFFFFFF, which the gate refuses.

Two forms are defined. They differ only in how they cut the fields out:

FormXYOpcodes beyond Genesis
split8254947f758254947f820120947f758254947f7704feffffff87none
chronicle7658b554b4012cb554b404feffffff87OP_LEFT, OP_RIGHT

In opcodes, the split form's X is OP_SIZE OP_4 OP_SUB OP_SPLIT OP_DROP OP_SIZE OP_4 OP_SUB OP_SPLIT (drop the hash type, cut nLockTime off the end) and its Y is OP_SIZE PUSH(20) OP_SUB OP_SPLIT OP_DROP OP_SIZE OP_4 OP_SUB OP_SPLIT OP_NIP PUSH(feffffff) OP_EQUAL (drop hashOutputs, keep the sequence number, compare). The chronicle form's X is OP_DUP OP_8 OP_RIGHT OP_4 OP_LEFT and its Y is PUSH(2c) OP_RIGHT OP_4 OP_LEFT PUSH(feffffff) OP_EQUAL. The constants are pushed minimally: OP_8, not a one-byte push of 08, because a node's default policy requires minimal pushes in a version 1 transaction ([CHRONICLE]).

The middle part, OP_BIN2NUM NUM(D) NUM(500000000) OP_WITHIN OP_VERIFY, is 81 || NUM(D) || 040065cd1d || a5 69. For D = 840000, NUM(D) is 0340d10c.

2.4 Building a gate

A builder MUST refuse a deadline outside 1 <= D < 500,000,000 (R1). It MUST emit NUM(D) minimally (R2); a reader that compares bytes (section 3.4) recognises no other encoding.

3. Templates

Public keys in the templates are 33-byte compressed keys, pushed as 21 || key. OP_IF is 63, OP_ELSE 67, OP_ENDIF 68, OP_VERIFY 69, OP_CHECKSIG ac and OP_CHECKMULTISIG ae.

3.1 Two-key

OP_IF <K_now> OP_CHECKSIG OP_ELSE GATE(D) OP_VERIFY <K_after> OP_CHECKSIG OP_ENDIF

K_now spends at any time; K_after spends from D. Two uses fix the roles. In a vault, K_now is a recovery key kept offline and K_after the everyday key, so a thief who takes the everyday key must wait for D, during which the recovery key can move the coins. In an inheritance, K_now is the owner's and K_after the beneficiary's, and the owner moves the deadline later by spending the output into a new one (section 5).

3.2 Threshold

OP_IF <m> <K_1> ... <K_n> <n> OP_CHECKMULTISIG OP_ELSE GATE(D) OP_VERIFY <K_after> OP_CHECKSIG OP_ENDIF

with 1 <= m <= n <= 16, m and n pushed as OP_1 to OP_16. The anytime branch needs m of the n keys; K_after spends from D. In a pooled fund, each contribution is an output of its own, the n keys belong to the fund's approvers, who can release it at any time, and K_after is the contributor's, who can take their contribution back if the approvers have not released it by D.

3.3 The gate alone

GATE(D) OP_VERIFY <K> OP_CHECKSIG

The output can be spent only by K and only from D. This is the shape for a lock with no early exit, such as a BRC-190 timelock.

3.4 Recognising a template

Recognition has two independent axes: which template an output is (two-key 3.1, 3.2, or the gate on its own 3.3), and which of the two forms (split or chronicle, section 2.3) its gate is written in. A reader MUST recognise an output by comparing bytes: it reads the keys, m, n and the bytes of NUM(D) at their positions, decodes D, rebuilds the template kind from them in each of the two forms, and accepts the output if one rebuild equals the locking script byte for byte (R8). It MUST NOT accept an output that differs in any byte, and it MUST report the template kind, the form, D and the keys (R9).

A reader MUST recognise, in both forms, every template kind it is built to report. A reader whose purpose is a single kind need recognise only that kind, in both forms: a reader that reports BRC-190 timelocks, for example, reads the gate on its own (3.3) and need not recognise 3.1 or 3.2. A general indexer that reports every template SHOULD recognise all three kinds. A reader that reports a deadline MUST report it as a block height and MUST NOT convert it into a date (BRC-210 section 4.1 states why).

3.5 Minimum value

An after-deadline or reclaim spend has one input and pays its fee from it (section 4), and it is large: it carries the input's whole preimage, which contains the whole locking script, so it is about 1,300 to 1,500 bytes (Security Considerations, "Size and fee"). A builder MUST refuse to create or fund a template output whose value cannot cover that spend's fee, at the prevailing rate, plus one output at or above the network's dust limit (R13); below that the output is consensus-spendable but relay-dead, and the coin is stranded. The sole output of an after-deadline or reclaim spend MUST itself be at least the dust limit (R14).

4. Spending

4.1 The anytime branch

The unlocking script is <sig_now> OP_1 for the two-key template and OP_0 <sig_1> ... <sig_m> OP_1 for the threshold template, the signatures in the order of their keys in the script and the leading OP_0 the dummy element OP_CHECKMULTISIG consumes. Nothing about the transaction is constrained beyond the signatures. A spender SHOULD spend the template output alone, as the only input, with sequence number 0xFFFFFFFF, and pay the fee from it (R11): only such a transaction replaces, at a node, a spend through the gate that is already held there (section 4.3).

4.2 The after-deadline branch

The unlocking script is <sig_after> <preimage> OP_0, or <sig> <preimage> for the gate alone. A spender MUST build the transaction so that (R3, R4, R5, R12, R14):

  1. it has one input, the template output, and pays its fee from it;
  2. its nLockTime lies in [D, 500,000,000);
  3. that input's sequence number is 0xFFFFFFFE;
  4. the pushed preimage is the input's SIGHASH_ALL | SIGHASH_FORKID preimage, built with the whole locking script as scriptCode;
  5. its sole output is at least the network dust limit (R14; section 3.5).

The spender SHOULD sign sig_after with SIGHASH_ALL | SIGHASH_FORKID too, so that the signature and the gate commit to the same transaction, and SHOULD check before broadcasting that the double SHA-256 of the preimage equals the signature hash its signing library computes (R6). The gate does not read the transaction version; version 1 and version 2 spends are both valid (the vectors include each).

4.3 When the spend can be mined

The gate is a script check. It decides whether a transaction is valid, and the transaction's own lock decides when it can be mined. A transaction with nLockTime = L below 500,000,000 and an input whose sequence number is below 0xFFFFFFFF is final only in a block whose height is greater than L; a node compares with the strict < ([FINAL]). So a spend with nLockTime = D can first be mined in block D + 1, and a node accepts it into its main pool once the chain is at D. (The Genesis specification's text says "greater or equal"; the node implements the strict comparison, and so does this BRC.)

A node that receives the spend earlier holds it in its non-final pool and relays it, unless it is configured to keep no such pool, in which case it refuses it; it never mines it early ([NONFINAL]). It checks that pool for transactions that have become final every ten minutes by default, so a held spend can reach the main pool some minutes after the tip reaches D. While it is held, the node refuses a final transaction that spends the same output, except one that spends exactly the same inputs with every sequence number 0xFFFFFFFF, which replaces it. Because of the one-input rule, the anytime branch's spend (R11) is such a transaction, and because of the sequence rule the held spend can have had no earlier replacement, so the anytime spend is its first and its allowance is untouched.

The anytime branch and the after-deadline branch can both be valid at the same moment from block D + 1. Whichever spend is mined first takes the coins.

5. Moving the deadline (informative)

The deadline is an absolute height written into the locking script. No script can read the current height, and a spender chooses nLockTime freely, so a delay counted from a later event (a withdrawal "N blocks after it is requested") cannot be enforced against the after-deadline key. The holder of the anytime key moves the deadline instead: they spend the output, through the anytime branch, into a new template output with the same keys and a later D. A wallet that does this for an inheritance gives the owner a check-in; for a vault, it keeps a stolen everyday key facing a delay. A party that watches the old output (the beneficiary's wallet, for example) can follow the move by reading the spending transaction. A wallet that moves a deadline SHOULD create exactly one output that is the same template with the same keys, so a follower can identify the new coin without ambiguity: that output is the new coin, and its D is the new deadline. A follower that finds no such output treats the coin as spent away, not moved. A follower that finds more than one SHOULD keep watching every candidate rather than abandoning the record as terminal, because the move cannot be told from a payment to a look-alike output by the script alone; which candidate is the true continuation is resolved out of band, and a re-import of the watched record MUST be able to revive it while the coin is not genuinely spent away.

6. Choosing a form

The split form uses only opcodes that every post-Genesis interpreter runs. The chronicle form is ten bytes shorter and uses OP_LEFT and OP_RIGHT, which the Chronicle upgrade re-enabled ([CHRONICLE]); it assumes those opcodes occupy the code points 0xb4 and 0xb5. A node runs them only in the script of an output created at or after the Chronicle activation height (mainnet 943,816), for a spend of any version. On a chain where 0xb4 and 0xb5 are still OP_NOP5 and OP_NOP6, and in the script of an output created before Chronicle, they do nothing: the field-extraction steps that should cut nLockTime and the sequence number out of the preimage become no-ops, the OP_WITHIN bound and the sequence comparison then read the wrong stack items, and the gated branch fails closed rather than passing wrongly. The failure is safe, in that no coin is spent early, but it leaves a chronicle-form coin unspendable there; a node's default policy in any case refuses to run the re-enabled opcodes in an older output's script. An interpreter without OP_LEFT and OP_RIGHT, such as one a wallet uses to check an unconfirmed incoming transaction before it is mined, cannot evaluate a chronicle-form spend at all and must defer to the node. For these reasons the chronicle form is not interoperable: a builder SHOULD use the split form as the default (R10), and SHOULD use the chronicle form only where it controls the validator and knows the opcodes are enforced. A reader MUST recognise both forms (R8).

7. Summary of requirements

#RoleRequirement
R1builderMUST refuse D outside 1 <= D < 500,000,000.
R2builderMUST build the gate and the templates exactly as in sections 2 and 3, with NUM(D) minimal and keys compressed.
R3spenderMUST set nLockTime in [D, 500,000,000) on an after-deadline spend.
R4spenderMUST set the spending input's sequence number to 0xFFFFFFFE on an after-deadline spend.
R5spenderMUST push the input's SIGHASH_ALL | SIGHASH_FORKID preimage, with the whole locking script as scriptCode.
R6spenderSHOULD sign with SIGHASH_ALL | SIGHASH_FORKID and check the preimage's hash against its own signature hash before broadcasting.
R7spender, readerAn interpreter used to evaluate a gate MUST accept script numbers of at least 65 bytes.
R8readerMUST recognise a template by rebuilding it byte for byte, in both forms.
R9readerMUST report the template, the form, D as a block height, and the keys; MUST NOT accept a near match.
R10builderSHOULD use the split form.
R11spenderSHOULD spend the template output alone, with sequence number 0xFFFFFFFF, on the anytime branch.
R12spenderMUST spend the template output alone on the after-deadline branch.
R13builderMUST refuse to create or fund a template output whose value cannot cover an after-deadline spend's fee plus one output at or above the network dust limit.
R14spenderMUST make the sole output of an after-deadline or reclaim spend at least the network dust limit.

Test Vectors

The vectors fix the keys, the deadline, the funded output and every spending transaction, so that each can be rebuilt from this document. They were generated by the reference implementation and checked against two interpreters that share no code with it: the [TS-SDK] interpreter (version 1.10.4, the split form; it does not implement OP_LEFT and OP_RIGHT) and SV-Node's own, through its verifyscript RPC on a regtest chain with Genesis and Chronicle active (SV-Node v1.2.2, both forms). All 72 cases agree with the node, and every split-form case with the SDK.

Keys, deadline and funded output

Each private key is the SHA-256 of a , the UTF-8 string timelock covenant test vector: followed by the role. They are test keys and protect nothing.

RoleLabel suffixPublic key
anytimeanytime key02abc4a7b45cb0559a7ce7b2268d842dbdbe87b4848d9b15950590f29100303410
afterafter-deadline key03da24677340fdf984bb2340b6e88607349834e0044e0d34041383a610e7a72f11
approver 1approver 10327de79105004832937313d2b56e2e52d6e61bab59c02b38057c8ae59ccaec097
approver 2approver 20266e0c322096edf965da13524c94e2413484cbf4cfca2a7873747ec73c9eebc8f
approver 3approver 302a3940064c817c59744b0f4ff0200f022fb88a5d82158bcdd35f0335878318dbb
  • D = 840000.
  • The funded output is output 0 of a transaction whose txid, in the usual display order, is fe962404dcb1c22c6384eca59fa63ea9fc7b23f2b4ebda23f4361f49b1b00ae6, with value 100000 satoshis and the template's locking script.
  • Every spending transaction has one input (that outpoint, its script the case's unlocking script) and one output: 99000 satoshis to the script of the after-deadline key, 76a9145eb85c2c837384ef9f23fb5818248d6ae86d634b88ac. Its version, nLockTime and sequence number are given per case. The a second input cases add, after it, output 0 of the transaction whose txid is b0d5a863d3d45985a8e149304065b7a09e7fdf8ae31560fcf8f8c1446cb7f4d9, with an empty script and the same sequence number; only the first input is evaluated.
  • Signatures are deterministic ([RFC6979]), low-S, with hash type 0x41.

Template scripts

TemplateFormSize (bytes)SHA-256 of the locking script
the gate on its own (2)split9984068289898cc84eaf0179c713e7e4371b72baef2ec77233e2442e3ade9698da0
gate and one key (3.3)split1034d7abb4e3d449442edca86585cc162f6658ae99bf9f81c9d72a991547256ca5f0
two-key (3.1)split1072a86db5e7751e855ca2cc01cf70f0b841248c19514980aa650131d16d890ae571
threshold, 2 of 3 (3.2)split1142373cb6ff56e4667bb0f8f8cf5576a6b8c3d0d17c57e2e689d1296b07c9a13052
the gate on its own (2)chronicle988047f44b6d14d898ad218adf2d89ea6f32196c90042227154c5d5129a693ae5e9
gate and one key (3.3)chronicle10248e7ae882d89d81a4d338deee1e3262f2eef586c676c2e0e1ef2a64c66c3bf405
two-key (3.1)chronicle10628a1df59c401e0c42f5ec9dde5c61a368338b91ab4e1603d664041feaa94d9881
threshold, 2 of 3 (3.2)chronicle1132522c1ec73435c94607989f22f7d8ed9ed861f350de51b2293d01c16d289f0973

The threshold template is 2 of the three approver keys, in the order of the table above. For D = 840000 the split gate alone (section 2, without section 3.3's key) is 998 bytes with SHA-256 4068289898cc84eaf0179c713e7e4371b72baef2ec77233e2442e3ade9698da0, the chronicle gate 988 bytes with SHA-256 047f44b6d14d898ad218adf2d89ea6f32196c90042227154c5d5129a693ae5e9.

Spending cases

For each template and form, these spends were evaluated. digest is the double SHA-256 of the preimage, in the order it is hashed, which is the message the gate's forced signature and sig_after both sign; a spend that pushes a preimage of another transaction keeps that other transaction's preimage and so fails. ZA is the length, in bytes, of the script number Z * A in step 3 of section 2.1 for the valid after-deadline spends: both lengths, 64 and 65, occur.

The gate on its own (2), split form

CaseValidVersionInputsSequencetxiddigestZA
the gate alone, at the deadlineyes21840000fffffffeba58e412b414d2a27326f952381e91eeedb965d79b7051bf1fa6f21eec9533503168ca3609f8ef8e52ac64525859dd75bcc8e8acc1146d32d61e62f4af95016f64
the gate alone, finality bypassno21840000ffffffff93441ed3e784bccefab48ef9005c621c276ada43f8cc5b4ac091b3ff9f96e7baa051e83f6dec0010ae7e4d6f431791c507c05888af486681dcd70deaa7ad4e04

Gate and one key (3.3), split form

CaseValidVersionInputsnLockTimeSequencetxiddigestZA
after-deadline spend at the deadlineyes21840000fffffffe0090090a0391fa530c44db0e66597c394085861ca8723a074163ad5685b584b9815b030f1a93abd2749d831809ad2dc2425d9daf2eea852a17035bdbe599488b64
after-deadline spend, a later heightyes21845000fffffffe27b981efcf9fb9802be2242585359d30c0904585164c0c120d678c382f49c47254c291d00bf7194341dbf4b234e33fd18d78856c43188c2dda6d9503117dda5d64
after-deadline spend, version 1yes11840000fffffffe4af8f3601a87ff7d0af6a53119c5c4ea6c699b266a4a9cb17a52daa2284175e645e3bd644c43f2e69747c000ae71eb3ca53a764eec2cd9c32b3a30ef3f0184d064
one block earlyno21839999fffffffe87ce14237cb911cda1f3c142fef05e3e8d911d402a2e3f4a2f2e4ce529871511857d6abc01364ba584f05d138d891fdbf4bab4429ea2e096a1e9ffff1eb69583
a timestamp-type nLockTimeno21500000001fffffffe131cd7407a5508c9277c62bfde4faff8622f62950b600d32ad7c2bb819e22b9c7435da70d83d46e09462f128f377010c47eaf8ae4b40f3f4e37dfa62c67cf477
the top bit setno212148323648fffffffe276f6a15ac16f3dfb3515a02f9d64b02dc5dda1a54edeea08b56a93f9888e4c53d2e79868ae64d96e31a226ef9fa13c453c8035dd903148782250924a284a870
finality bypassno21840000ffffffff4d91ba94fcbe5a70b63c5197512c53cfa354b45b4b0809bb36f0b8544391f5e7b3ae084cc469efadeb4a06dd96c2f0bc856550e5e93ef843e8ba069ff533e65d
another non-final sequenceno21840000fffffffd809048f66276b04f955f63e96257c1540aaf13ed621d8c0be3fa63354bc04f916b4930283a2ebe6c5db38933e68abc94defe7f6717ded9c5fdd60fb422e913dd
a second inputno22840000fffffffe4264b96fff847ff101c35543fedd298f7375ed320ce7b0dbd54e429c6b89085713368df103e12a8ef5ed69ee8cb9997d10770dd8395b2120f348349a2de86fdc
a preimage of another transactionno21840000fffffffec88cea43509c9de3df52eb59f79e3279f04062213650c3375a5eea4313e7b8e2815b030f1a93abd2749d831809ad2dc2425d9daf2eea852a17035bdbe599488b
the gate alone with its key, another key's signatureno21840000fffffffe8cb42321ec1fdd099b493be766886d139aaea39e8db9b3c93f9b071f04601157815b030f1a93abd2749d831809ad2dc2425d9daf2eea852a17035bdbe599488b

Two-key (3.1), split form

CaseValidVersionInputsnLockTimeSequencetxiddigestZA
anytime branch, no deadlineyes210ffffffffb961d1d0eed2e6f42ffe9c054faeb6a2e351cb6e0b35b230c239a3a8df45c70e419130f872d74bcd23ae4c72b16e97ab585cc619a67921b55c1cd6a33d4590d1
after-deadline spend at the deadlineyes21840000fffffffe33aff459382b2eef3953374145724d7eb592ce1b784469e2b80c6cd8d4b57df10e50d2d930b4ada70e16d1f6fd6dd3a85360aa5e6822054572f9922c32270df564
after-deadline spend, a later heightyes21845000fffffffe842782e72402dece87b9a3cc8fc3262e5328b643593573397918483748c5c07b55c78a54455b0305d94a76c3a0e9d584ebc5088b6ee413da01c0c41498a2669164
after-deadline spend, version 1yes11840000fffffffecb569b2869adb2c1fccaf6bf5affdd7015e4b7a7cb0ea6381e71a24e855acb55281ae6e4c7f82a808cc56faa229c556b4b2b564f6a5456e6052683385276087664
one block earlyno21839999fffffffec9fb534ec2954138c189a36fc14e9c6d7f3de0911e1faca68fd8e4aae152aead8dd5a32addc51e429d6216612d0c12a6e70973b85fdcc1fd7d3dad715d3b7c69
a timestamp-type nLockTimeno21500000001fffffffe4ee3d59779e684fbb5d25a8a347c15e7c19b5abb9482b81375a41e7c488548fa00839529b16db94beaa82dc22501d382cf7545c1f3acd3df050e959a311be4c3
the top bit setno212148323648fffffffe4df1e4358a37427cd00091f76f939c78aec9156954529539bf844fd3621b7c12f056a7f49e2989006a911a043678c323baf9c4acc9139c744ace25891e47b539
finality bypassno21840000ffffffffabcab8eb9206f3f9da73b141bb8aa66171d8801871cc3067490854c04a4f92494326d49ef258ef0cdebe1cf04b863469b67a8b27c06150464decc4eb1324bb7a
another non-final sequenceno21840000fffffffddfe390b7d24ba33415140261896a4ba54fc4e8b401972ce7f645dbd2336cb3ce981df2b3a041a93c6e179bc45383b987cc1e030414c59a99a31d7820e7ae54d7
a second inputno22840000fffffffe2cb7a72021355539ff00cf559d9ba5ad331b8d4dbf484aea19d6ba0764cd78fa5966bb41f12b15d5eba0ec4391668edeb41f92c4dc61f806bdbdf7aa30982fd8
a preimage of another transactionno21840000fffffffecb09e18c5998861b2231a148afbaa07eb1c3f9bd1c23b8b7af7e7e615f9985fc0e50d2d930b4ada70e16d1f6fd6dd3a85360aa5e6822054572f9922c32270df5
after-deadline branch, the anytime key's signatureno21840000fffffffe886e005835ccc7386883be2b86d62b14e602492e67b032c08b02ec5aea885d0d0e50d2d930b4ada70e16d1f6fd6dd3a85360aa5e6822054572f9922c32270df5

Threshold, 2 of 3 (3.2), split form

CaseValidVersionInputsnLockTimeSequencetxiddigestZA
2-of-3 anytime branchyes210ffffffffca3e0747a4db2219b3dbd836dec3c2d7672d2731174c9359696f7f0854e5e0720432a64765d3aa4d725cb9692345b98ba0a4811b96329e397c47495204bee62b
after-deadline spend at the deadlineyes21840000fffffffe87cd4829a18fdb9e3b78b95427544962746f5d7c5ebaed8cece974604c2b1ef3cc967fc0cebd448c14f7495545ff5ac5d4d33f17c93f5c2762321b0cfb2ffe5f65
after-deadline spend, a later heightyes21845000fffffffeb03ce185cfe5cf8550b2ae86637a405e43a977eb77a973787b067986c808ac4c10d4de82e4d6eaf8c7c4fd663d5a290ea5890a479b2296baec8a8641eaf0e01264
after-deadline spend, version 1yes11840000fffffffee086050503ff5ce0fa3e3dc7613024f8241288bbadba8b09425e9ebf1c646f2e1bd9bea54d03151fb91e94c3066c5cf9d79200924ce38285dbb40270c9ca50d664
one block earlyno21839999fffffffe66b0e4d4492eba9427affc3a1d6944c9815f8e60f3fcf2365d3df44b3dbf8064ed5c4cb174658b78f4c7d2a73cec59c31586c30e73bbbdd01bbb03492fa7dd1b
a timestamp-type nLockTimeno21500000001fffffffe112bef6f1ed3563098ca6f97bae2d91b34a41029eadb6d6eb0e59d741e3097cd56e76fbdd0fadc1ce416765e066bf39431640517543dfa4ec95649888bc091c3
the top bit setno212148323648fffffffee1dd207b72aa10be1669dd82313a3bb40c14e860022f7f5d1f6b7b94d2486ca3c8b644db5161d8eb6c9807df6a242782c6decb46cbe46041cc09694322f7807f
finality bypassno21840000ffffffff5f52aab1aa5de3e9c0a0bf3568a5c8ce40ad080c30551e4285c4bc932564393c649623f45457e3382492ce89a7166a4b4412fbad93b8faec4deabce0485f4b9c
another non-final sequenceno21840000fffffffda943978c515e720521b32a79ccf6e4b79320b36c7258529c0915cd869c6385d2862c4a84b51375f2c5a698f7ca4dae348bf3ba3594d0ace3c8c2844e04e25bcf
a second inputno22840000fffffffea2aa4cd9b70f1c6897c18acbbe6f82c2992d3d2bf950dda93723fe54717429cc1f50eb2ca54d81cbc14a7464259ef9052dd2ce1bbc10a2fa7a75a14ad3952784
a preimage of another transactionno21840000fffffffe0fdcaa647e40d19cd5233a1028ac0f4f028477a5e2d69b3d47c2624cca7fd5cacc967fc0cebd448c14f7495545ff5ac5d4d33f17c93f5c2762321b0cfb2ffe5f

The gate on its own (2), chronicle form

CaseValidVersionInputsnLockTimeSequencetxiddigestZA
the gate alone, at the deadlineyes21840000fffffffee835443ab0fed154584fd0b113b4adaa26859bd5073fbaa903e15e41e08d27eea8db559591fa667220f46a9f9601b2419a70e0293a0c39d2cd1140cddb48272b64
the gate alone, finality bypassno21840000ffffffff96656933ee7134dbd02055d7c018874a490cf0e88c2c49800624cb4766cb2ad79181a1ecf91de2376b367ea075840e7f07c790db3fb220c5daf482dbf5ce3d85

Gate and one key (3.3), chronicle form

CaseValidVersionInputsnLockTimeSequencetxiddigestZA
after-deadline spend at the deadlineyes21840000fffffffe7ab542beb7dfdf2b464cf30577945a07793b55219c2abb60966cd2a590c01524d556f3103fc97365975ea9c22845033be7b238456dd25bd38ec6c9ccd30f544265
after-deadline spend, a later heightyes21845000fffffffe6080593635f6ec21fec3d2cbce5ba2e513a4cb578bb0cd1ecfa21f3f2931d4d3c6078a334dee23b4a3c93cc6770172df9ff575b1ee1cd66c59367eba38d4786765
after-deadline spend, version 1yes11840000fffffffe5aa090a053b77af5453dcda6ad94cb33e9cede8c1d7a3f26c05a7e5f8e6850fe9a98ef4067a82238374f30927313697d840d17f2caf535db183610b31e7c654664
one block earlyno21839999fffffffe1def413550afecf734dd79ad39aebf896c021eb87cbdd36d2e8fa59421e6adf0ce8e456157ec72a88d80774e65ad4e7e889cb3ac06db2394772f496f19b3c8a7
a timestamp-type nLockTimeno21500000001fffffffe7c64bb265b4bb12729b892c696aa9675e93f108a75d81943b748ff304e7152742fa9716e70d6b33128c576ccc240ca59ca729c97dc311c3ff2162ab173c014bd
the top bit setno212148323648fffffffe593f48d474349f243cbf64179a74d7fec42aba973c451c90c1e04c8901668509d1e414385c917cdda0fcaed36db459ba34b5722eb6de52d48a3408dcd91e255f
finality bypassno21840000ffffffff35829316545520684965d89a95b044abd6ee43fee05ec501810925dec5f8f7a4bb15b5ee9432518eff1f5caeb1903b66762ab6ae1a7ca4c62694802575aeba00
another non-final sequenceno21840000fffffffd705b60399f3ed87aafda731e319b666a3277805bf6d2192866cbb39649f3dbda760717a48a8c09fd80cdb27803d6cf957a62011643638d32d85b71d6c6b70e5e
a second inputno22840000fffffffe89cd1d8993f8529a7e216270e1ee0462b5cfbac8ced077828473b11b40a5825689338db85bf5a36391c69670209367561afabb2cde5805fee2eeca7eb987cc94
a preimage of another transactionno21840000fffffffefe191a3f572b2578ccfa5551455903a3b4865e96d67b429f57ea8e075828d65ed556f3103fc97365975ea9c22845033be7b238456dd25bd38ec6c9ccd30f5442
the gate alone with its key, another key's signatureno21840000fffffffedcc12f9d790bcea52eefc83b590d7b09c01c962a58d22a6e83e35e4d925c22ded556f3103fc97365975ea9c22845033be7b238456dd25bd38ec6c9ccd30f5442

Two-key (3.1), chronicle form

CaseValidVersionInputsnLockTimeSequencetxiddigestZA
anytime branch, no deadlineyes210ffffffff9d2ba01073c2f64389c79aa37273601ea94ce34185ed1c4321d834821a2c22f5a5524d393a72ac11e8a8a32d9fe32433cf8af9c96dcfa2df7b8c452c8dcd2edf
after-deadline spend at the deadlineyes21840000fffffffe7fe240b3fcff7c44bd184874b8569c9dba1eea146e7d2dcc61dafdcc4284639d829d3a185b42924df3c8467d84513e7fdc81e8790d1a72ffc5c1795eab7982cb64
after-deadline spend, a later heightyes21845000fffffffe6aa9b43160ef8d11ec1f2d04e68f8da4459f716cfbead75c7269fb099db20a1a8c5bbab64d32c05055cf97905664cec44c929966d9b10e9a99274073abb819ec64
after-deadline spend, version 1yes11840000fffffffe466a8e60a90c5d4a6c9884af9fd533805e2be9a360f90ef5add900e1f62ddee064aa6589143960d7916d6c31788f5d80de3c8174a735f27e51c84c146a5bc4b164
one block earlyno21839999fffffffef2be56ed205ef5e15bcb019f1fd94d1bbd2bce8332d9dbb77ff38268df08ed55c51f50c20f5acc7bab4bf291a82353e4abe3d0371abe3cdc9e6654b467379670
a timestamp-type nLockTimeno21500000001fffffffe2d907dbb68428be8c82755ded636b5335f258aca3f5e1b9fb83b0307cc2c630d14407fdb6996441e2bc65f30d8bdf23ab7a560b2921b15a4b2aeec6bfba81c1d
the top bit setno212148323648fffffffe0e44fa807a22c2592213f616bde1dd31731ef978ed31b86d74ac7a52c06b60733643792031ae39797f3a1dfc046a9cb1514b11091198a988ca6f8248b9dada08
finality bypassno21840000ffffffff013fd5c69f583c2dc4bccae274a8862a46b3df58587f41d969d358f8bc9be3e88f88ab7abf1855687c661437e6480ae5765f0973945102fd7e09dec85548ceb1
another non-final sequenceno21840000fffffffdc6036db5461f2e20406d32f29ff1efc686d81cec419cc06fa131789eb08326dd37e3bf0777c7361dadc51a57ce95420abbd08fee032c66034143e256ee903605
a second inputno22840000fffffffebfbec399a1f0968849c19b200d9e08f4ec254dde61f65f3097f9e18992a8c5de559ad22fb3c7aa5b6cbbf470ab4fdae8502905f39bc863be37fffaa604233910
a preimage of another transactionno21840000fffffffef9a628e18c7e799bafcec2eb6719bc014d5f8c80aca73cc402c6fb2a16da644b829d3a185b42924df3c8467d84513e7fdc81e8790d1a72ffc5c1795eab7982cb
after-deadline branch, the anytime key's signatureno21840000fffffffe411bc504846b6c02eaa17fadb1cf72696b24d26a67c94547ff9b95a4ff7f7193829d3a185b42924df3c8467d84513e7fdc81e8790d1a72ffc5c1795eab7982cb

Threshold, 2 of 3 (3.2), chronicle form

CaseValidVersionInputsnLockTimeSequencetxiddigestZA
2-of-3 anytime branchyes210fffffffff19bc0a0e424feebee7312553a8bc58b0f4cf27b7b5c309a462f2f5548f925e9529cfd3b69e56e5a0ddb11be0650533ad7369886e62dc264d5589efb52754039
after-deadline spend at the deadlineyes21840000fffffffe1bb7c1980e3efed0089597f83536439e0ce979fa92ca1b008e53b73e21d5e296f79f3f916a1170114019d703dfe7c06f65356cee57d804a88dc171888c14030d65
after-deadline spend, a later heightyes21845000fffffffe1d4cb98f9bb1b55c0830e6e5f3d013ed56ca02ce52b077103425b98b0a8583a6efdbb99bee1481809d8a397439195692c04398bb84458628c83078e060edf5f965
after-deadline spend, version 1yes11840000fffffffec81e0d03c791e479f4dc0b1e5b5ddc8a5ed544fd06d900a75cf5bd9c66e8c9d08df92b9175fcd09845f385e9ee4ad3a5124efef3bd57e2536d679e319a1d671d64
one block earlyno21839999fffffffe1553c0d1fc078ee47e27db506969d69cc2ad67c88beb53a5e9fb1fd26d059940e57c9f8826b2a03455ce9e6d46b11ade48f54badcb42d0c45976b87a9541c35e
a timestamp-type nLockTimeno21500000001fffffffedcc5016f08c36c14f85f27d006ff86ac010cb894ce194421304bf8ae912cc50fe1e7254570ca16c4744b23ee939a5d5c27a6a88452258d75bd04dc6108525d90
the top bit setno212148323648fffffffeb1fa1545451bf60a6a0e6d2b16a0f14ad0474f8d3dbadb9e4ab8ed148f124a03f3550e0ad32de9dc98a28d7c672cdfb0593b611571038745fa616c2338c5687c
finality bypassno21840000ffffffff123601d915a74d95a46fc9d06195cc34d72e1eb7fea40cdf6fbdd7f8ad39eb47ea2f1ce07b4c07c4544e3747c147303aaaab07108904602ea4a293b9f02aebe9
another non-final sequenceno21840000fffffffd33eed5fba7d954b0ab5d3bb5b910ea6b870ad7cb61a2c6c69d0ab3afc691ab3a0aa122e3396e746e27851fd259f2e78cbbc9fc3e1b243ef5048b49877d8dd50c
a second inputno22840000fffffffe02435ecf55564b664590ba65ff57f403103e5077fd7e0dfda1c91d5fe39f6a80deaa41c9b3669511ed27c5bf4ce1b737fe1e02af0d02da13da8d68f0a9308fea
a preimage of another transactionno21840000fffffffe305d536b5925829442c89ae5b9463ade3fe9a60e6f30000c47660aff1606ce71f79f3f916a1170114019d703dfe7c06f65356cee57d804a88dc171888c14030d

The failing cases fail where section 2 says they do, on both interpreters: the second input at ONE_INPUT's OP_EQUALVERIFY, the early, timestamp and top-bit spends at the OP_VERIFY after OP_WITHIN, the finality bypass and the other non-final sequence at the OP_VERIFY after the template's gate (with the gate alone, as a false result), the foreign preimage at PART_A's OP_CHECKSIGVERIFY, and the anytime key's signature in the after-deadline branch at the final OP_CHECKSIG.

Implementations

A reference implementation exists, in a wallet whose vaults, inheritances and pooled funds use the templates of sections 3.1 and 3.2, in both forms; it does not build section 3.3's template, which the vectors cover. A gate without the one-input rule was built on a regtest node to demonstrate the pin of the Motivation: a two-input spend through the gate, broadcast before the deadline, was held, the anytime spend was refused (bad-txn-update), and at the deadline the held spend was mined in block D + 1. With the gate of this BRC, the node refused the two-input spend (Script failed an OP_EQUALVERIFY operation) and a spend with sequence number 0xFFFFFFFD, held a one-input one, refused to let the after-deadline key re-send it with a higher sequence number, and replaced it with the anytime spend, which was mined, in both forms. Its after-deadline spends of the two-key template (both forms) and of the threshold template were broadcast to SV-Node regtest chains with Genesis and Chronicle active. Spends with a timestamp nLockTime before the deadline, and spends one block early once the chain had passed it, were refused with a script evaluation failure on an OP_VERIFY. Honest spends at the deadline confirmed, in version 1 and version 2 transactions and with PART_A products of 64 and of 65 bytes, on a node with permissive policy settings and on one with the default relay policy (script numbers up to 10,000 bytes, scripts up to 500,000 bytes). The wallet also moves an inheritance's deadline through the anytime branch (section 5), confirmed on a regtest node, and the beneficiary's wallet follows the move and claims after the new deadline.

Mathematical and cryptographic basis

This section states what a passing spend proves and on which assumptions. Write z* for the real signature hash of the input being evaluated, the double SHA-256 of its genuine SIGHASH_ALL | SIGHASH_FORKID preimage read as a big-endian integer, and Z for the double SHA-256, read the same way, of the bytes the unlocking script pushed.

The forced signature authenticates the preimage

PART_A (section 2.1) computes in script s = (Z * A + B) mod N, with A = k^-1 mod N, B = k^-1 * r * d mod N, the fixed private key d = 2, the fixed nonce k = 3, and r the x-coordinate of 3G reduced mod N; it puts s in low-S form, encodes (r, s) as DER, and checks it with OP_CHECKSIGVERIFY against P = 2G. OP_CHECKSIG verifies a signature with this r against z* exactly when s = k^-1 * (z* + r * d) mod N. The script set s = k^-1 * (Z + r * d) mod N. The two agree when Z = z* mod N. The low-S fold of step 4 maps s and its complement N - s to the one value OP_CHECKSIG accepts, so the check also passes for the digest whose script s is that complement, Z = -z* - 2 * r * d mod N; the gate passes for Z in these two residue classes mod N and no others.

Z and z* are 256-bit double-SHA-256 digests and N is within about 2^128 of 2^256, so two distinct 256-bit values in one residue class mod N differ by exactly N, which forces the larger into a top band of about one digest in 2^128. Each passing class is a single fixed 256-bit target, so any pushed bytes other than the input's genuine preimage that pass the check hash, under double SHA-256, to a fixed value, which is a second-preimage. Under the second-preimage resistance of SHA-256 none can be found, so the pushed bytes of a passing spend are the genuine preimage, and the gate's reads of nLockTime and the input's sequence number (section 2.3) are reads of the real transaction. The private key and nonce are public, which is sound: their only role is to make s computable, and forging a pass would still require a double SHA-256 second-preimage of a fixed target.

The deadline holds in consensus

Given a genuine preimage, the gate enforces D <= nLockTime < 500,000,000 and the input's sequence number = 0xFFFFFFFE. Consensus reads an nLockTime below 500,000,000 as a block height, and a transaction with an input whose sequence number is below 0xFFFFFFFF is final only in a block of height strictly greater than its nLockTime ([FINAL]). So a spend through the gate is mined no earlier than block D + 1. OP_BIN2NUM reads the four nLockTime bytes as a sign-magnitude number, so a value with its top bit set is negative and fails D <= nLockTime, and the upper bound rules out a timestamp-typed value; those are the two values that would otherwise make the comparison worthless.

Each guard is necessary, and the one-input rule is exact

The guards are independent, and each of the four ways to weaken them (the sequence guard has two) is exhibited by a Test Vector that then passes where it must fail. Without the OP_WITHIN upper bound, nLockTime = 500,000,001 is a past Unix time and the spend is final at once. With a sequence rule that admits 0xFFFFFFFF, the transaction is final whatever its nLockTime. Without the exact 0xFFFFFFFE, a held gated spend keeps a replacement path that exhausts a node's replacement allowance while the anytime branch, itself a replacement, is refused. Without the one-input rule, the gated key's holder adds a coin of their own to a spend held as non-final, and the anytime branch, which cannot spend that coin, is refused until D. The one-input rule is hashPrevouts = HASH256(outpoint), which holds exactly when the transaction has that one input, under the collision resistance of SHA-256.

Reader agreement

A reader recognises a template by rebuilding it byte for byte (section 3.4), so it accepts an output only when the output equals one of the finitely many rebuilds for its keys, m, n and D. Two conforming readers therefore report the same template, form, deadline and keys for every output either accepts, and neither accepts a near match.

Security Considerations

What the gate guarantees. A spend through the gate cannot be mined before block D + 1. That rests on three facts: the preimage is the transaction's own (section 2.1), its nLockTime is a block height of at least D and its input's lock is in force (section 2.3), and consensus does not mine a transaction whose lock is in force before its height ([FINAL]). The gate's private key and nonce are public; they make the forced signature computable in script and protect nothing. An error in PART_A makes honest spends fail; it cannot make a false preimage pass, because OP_CHECKSIGVERIFY checks against the real signature hash.

What it does not guarantee. The gate does not constrain the spend's outputs. The after-deadline signature does, when it signs with SIGHASH_ALL, so a spender who uses another hash type for it lets others change what the spend pays. Nothing in the anytime branch is constrained, so the templates protect the after-deadline party only against early spends by that party's own key; the anytime keys can spend at any time, including after D.

Absolute heights. D is fixed when the output is created. A vault or an inheritance whose deadline has passed is open to the after-deadline key until the anytime key moves it (section 5). Wallets that hold the anytime key SHOULD warn before a deadline passes.

The guards are the point. A conforming gate carries all three guards, and each is a MUST: the upper bound of OP_WITHIN (nLockTime below 500,000,000), the sequence rule (the input's sequence number exactly 0xFFFFFFFE, not merely other than 0xFFFFFFFF) and the one-input rule (hashPrevouts equal to the double SHA-256 of the input's own outpoint). An implementation that rewrites the gate, for size or for style, MUST keep every one. Without the bound, or with a sequence rule that admits 0xFFFFFFFF, every output it builds can be spent at once; without the one-input rule, or with a sequence rule that admits other non-final values, its anytime branch can be shut until the deadline. Nothing fails visibly until someone does so. The vectors' a timestamp-type nLockTime, finality bypass, another non-final sequence and a second input cases exist to catch that.

A two-guard gate is non-conforming. A gate that carries only the bound and the sequence rule, without the one-input rule, is non-conforming. An adversary who holds the gated (after-deadline) key can broadcast, long before D, a spend through the gate that also spends a coin of their own, and every node that holds it then refuses the anytime branch's clawback, which cannot spend that extra coin, until D (Motivation, item 3). The one-input rule is what forecloses that, so a conforming gate always carries it.

Pinning, and what the gate leaves. The one-input and sequence rules close the pin of the Motivation for an anytime spend that follows R11. An anytime spend that adds an input of its own, to pay its fee for example, is refused by a node holding a pending spend through the gate, as before. A threshold template's approvers who release several contributions in one transaction meet the same refusal if any one of them has a pending reclaim; they release that contribution on its own. A node's handling of conflicts is local policy: a miner that never received the pending spend mines the anytime spend whatever its inputs, and a miner can be configured to keep no non-final pool.

Interpreter limits. Section 2.1's product can need a 65-byte script number (R7). An interpreter with a lower cap fails honest spends at random, about one in four, depending on the transaction's hash. A chronicle-form spend cannot be evaluated by an interpreter without OP_LEFT and OP_RIGHT (section 6), so a wallet that checks unconfirmed transactions before accepting them cannot accept one until it is mined.

Malleability. A third party can change a broadcast transaction's id without invalidating it where the unlocking script admits another encoding. In a block at or after the Chronicle height, a transaction of version greater than 1 is exempt from the low-S, null-fail and push-only rules, and from the minimal-push and clean-stack policies ([CHRONICLE]), so a spend of either branch can be mined under another txid with the same effect. A spender that tracks its spend SHOULD look for the spend of the outpoint, not for one txid.

Size and fee. A template is about 1,060 to 1,150 bytes, and an after-deadline spend carries the preimage, which contains the whole locking script, so it is about 1,300 to 1,500 bytes. The fee is paid from the coin (R11, R12).

Dust and stranding. Because an after-deadline spend is large and has one output, a template output funded with too little value cannot produce a spend that both clears the fee and leaves an output at or above the dust limit. Such an output is valid in a block, but no node will relay its spend, so the coin is stranded: consensus-spendable, relay-dead. A builder MUST refuse to create or fund one (R13; section 3.5), and every after-deadline or reclaim spend's sole output MUST clear the dust limit (R14).

Privacy Considerations

A template output is public in full from the moment it is created: its locking script names every key and the deadline D in the clear, and an after-deadline spend carries the whole locking script inside its pushed preimage, so the terms are legible to anyone watching the chain, before and after a spend. The gate's forced-signature key P = 2G is the same in every gate built to this BRC, so it is not a per-output fingerprint, though the template is still distinguishable from an ordinary output by its size and its fixed PART_A prefix. A party that needs the existence of a deadline arrangement to stay private should not place it on chain in a template. Moving a deadline (section 5) links the old output to the new one through the spending transaction by construction, because that link is what lets a watcher follow the move.

References

  • [BRC-21] Push TX. scripts/0021.md
  • [BRC-171] Fixed-Width State in a Covenant's Own Locking Script. state-machines/0171.md
  • [BRC-172] Giving an AI Agent Control of a Delivery Vehicle Without Giving It a Wallet. state-machines/0172.md
  • [BRC-190] Access Gates for Metanet Rooms, section 4.5. apps/0190.md
  • [BRC-210] Derived Collectibles. apps/0210.md
  • [BRC-226] Miner-Enforced Resale-Royalty Covenant Tokens (OP_PUSH_TX). tokens/0226.md
  • [BIP65] P. Todd, OP_CHECKLOCKTIMEVERIFY. https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki
  • [WP-1605] nChain, WP1605: PUSHTX and its Building Blocks. https://nchain.com/wp-content/uploads/2022/03/WP1605_PUSHTX-and-its-Building-Blocks.pdf
  • [BRC-197] Accumulating Right-of-Sale Listings. tokens/0197.md
  • [RFC6979] T. Pornin, Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA). https://www.rfc-editor.org/rfc/rfc6979
  • [GENESIS] The Genesis upgrade: https://github.com/bitcoin-sv-specs/protocol/blob/master/updates/genesis-spec.md, and SV-Node v1.2.3 (commit 6504a3aff65ba97c0f6c80962b033e35ecbfed4b), src/script/interpreter.cpp, EvalScript: OP_CHECKLOCKTIMEVERIFY and OP_CHECKSEQUENCEVERIFY are treated as OP_NOP2 and OP_NOP3 for an input whose spent output was created after Genesis (utxo_after_genesis), and SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS is in the standard flags (src/policy/policy.h).
  • [FINAL] SV-Node v1.2.3, src/validation.cpp, IsFinalTx (if (lockTime < lockTimeLimit) return true;, then every input's sequence number), ContextualCheckBlock (the block's own height) and ContextualCheckTransactionForCurrentBlock (the tip's height plus one); LOCKTIME_THRESHOLD in src/script/script.h.
  • [NONFINAL] SV-Node v1.2.3: src/validation.cpp ( go to their own pool after Genesis), src/time_locked_mempool.cpp (finalisesExistingTransaction, addOrUpdateTransaction, validateUpdateNL, the periodic check, -maxmempoolnonfinal, -mempoolexpirynonfinal, -checknonfinalfreq), src/txmempool.cpp, CTxMemPool::CheckTxConflicts (txn-mempool-conflict).
  • [CHRONICLE] The Chronicle release, SV-Node v1.2.0 (mainnet activation height 943,816): https://github.com/bitcoin-sv/bitcoin-sv/releases/tag/v1.2.0, and v1.2.3 src/script/interpreter.cpp: the rules a transaction of version greater than 1 is exempt from (EnforceNonMalleability), and OP_LEFT, OP_RIGHT and the other re-enabled opcodes for outputs created after Chronicle (utxo_after_chronicle).
  • [SIGHASH] SV-Node v1.2.3, src/script/interpreter.cpp, SignatureHashBIP143 (the preimage with SIGHASH_FORKID, used unless the 0x20 bit selects the original digest), and [BIP143] https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki.
  • [TS-SDK] The BSV TypeScript SDK, Spend, version 1.10.4: https://github.com/bsv-blockchain/ts-sdk
Was this helpful?

Search Beersy

Search standards by number, title, author or topic