From defb3fcd9542d0dc8a187458837d0a8e3ccbbd1a Mon Sep 17 00:00:00 2001 From: Julian Moik Date: Fri, 31 Jul 2026 21:16:43 +0200 Subject: [PATCH 1/5] BIP-0440: document mixed-version resource limits --- bip-0440.mediawiki | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/bip-0440.mediawiki b/bip-0440.mediawiki index 7b5493ca07..a8a16eee1a 100644 --- a/bip-0440.mediawiki +++ b/bip-0440.mediawiki @@ -10,7 +10,7 @@ License: BSD-3-Clause Discussion: https://groups.google.com/g/bitcoindev/c/GisTcPb8Jco/m/8znWcWwKAQAJ https://delvingbitcoin.org/t/benchmarking-bitcoin-script-evaluation-for-the-varops-budget-great-script-restoration/2094 - Version: 0.2.1 + Version: 0.2.2 ==Introduction== @@ -51,7 +51,9 @@ The last two assumptions make a large difference in practice: normal usage on sm A per-transaction integer "varops budget" is determined by multiplying the total transaction weight by the fixed factor 10,000 (chosen to make operation costs all integer values). The budget is transaction-wide (rather than per-input) to allow for cross-input introspection: a small input may reasonably access larger inputs. -Opcodes consume budget as they are executed, based on the length (not generally the value) of their parameters as detailed below. A transaction which exceeds its budget fails to validate. +Opcodes evaluated under Tapscript v2 and later participating leaf versions consume budget as they are executed, based on the length (not generally the value) of their parameters as detailed below, and fail before performing an operation whose cost exceeds the remaining budget. + +Earlier script versions retain their existing resource limits and do not consume the varops budget. An adversarial mixed-version transaction can therefore combine both workloads, requiring up to twice the validation work of the more expensive regime alone. This is accepted to avoid making budget funding depend on input-version composition, or retrofitting varops accounting into existing script versions and transaction tooling. ===Derivation of Costs=== @@ -75,13 +77,13 @@ The costs were validated by constructing maximally expensive scripts for every o Apple M1 Pro, Apple M2, Apple M4 Pro (macOS + Linux/Docker), AMD Ryzen 5 3600, AMD Ryzen 7 5800U, AMD Ryzen 9 9950X, Intel i5-12500, Intel i7-7700, Intel i7-8700, Intel i9-9900K, Intel N150 (Umbrel), Raspberry Pi 5. -For each machine, the ratio of the GSR worst-case block time to the existing (pre-GSR) worst-case block time was computed. A ratio below 1.0 means GSR does not introduce a new worst case. On all 14 tested machines, the ratio is below 1.0. +For each machine, we compared the worst-case block time under Tapscript v2 alone with the worst-case block time under existing script versions. The resulting ratio was below 1.0 on all 14 tested machines. -Without GSR, the slowest blocks are dominated by: +Under existing script versions, the slowest blocks are dominated by: * Schnorr signature validation (80,000 signatures per block) * Repeated hashing of 520-byte elements (3DUP + HASH256, 3DUP + RIPEMD160) -With GSR enabled, the slowest blocks restricted by the varops budget depend on the machine but usually include: +Under Tapscript v2, the slowest blocks permitted by the varops budget depend on the machine but usually include: * Schnorr signature validation (80,000 signatures per block) * Repeated hashing of 520-byte elements (3DUP + HASH256, 3DUP + RIPEMD160) * Small-element multiplication (MUL on 1-byte operands) @@ -348,6 +350,7 @@ Work in progress: ==Changelog== +* 0.2.2: 2026-08-05: document mixed-version resource limits. * 0.2.1: 2026-06-15: define wordspan notation and clarify byte-length versus word-span costs. * 0.2.0: 2026-02-21: increase in cost for hashing and copying based on benchmark results. * 0.1.0: 2025-09-27: first public posting From 00a5bb87b37219501252b7c5e6dffdf1f920e8e8 Mon Sep 17 00:00:00 2001 From: Julian Moik Date: Fri, 31 Jul 2026 21:17:03 +0200 Subject: [PATCH 2/5] BIP-0441: add OP_BOOLAND to varops cost list --- bip-0441.mediawiki | 1 + 1 file changed, 1 insertion(+) diff --git a/bip-0441.mediawiki b/bip-0441.mediawiki index fd4de36f27..d92a95c5fc 100644 --- a/bip-0441.mediawiki +++ b/bip-0441.mediawiki @@ -617,6 +617,7 @@ The varops costs of the following opcodes are defined in * OP_PICK * OP_TUCK * OP_ROLL +* OP_BOOLAND * OP_BOOLOR * OP_NUMEQUAL * OP_NUMEQUALVERIFY From f3360275bf7536b2ba6324395b26f872c8b74699 Mon Sep 17 00:00:00 2001 From: Julian Moik Date: Wed, 12 Aug 2026 11:35:54 +0200 Subject: [PATCH 3/5] BIP-0440: clarify varops charging rules Document bounded linear postcharging and require superlinear operations and signature checks to be precharged. Charge SIGCHECK only for nonempty signature operands. --- bip-0440.mediawiki | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bip-0440.mediawiki b/bip-0440.mediawiki index a8a16eee1a..3f002484b3 100644 --- a/bip-0440.mediawiki +++ b/bip-0440.mediawiki @@ -10,7 +10,7 @@ License: BSD-3-Clause Discussion: https://groups.google.com/g/bitcoindev/c/GisTcPb8Jco/m/8znWcWwKAQAJ https://delvingbitcoin.org/t/benchmarking-bitcoin-script-evaluation-for-the-varops-budget-great-script-restoration/2094 - Version: 0.2.2 + Version: 0.2.3 ==Introduction== @@ -51,7 +51,7 @@ The last two assumptions make a large difference in practice: normal usage on sm A per-transaction integer "varops budget" is determined by multiplying the total transaction weight by the fixed factor 10,000 (chosen to make operation costs all integer values). The budget is transaction-wide (rather than per-input) to allow for cross-input introspection: a small input may reasonably access larger inputs. -Opcodes evaluated under Tapscript v2 and later participating leaf versions consume budget as they are executed, based on the length (not generally the value) of their parameters as detailed below, and fail before performing an operation whose cost exceeds the remaining budget. +Opcodes evaluated under Tapscript v2 and later participating leaf versions consume budget based on the lengths (not generally the values) of their parameters, as detailed below. Because a linear operation determines its exact cost as it executes, that cost may be deducted afterward instead of being calculated in a separate pass; exceeding the remaining budget invalidates the script before the next opcode. Superlinear operations and signature checks must instead be charged before execution because they could otherwise perform disproportionately expensive work before an overrun is detected. Earlier script versions retain their existing resource limits and do not consume the varops budget. An adversarial mixed-version transaction can therefore combine both workloads, requiring up to twice the validation work of the more expensive regime alone. This is accepted to avoid making budget funding depend on input-version composition, or retrofitting varops accounting into existing script versions and transaction tooling. @@ -108,7 +108,7 @@ We divided operations into six speed categories: Each class then has the following costs. -# Signature operations cost 500,000 (10,000 * 50) units each, this resembles the cost of the existing sigops budget. +# Signature operations with a nonempty signature operand cost 500,000 (10,000 * 50) units each; signature operations with an empty signature operand have no SIGCHECK cost. This resembles the existing sigops budget and applies to unknown nonzero-length public-key types as well. # Hashing costs 50 units per byte hashed. # OP_ROLL costs an additional 48 units (24 bytes per std::vector * 2 units per byte) per stack entry moved (i.e. the value of its operand). # Fast operations cost 2 units per byte output. @@ -133,7 +133,7 @@ We use the following annotations to indicate the derivation for each opcode: ;ARITH : Arithmetic operations which have carry operations: cost = 6 per byte examined. ;SIGCHECK -: Checking a signature is a flat cost: cost = 500,000. +: A signature operation with a nonempty signature operand has a flat cost of 500,000; an empty signature operand has a cost of 0. ;HASH : cost = 50 per byte hashed. ;ROLL @@ -350,6 +350,7 @@ Work in progress: ==Changelog== +* 0.2.3: 2026-08-11: clarify conditional SIGCHECK charging and charging order for linear and superlinear operations. * 0.2.2: 2026-08-05: document mixed-version resource limits. * 0.2.1: 2026-06-15: define wordspan notation and clarify byte-length versus word-span costs. * 0.2.0: 2026-02-21: increase in cost for hashing and copying based on benchmark results. From d536a811c574e50dcaf8ed1611ba9b21530dbf40 Mon Sep 17 00:00:00 2001 From: Julian Moik Date: Wed, 12 Aug 2026 11:36:15 +0200 Subject: [PATCH 4/5] BIP-0441: clarify conditional sigcheck costs Define sigcheck_cost from signature emptiness and apply it to CHECKSIG, CHECKSIGVERIFY, and CHECKSIGADD. --- bip-0441.mediawiki | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/bip-0441.mediawiki b/bip-0441.mediawiki index d92a95c5fc..610ed87b17 100644 --- a/bip-0441.mediawiki +++ b/bip-0441.mediawiki @@ -9,7 +9,7 @@ Assigned: 2026-03-25 License: BSD-3-Clause Discussion: https://groups.google.com/g/bitcoindev/c/GisTcPb8Jco/m/8znWcWwKAQAJ - Version: 0.2.2 + Version: 0.2.3 Requires: 440 @@ -567,6 +567,8 @@ failure, as mathematicians agree the result would not be natural. The following opcodes have costs below: +In this table, sigcheck_cost(signature) is 500,000 if the signature operand is nonempty, and 0 otherwise. This rule also applies to unknown nonzero-length public-key types. + {| ! Opcode ! Varops Budget Cost @@ -581,22 +583,21 @@ The following opcodes have costs below: | LENGTHCONV |- | OP_CHECKSIGADD -| MAX(wordspan(1), wordspan(number operand)) * 9 + 500,000 +| MAX(wordspan(1), wordspan(number operand)) * 9 + sigcheck_cost(signature) | ARITH + COPYING + SIGCHECK |- | OP_CHECKSIG -| 500,000 +| sigcheck_cost(signature) | SIGCHECK |- | OP_CHECKSIGVERIFY -| 500,000 +| sigcheck_cost(signature) | SIGCHECK |} ====Rationale==== -OP_CHECKSIGADD does an OP_1ADD on success, so we use the same cost as that. -For simplicity, this is charged whether the OP_CHECKSIGADD succeeds or not. +The arithmetic and copying component of OP_CHECKSIGADD uses the OP_1ADD cost and is charged whether or not the signature is empty or valid. Its SIGCHECK component is charged only for a nonempty signature. ===Other Operators=== @@ -649,6 +650,7 @@ Work in progress: ==Changelog== +* 0.2.3: 2026-08-11: clarify that SIGCHECK cost applies only to nonempty signature operands. * 0.2.2: 2026-06-15: clarify wordspan costs, OP_RIGHT semantics, OP_UPSHIFT unaligned cost, CLTV/CSV bounds, and final success-check cost. * 0.2.1: 2023-03-27: fix OP_MUL cost to round length(B) up * 0.2.0: 2025-02-21: change costs to match those in varops budget From ec838b72734bf64c47c6aec0194da0dff20b6cdb Mon Sep 17 00:00:00 2001 From: Julian Moik Date: Wed, 12 Aug 2026 16:58:45 +0200 Subject: [PATCH 5/5] BIP-0441: update reference implementation branch --- bip-0441.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip-0441.mediawiki b/bip-0441.mediawiki index 610ed87b17..8c83f088c8 100644 --- a/bip-0441.mediawiki +++ b/bip-0441.mediawiki @@ -646,7 +646,7 @@ version, for backwards compatibility. Work in progress: - https://github.com/jmoik/bitcoin/tree/gsr + https://github.com/jmoik/bitcoin/tree/gsr-core ==Changelog==