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 unlocking script 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:
- The finality bypass. Consensus ignores
nLockTimewhen every input's sequence number is0xFFFFFFFF. A gate that comparesnLockTimewith the deadline and stops there is satisfied by a transaction carrying the deadline innLockTimeand0xFFFFFFFFin its one sequence number. That transaction is final and can be mined at once. - The type confusion. Consensus reads an
nLockTimeof 500,000,000 or more as a Unix time. A gate that comparesnLockTime >= Dagainst a block heightDis satisfied by 500,000,001, a moment in 1985 that has long passed, so the transaction is final at once. [BIP65] avoided this inOP_CHECKLOCKTIMEVERIFYby requiring the two values to be of the same type; a gate in script has to state that rule itself. - 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 beforeD, 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. AtDthe 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 satoshis they have locked until a height, and BRC-210 section 7.4 lets a score require a timelocked mark. 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 scope 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 overlay. 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 covenant'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 nonce, 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 ECDSA 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 outpoint (36), the scriptCode with its length, the input's value (8), the input's sequence number (4), hashOutputs (32),nLockTime(4) and the hash type (4), integers little-endian. With noOP_CODESEPARATORin the locking script, the scriptCode is the whole locking script. - Deadline
D: a block height, an integer with1 <= D < 500,000,000. - Gate: the script of section 2 for a deadline
D, writtenGATE(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 integerxas a script number:OP_0for 0,OP_1toOP_16for 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 stringb.
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:
OP_HASH256, which leaves the 32-byte digestz.REVERSE32, which is(OP_1 OP_SPLIT)repeated 31 times followed by(OP_SWAP OP_CAT)repeated 31 times, thenPUSH(00) OP_CAT OP_BIN2NUM: together these readzas an unsigned big-endian integerZ.NUM(A) OP_MUL NUM(B) OP_ADD NUM(N) OP_MOD:s = (Z * A + B) mod N.OP_DUP NUM(N >> 1) OP_GREATERTHAN OP_IF NUM(N) OP_SWAP OP_SUB OP_ENDIF: the low-S form ofs, which is also below2^255, so that the next step yields a positive 32-byte value.PUSH(20) OP_NUM2BIN REVERSE32:sas 32 bytes, big-endian.- 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, since0x80is a negative zero as a number). 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.OP_SIZE OP_2 OP_SWAP OP_CAT OP_SWAP OP_CAT, thenPUSH(02 21 || 00 || r) OP_SWAP OP_CAT, thenOP_SIZE PUSH(30) OP_SWAP OP_CAT OP_SWAP OP_CAT, thenPUSH(41) OP_CAT: the DER signature30 len 02 21 00 r 02 slen sand the hash type0x41.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:
| Form | X |
Y |
Opcodes beyond Genesis |
|---|---|---|---|
| split | 8254947f758254947f |
820120947f758254947f7704feffffff87 |
none |
| chronicle | 7658b554b4 |
012cb554b404feffffff87 |
OP_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 secp256k1 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 kind an output is (two-key 3.1, threshold 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):
- it has one input, the template output, and pays its fee from it;
- its
nLockTimelies in[D, 500,000,000); - that input's sequence number is
0xFFFFFFFE; - the pushed preimage is the input's
SIGHASH_ALL | SIGHASH_FORKIDpreimage, built with the whole locking script as scriptCode; - 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 tip 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
| # | Role | Requirement |
|---|---|---|
| R1 | builder | MUST refuse D outside 1 <= D < 500,000,000. |
| R2 | builder | MUST build the gate and the templates exactly as in sections 2 and 3, with NUM(D) minimal and keys compressed. |
| R3 | spender | MUST set nLockTime in [D, 500,000,000) on an after-deadline spend. |
| R4 | spender | MUST set the spending input's sequence number to 0xFFFFFFFE on an after-deadline spend. |
| R5 | spender | MUST push the input's SIGHASH_ALL | SIGHASH_FORKID preimage, with the whole locking script as scriptCode. |
| R6 | spender | SHOULD sign with SIGHASH_ALL | SIGHASH_FORKID and check the preimage's hash against its own signature hash before broadcasting. |
| R7 | spender, reader | An interpreter used to evaluate a gate MUST accept script numbers of at least 65 bytes. |
| R8 | reader | MUST recognise a template by rebuilding it byte for byte, in both forms. |
| R9 | reader | MUST report the template, the form, D as a block height, and the keys; MUST NOT accept a near match. |
| R10 | builder | SHOULD use the split form. |
| R11 | spender | SHOULD spend the template output alone, with sequence number 0xFFFFFFFF, on the anytime branch. |
| R12 | spender | MUST spend the template output alone on the after-deadline branch. |
| R13 | builder | MUST 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. |
| R14 | spender | MUST 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 label, the UTF-8 string timelock covenant test vector: followed by the role. They are test keys and protect nothing.
| Role | Label suffix | Public key |
|---|---|---|
| anytime | anytime key |
02abc4a7b45cb0559a7ce7b2268d842dbdbe87b4848d9b15950590f29100303410 |
| after | after-deadline key |
03da24677340fdf984bb2340b6e88607349834e0044e0d34041383a610e7a72f11 |
| approver 1 | approver 1 |
0327de79105004832937313d2b56e2e52d6e61bab59c02b38057c8ae59ccaec097 |
| approver 2 | approver 2 |
0266e0c322096edf965da13524c94e2413484cbf4cfca2a7873747ec73c9eebc8f |
| approver 3 | approver 3 |
02a3940064c817c59744b0f4ff0200f022fb88a5d82158bcdd35f0335878318dbb |
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 P2PKH script of the
after-deadline key,76a9145eb85c2c837384ef9f23fb5818248d6ae86d634b88ac. Its version,nLockTimeand sequence number are given per case. Thea second inputcases add, after it, output 0 of the transaction whose txid isb0d5a863d3d45985a8e149304065b7a09e7fdf8ae31560fcf8f8c1446cb7f4d9, 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
| Template | Form | Size (bytes) | SHA-256 of the locking script |
|---|---|---|---|
| the gate on its own (2) | split | 998 | 4068289898cc84eaf0179c713e7e4371b72baef2ec77233e2442e3ade9698da0 |
| gate and one key (3.3) | split | 1034 | d7abb4e3d449442edca86585cc162f6658ae99bf9f81c9d72a991547256ca5f0 |
| two-key (3.1) | split | 1072 | a86db5e7751e855ca2cc01cf70f0b841248c19514980aa650131d16d890ae571 |
| threshold, 2 of 3 (3.2) | split | 1142 | 373cb6ff56e4667bb0f8f8cf5576a6b8c3d0d17c57e2e689d1296b07c9a13052 |
| the gate on its own (2) | chronicle | 988 | 047f44b6d14d898ad218adf2d89ea6f32196c90042227154c5d5129a693ae5e9 |
| gate and one key (3.3) | chronicle | 1024 | 8e7ae882d89d81a4d338deee1e3262f2eef586c676c2e0e1ef2a64c66c3bf405 |
| two-key (3.1) | chronicle | 1062 | 8a1df59c401e0c42f5ec9dde5c61a368338b91ab4e1603d664041feaa94d9881 |
| threshold, 2 of 3 (3.2) | chronicle | 1132 | 522c1ec73435c94607989f22f7d8ed9ed861f350de51b2293d01c16d289f0973 |
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
| Case | Valid | Version | Inputs | nLockTime | Sequence | txid | digest | ZA |
|---|---|---|---|---|---|---|---|---|
| the gate alone, at the deadline | yes | 2 | 1 | 840000 | fffffffe |
ba58e412b414d2a27326f952381e91eeedb965d79b7051bf1fa6f21eec953350 |
3168ca3609f8ef8e52ac64525859dd75bcc8e8acc1146d32d61e62f4af95016f |
64 |
| the gate alone, finality bypass | no | 2 | 1 | 840000 | ffffffff |
93441ed3e784bccefab48ef9005c621c276ada43f8cc5b4ac091b3ff9f96e7ba |
a051e83f6dec0010ae7e4d6f431791c507c05888af486681dcd70deaa7ad4e04 |
Gate and one key (3.3), split form
| Case | Valid | Version | Inputs | nLockTime | Sequence | txid | digest | ZA |
|---|---|---|---|---|---|---|---|---|
| after-deadline spend at the deadline | yes | 2 | 1 | 840000 | fffffffe |
0090090a0391fa530c44db0e66597c394085861ca8723a074163ad5685b584b9 |
815b030f1a93abd2749d831809ad2dc2425d9daf2eea852a17035bdbe599488b |
64 |
| after-deadline spend, a later height | yes | 2 | 1 | 845000 | fffffffe |
27b981efcf9fb9802be2242585359d30c0904585164c0c120d678c382f49c472 |
54c291d00bf7194341dbf4b234e33fd18d78856c43188c2dda6d9503117dda5d |
64 |
| after-deadline spend, version 1 | yes | 1 | 1 | 840000 | fffffffe |
4af8f3601a87ff7d0af6a53119c5c4ea6c699b266a4a9cb17a52daa2284175e6 |
45e3bd644c43f2e69747c000ae71eb3ca53a764eec2cd9c32b3a30ef3f0184d0 |
64 |
| one block early | no | 2 | 1 | 839999 | fffffffe |
87ce14237cb911cda1f3c142fef05e3e8d911d402a2e3f4a2f2e4ce529871511 |
857d6abc01364ba584f05d138d891fdbf4bab4429ea2e096a1e9ffff1eb69583 |
|
| a timestamp-type nLockTime | no | 2 | 1 | 500000001 | fffffffe |
131cd7407a5508c9277c62bfde4faff8622f62950b600d32ad7c2bb819e22b9c |
7435da70d83d46e09462f128f377010c47eaf8ae4b40f3f4e37dfa62c67cf477 |
|
| the top bit set | no | 2 | 1 | 2148323648 | fffffffe |
276f6a15ac16f3dfb3515a02f9d64b02dc5dda1a54edeea08b56a93f9888e4c5 |
3d2e79868ae64d96e31a226ef9fa13c453c8035dd903148782250924a284a870 |
|
| finality bypass | no | 2 | 1 | 840000 | ffffffff |
4d91ba94fcbe5a70b63c5197512c53cfa354b45b4b0809bb36f0b8544391f5e7 |
b3ae084cc469efadeb4a06dd96c2f0bc856550e5e93ef843e8ba069ff533e65d |
|
| another non-final sequence | no | 2 | 1 | 840000 | fffffffd |
809048f66276b04f955f63e96257c1540aaf13ed621d8c0be3fa63354bc04f91 |
6b4930283a2ebe6c5db38933e68abc94defe7f6717ded9c5fdd60fb422e913dd |
|
| a second input | no | 2 | 2 | 840000 | fffffffe |
4264b96fff847ff101c35543fedd298f7375ed320ce7b0dbd54e429c6b890857 |
13368df103e12a8ef5ed69ee8cb9997d10770dd8395b2120f348349a2de86fdc |
|
| a preimage of another transaction | no | 2 | 1 | 840000 | fffffffe |
c88cea43509c9de3df52eb59f79e3279f04062213650c3375a5eea4313e7b8e2 |
815b030f1a93abd2749d831809ad2dc2425d9daf2eea852a17035bdbe599488b |
|
| the gate alone with its key, another key's signature | no | 2 | 1 | 840000 | fffffffe |
8cb42321ec1fdd099b493be766886d139aaea39e8db9b3c93f9b071f04601157 |
815b030f1a93abd2749d831809ad2dc2425d9daf2eea852a17035bdbe599488b |
Two-key (3.1), split form
| Case | Valid | Version | Inputs | nLockTime | Sequence | txid | digest | ZA |
|---|---|---|---|---|---|---|---|---|
| anytime branch, no deadline | yes | 2 | 1 | 0 | ffffffff |
b961d1d0eed2e6f42ffe9c054faeb6a2e351cb6e0b35b230c239a3a8df45c70e |
419130f872d74bcd23ae4c72b16e97ab585cc619a67921b55c1cd6a33d4590d1 |
|
| after-deadline spend at the deadline | yes | 2 | 1 | 840000 | fffffffe |
33aff459382b2eef3953374145724d7eb592ce1b784469e2b80c6cd8d4b57df1 |
0e50d2d930b4ada70e16d1f6fd6dd3a85360aa5e6822054572f9922c32270df5 |
64 |
| after-deadline spend, a later height | yes | 2 | 1 | 845000 | fffffffe |
842782e72402dece87b9a3cc8fc3262e5328b643593573397918483748c5c07b |
55c78a54455b0305d94a76c3a0e9d584ebc5088b6ee413da01c0c41498a26691 |
64 |
| after-deadline spend, version 1 | yes | 1 | 1 | 840000 | fffffffe |
cb569b2869adb2c1fccaf6bf5affdd7015e4b7a7cb0ea6381e71a24e855acb55 |
281ae6e4c7f82a808cc56faa229c556b4b2b564f6a5456e60526833852760876 |
64 |
| one block early | no | 2 | 1 | 839999 | fffffffe |
c9fb534ec2954138c189a36fc14e9c6d7f3de0911e1faca68fd8e4aae152aead |
8dd5a32addc51e429d6216612d0c12a6e70973b85fdcc1fd7d3dad715d3b7c69 |
|
| a timestamp-type nLockTime | no | 2 | 1 | 500000001 | fffffffe |
4ee3d59779e684fbb5d25a8a347c15e7c19b5abb9482b81375a41e7c488548fa |
00839529b16db94beaa82dc22501d382cf7545c1f3acd3df050e959a311be4c3 |
|
| the top bit set | no | 2 | 1 | 2148323648 | fffffffe |
4df1e4358a37427cd00091f76f939c78aec9156954529539bf844fd3621b7c12 |
f056a7f49e2989006a911a043678c323baf9c4acc9139c744ace25891e47b539 |
|
| finality bypass | no | 2 | 1 | 840000 | ffffffff |
abcab8eb9206f3f9da73b141bb8aa66171d8801871cc3067490854c04a4f9249 |
4326d49ef258ef0cdebe1cf04b863469b67a8b27c06150464decc4eb1324bb7a |
|
| another non-final sequence | no | 2 | 1 | 840000 | fffffffd |
dfe390b7d24ba33415140261896a4ba54fc4e8b401972ce7f645dbd2336cb3ce |
981df2b3a041a93c6e179bc45383b987cc1e030414c59a99a31d7820e7ae54d7 |
|
| a second input | no | 2 | 2 | 840000 | fffffffe |
2cb7a72021355539ff00cf559d9ba5ad331b8d4dbf484aea19d6ba0764cd78fa |
5966bb41f12b15d5eba0ec4391668edeb41f92c4dc61f806bdbdf7aa30982fd8 |
|
| a preimage of another transaction | no | 2 | 1 | 840000 | fffffffe |
cb09e18c5998861b2231a148afbaa07eb1c3f9bd1c23b8b7af7e7e615f9985fc |
0e50d2d930b4ada70e16d1f6fd6dd3a85360aa5e6822054572f9922c32270df5 |
|
| after-deadline branch, the anytime key's signature | no | 2 | 1 | 840000 | fffffffe |
886e005835ccc7386883be2b86d62b14e602492e67b032c08b02ec5aea885d0d |
0e50d2d930b4ada70e16d1f6fd6dd3a85360aa5e6822054572f9922c32270df5 |
Threshold, 2 of 3 (3.2), split form
| Case | Valid | Version | Inputs | nLockTime | Sequence | txid | digest | ZA |
|---|---|---|---|---|---|---|---|---|
| 2-of-3 anytime branch | yes | 2 | 1 | 0 | ffffffff |
ca3e0747a4db2219b3dbd836dec3c2d7672d2731174c9359696f7f0854e5e072 |
0432a64765d3aa4d725cb9692345b98ba0a4811b96329e397c47495204bee62b |
|
| after-deadline spend at the deadline | yes | 2 | 1 | 840000 | fffffffe |
87cd4829a18fdb9e3b78b95427544962746f5d7c5ebaed8cece974604c2b1ef3 |
cc967fc0cebd448c14f7495545ff5ac5d4d33f17c93f5c2762321b0cfb2ffe5f |
65 |
| after-deadline spend, a later height | yes | 2 | 1 | 845000 | fffffffe |
b03ce185cfe5cf8550b2ae86637a405e43a977eb77a973787b067986c808ac4c |
10d4de82e4d6eaf8c7c4fd663d5a290ea5890a479b2296baec8a8641eaf0e012 |
64 |
| after-deadline spend, version 1 | yes | 1 | 1 | 840000 | fffffffe |
e086050503ff5ce0fa3e3dc7613024f8241288bbadba8b09425e9ebf1c646f2e |
1bd9bea54d03151fb91e94c3066c5cf9d79200924ce38285dbb40270c9ca50d6 |
64 |
| one block early | no | 2 | 1 | 839999 | fffffffe |
66b0e4d4492eba9427affc3a1d6944c9815f8e60f3fcf2365d3df44b3dbf8064 |
ed5c4cb174658b78f4c7d2a73cec59c31586c30e73bbbdd01bbb03492fa7dd1b |
|
| a timestamp-type nLockTime | no | 2 | 1 | 500000001 | fffffffe |
112bef6f1ed3563098ca6f97bae2d91b34a41029eadb6d6eb0e59d741e3097cd |
56e76fbdd0fadc1ce416765e066bf39431640517543dfa4ec95649888bc091c3 |
|
| the top bit set | no | 2 | 1 | 2148323648 | fffffffe |
e1dd207b72aa10be1669dd82313a3bb40c14e860022f7f5d1f6b7b94d2486ca3 |
c8b644db5161d8eb6c9807df6a242782c6decb46cbe46041cc09694322f7807f |
|
| finality bypass | no | 2 | 1 | 840000 | ffffffff |
5f52aab1aa5de3e9c0a0bf3568a5c8ce40ad080c30551e4285c4bc932564393c |
649623f45457e3382492ce89a7166a4b4412fbad93b8faec4deabce0485f4b9c |
|
| another non-final sequence | no | 2 | 1 | 840000 | fffffffd |
a943978c515e720521b32a79ccf6e4b79320b36c7258529c0915cd869c6385d2 |
862c4a84b51375f2c5a698f7ca4dae348bf3ba3594d0ace3c8c2844e04e25bcf |
|
| a second input | no | 2 | 2 | 840000 | fffffffe |
a2aa4cd9b70f1c6897c18acbbe6f82c2992d3d2bf950dda93723fe54717429cc |
1f50eb2ca54d81cbc14a7464259ef9052dd2ce1bbc10a2fa7a75a14ad3952784 |
|
| a preimage of another transaction | no | 2 | 1 | 840000 | fffffffe |
0fdcaa647e40d19cd5233a1028ac0f4f028477a5e2d69b3d47c2624cca7fd5ca |
cc967fc0cebd448c14f7495545ff5ac5d4d33f17c93f5c2762321b0cfb2ffe5f |
The gate on its own (2), chronicle form
| Case | Valid | Version | Inputs | nLockTime | Sequence | txid | digest | ZA |
|---|---|---|---|---|---|---|---|---|
| the gate alone, at the deadline | yes | 2 | 1 | 840000 | fffffffe |
e835443ab0fed154584fd0b113b4adaa26859bd5073fbaa903e15e41e08d27ee |
a8db559591fa667220f46a9f9601b2419a70e0293a0c39d2cd1140cddb48272b |
64 |
| the gate alone, finality bypass | no | 2 | 1 | 840000 | ffffffff |
96656933ee7134dbd02055d7c018874a490cf0e88c2c49800624cb4766cb2ad7 |
9181a1ecf91de2376b367ea075840e7f07c790db3fb220c5daf482dbf5ce3d85 |
Gate and one key (3.3), chronicle form
| Case | Valid | Version | Inputs | nLockTime | Sequence | txid | digest | ZA |
|---|---|---|---|---|---|---|---|---|
| after-deadline spend at the deadline | yes | 2 | 1 | 840000 | fffffffe |
7ab542beb7dfdf2b464cf30577945a07793b55219c2abb60966cd2a590c01524 |
d556f3103fc97365975ea9c22845033be7b238456dd25bd38ec6c9ccd30f5442 |
65 |
| after-deadline spend, a later height | yes | 2 | 1 | 845000 | fffffffe |
6080593635f6ec21fec3d2cbce5ba2e513a4cb578bb0cd1ecfa21f3f2931d4d3 |
c6078a334dee23b4a3c93cc6770172df9ff575b1ee1cd66c59367eba38d47867 |
65 |
| after-deadline spend, version 1 | yes | 1 | 1 | 840000 | fffffffe |
5aa090a053b77af5453dcda6ad94cb33e9cede8c1d7a3f26c05a7e5f8e6850fe |
9a98ef4067a82238374f30927313697d840d17f2caf535db183610b31e7c6546 |
64 |
| one block early | no | 2 | 1 | 839999 | fffffffe |
1def413550afecf734dd79ad39aebf896c021eb87cbdd36d2e8fa59421e6adf0 |
ce8e456157ec72a88d80774e65ad4e7e889cb3ac06db2394772f496f19b3c8a7 |
|
| a timestamp-type nLockTime | no | 2 | 1 | 500000001 | fffffffe |
7c64bb265b4bb12729b892c696aa9675e93f108a75d81943b748ff304e715274 |
2fa9716e70d6b33128c576ccc240ca59ca729c97dc311c3ff2162ab173c014bd |
|
| the top bit set | no | 2 | 1 | 2148323648 | fffffffe |
593f48d474349f243cbf64179a74d7fec42aba973c451c90c1e04c8901668509 |
d1e414385c917cdda0fcaed36db459ba34b5722eb6de52d48a3408dcd91e255f |
|
| finality bypass | no | 2 | 1 | 840000 | ffffffff |
35829316545520684965d89a95b044abd6ee43fee05ec501810925dec5f8f7a4 |
bb15b5ee9432518eff1f5caeb1903b66762ab6ae1a7ca4c62694802575aeba00 |
|
| another non-final sequence | no | 2 | 1 | 840000 | fffffffd |
705b60399f3ed87aafda731e319b666a3277805bf6d2192866cbb39649f3dbda |
760717a48a8c09fd80cdb27803d6cf957a62011643638d32d85b71d6c6b70e5e |
|
| a second input | no | 2 | 2 | 840000 | fffffffe |
89cd1d8993f8529a7e216270e1ee0462b5cfbac8ced077828473b11b40a58256 |
89338db85bf5a36391c69670209367561afabb2cde5805fee2eeca7eb987cc94 |
|
| a preimage of another transaction | no | 2 | 1 | 840000 | fffffffe |
fe191a3f572b2578ccfa5551455903a3b4865e96d67b429f57ea8e075828d65e |
d556f3103fc97365975ea9c22845033be7b238456dd25bd38ec6c9ccd30f5442 |
|
| the gate alone with its key, another key's signature | no | 2 | 1 | 840000 | fffffffe |
dcc12f9d790bcea52eefc83b590d7b09c01c962a58d22a6e83e35e4d925c22de |
d556f3103fc97365975ea9c22845033be7b238456dd25bd38ec6c9ccd30f5442 |
Two-key (3.1), chronicle form
| Case | Valid | Version | Inputs | nLockTime | Sequence | txid | digest | ZA |
|---|---|---|---|---|---|---|---|---|
| anytime branch, no deadline | yes | 2 | 1 | 0 | ffffffff |
9d2ba01073c2f64389c79aa37273601ea94ce34185ed1c4321d834821a2c22f5 |
a5524d393a72ac11e8a8a32d9fe32433cf8af9c96dcfa2df7b8c452c8dcd2edf |
|
| after-deadline spend at the deadline | yes | 2 | 1 | 840000 | fffffffe |
7fe240b3fcff7c44bd184874b8569c9dba1eea146e7d2dcc61dafdcc4284639d |
829d3a185b42924df3c8467d84513e7fdc81e8790d1a72ffc5c1795eab7982cb |
64 |
| after-deadline spend, a later height | yes | 2 | 1 | 845000 | fffffffe |
6aa9b43160ef8d11ec1f2d04e68f8da4459f716cfbead75c7269fb099db20a1a |
8c5bbab64d32c05055cf97905664cec44c929966d9b10e9a99274073abb819ec |
64 |
| after-deadline spend, version 1 | yes | 1 | 1 | 840000 | fffffffe |
466a8e60a90c5d4a6c9884af9fd533805e2be9a360f90ef5add900e1f62ddee0 |
64aa6589143960d7916d6c31788f5d80de3c8174a735f27e51c84c146a5bc4b1 |
64 |
| one block early | no | 2 | 1 | 839999 | fffffffe |
f2be56ed205ef5e15bcb019f1fd94d1bbd2bce8332d9dbb77ff38268df08ed55 |
c51f50c20f5acc7bab4bf291a82353e4abe3d0371abe3cdc9e6654b467379670 |
|
| a timestamp-type nLockTime | no | 2 | 1 | 500000001 | fffffffe |
2d907dbb68428be8c82755ded636b5335f258aca3f5e1b9fb83b0307cc2c630d |
14407fdb6996441e2bc65f30d8bdf23ab7a560b2921b15a4b2aeec6bfba81c1d |
|
| the top bit set | no | 2 | 1 | 2148323648 | fffffffe |
0e44fa807a22c2592213f616bde1dd31731ef978ed31b86d74ac7a52c06b6073 |
3643792031ae39797f3a1dfc046a9cb1514b11091198a988ca6f8248b9dada08 |
|
| finality bypass | no | 2 | 1 | 840000 | ffffffff |
013fd5c69f583c2dc4bccae274a8862a46b3df58587f41d969d358f8bc9be3e8 |
8f88ab7abf1855687c661437e6480ae5765f0973945102fd7e09dec85548ceb1 |
|
| another non-final sequence | no | 2 | 1 | 840000 | fffffffd |
c6036db5461f2e20406d32f29ff1efc686d81cec419cc06fa131789eb08326dd |
37e3bf0777c7361dadc51a57ce95420abbd08fee032c66034143e256ee903605 |
|
| a second input | no | 2 | 2 | 840000 | fffffffe |
bfbec399a1f0968849c19b200d9e08f4ec254dde61f65f3097f9e18992a8c5de |
559ad22fb3c7aa5b6cbbf470ab4fdae8502905f39bc863be37fffaa604233910 |
|
| a preimage of another transaction | no | 2 | 1 | 840000 | fffffffe |
f9a628e18c7e799bafcec2eb6719bc014d5f8c80aca73cc402c6fb2a16da644b |
829d3a185b42924df3c8467d84513e7fdc81e8790d1a72ffc5c1795eab7982cb |
|
| after-deadline branch, the anytime key's signature | no | 2 | 1 | 840000 | fffffffe |
411bc504846b6c02eaa17fadb1cf72696b24d26a67c94547ff9b95a4ff7f7193 |
829d3a185b42924df3c8467d84513e7fdc81e8790d1a72ffc5c1795eab7982cb |
Threshold, 2 of 3 (3.2), chronicle form
| Case | Valid | Version | Inputs | nLockTime | Sequence | txid | digest | ZA |
|---|---|---|---|---|---|---|---|---|
| 2-of-3 anytime branch | yes | 2 | 1 | 0 | ffffffff |
f19bc0a0e424feebee7312553a8bc58b0f4cf27b7b5c309a462f2f5548f925e9 |
529cfd3b69e56e5a0ddb11be0650533ad7369886e62dc264d5589efb52754039 |
|
| after-deadline spend at the deadline | yes | 2 | 1 | 840000 | fffffffe |
1bb7c1980e3efed0089597f83536439e0ce979fa92ca1b008e53b73e21d5e296 |
f79f3f916a1170114019d703dfe7c06f65356cee57d804a88dc171888c14030d |
65 |
| after-deadline spend, a later height | yes | 2 | 1 | 845000 | fffffffe |
1d4cb98f9bb1b55c0830e6e5f3d013ed56ca02ce52b077103425b98b0a8583a6 |
efdbb99bee1481809d8a397439195692c04398bb84458628c83078e060edf5f9 |
65 |
| after-deadline spend, version 1 | yes | 1 | 1 | 840000 | fffffffe |
c81e0d03c791e479f4dc0b1e5b5ddc8a5ed544fd06d900a75cf5bd9c66e8c9d0 |
8df92b9175fcd09845f385e9ee4ad3a5124efef3bd57e2536d679e319a1d671d |
64 |
| one block early | no | 2 | 1 | 839999 | fffffffe |
1553c0d1fc078ee47e27db506969d69cc2ad67c88beb53a5e9fb1fd26d059940 |
e57c9f8826b2a03455ce9e6d46b11ade48f54badcb42d0c45976b87a9541c35e |
|
| a timestamp-type nLockTime | no | 2 | 1 | 500000001 | fffffffe |
dcc5016f08c36c14f85f27d006ff86ac010cb894ce194421304bf8ae912cc50f |
e1e7254570ca16c4744b23ee939a5d5c27a6a88452258d75bd04dc6108525d90 |
|
| the top bit set | no | 2 | 1 | 2148323648 | fffffffe |
b1fa1545451bf60a6a0e6d2b16a0f14ad0474f8d3dbadb9e4ab8ed148f124a03 |
f3550e0ad32de9dc98a28d7c672cdfb0593b611571038745fa616c2338c5687c |
|
| finality bypass | no | 2 | 1 | 840000 | ffffffff |
123601d915a74d95a46fc9d06195cc34d72e1eb7fea40cdf6fbdd7f8ad39eb47 |
ea2f1ce07b4c07c4544e3747c147303aaaab07108904602ea4a293b9f02aebe9 |
|
| another non-final sequence | no | 2 | 1 | 840000 | fffffffd |
33eed5fba7d954b0ab5d3bb5b910ea6b870ad7cb61a2c6c69d0ab3afc691ab3a |
0aa122e3396e746e27851fd259f2e78cbbc9fc3e1b243ef5048b49877d8dd50c |
|
| a second input | no | 2 | 2 | 840000 | fffffffe |
02435ecf55564b664590ba65ff57f403103e5077fd7e0dfda1c91d5fe39f6a80 |
deaa41c9b3669511ed27c5bf4ce1b737fe1e02af0d02da13da8d68f0a9308fea |
|
| a preimage of another transaction | no | 2 | 1 | 840000 | fffffffe |
305d536b5925829442c89ae5b9463ade3fe9a60e6f30000c47660aff1606ce71 |
f79f3f916a1170114019d703dfe7c06f65356cee57d804a88dc171888c14030d |
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_CHECKLOCKTIMEVERIFYandOP_CHECKSEQUENCEVERIFYare treated asOP_NOP2andOP_NOP3for an input whose spent output was created after Genesis (utxo_after_genesis), andSCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPSis 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) andContextualCheckTransactionForCurrentBlock(the tip's height plus one);LOCKTIME_THRESHOLDinsrc/script/script.h. - [NONFINAL] SV-Node v1.2.3:
src/validation.cpp(non-final transactions 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), andOP_LEFT,OP_RIGHTand 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 withSIGHASH_FORKID, used unless the0x20bit 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