BRC-215 Scripts

Block-Height Deadline Covenant Templates (OP_PUSH_TX)

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 f

RexStarBSV (RexStarBSV@protonmail.com)

How it connects

Relationships

Authoritative content mirror

Full upstream text

View source ↗
Rendered from scripts/0215.md at the indexed upstream commit

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:

  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 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 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 script number: 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:

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):

  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 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, 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

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_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 (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), 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