Varops: Rusty Russell's Variable-Cost Script Operations Proposal
Bitcoin’s scripting language was neutered in 2010 to prevent denial-of-service attacks. Now, Core Lightning developer Rusty Russell has submitted BIP PR #2118 proposing to restore what was lost through a smarter approach: variable-cost operation budgeting, or “varops.”
The proposal introduces two complementary BIPs. One establishes a framework for measuring script costs dynamically. The other uses that framework to restore 15 opcodes disabled since Bitcoin v0.3.1 while removing arbitrary limits that have constrained Script development for over a decade.
Why Script got locked down
Bitcoin’s scripting language was originally designed to be comprehensive. As Satoshi Nakamoto explained in June 2010:
“The nature of Bitcoin is such that once version 0.1 was released, the core design was set in stone for the rest of its lifetime. Because of that, I wanted to design it to support every possible transaction type I could think of.”
One month later, Bitcoin v0.3.1 disabled 15 opcodes to address CVE-2010-5137 and related vulnerabilities. The problem wasn’t that the functionality was dangerous; unbounded computational costs could crash nodes through memory exhaustion or excessive CPU usage.
The disabled opcodes included:
- Splice operations: OP_CAT, OP_SUBSTR, OP_LEFT, OP_RIGHT
- Bitwise operations: OP_INVERT, OP_AND, OP_OR, OP_XOR, OP_LSHIFT, OP_RSHIFT
- Arithmetic operations: OP_2MUL, OP_2DIV, OP_MUL, OP_DIV, OP_MOD
Along with disabling opcodes, the fix imposed strict limitations:
- Stack element size: 520 bytes maximum
- Total stack elements: 1,000 maximum (for Tapscript)
- Number size: 32-bit signed integers only
These were defensive measures, not architectural decisions. They worked, but they were blunt instruments.
How varops works
Instead of hard limits, Russell proposes a “varops budget”—a generalization of BIP-342’s signature operations budget that applies to all variable-length stack operations.
The budget calculation
Each transaction receives a varops budget proportional to its size:
Varops Budget = Transaction Weight × 10,000
For a maximum 4MB (4,000,000 weight units) block, this yields 40 billion varops units. The budget is transaction-wide rather than per-input to support cross-input introspection opcodes that might need to examine other inputs in the same transaction.
Cost tiers
Operations are classified into six cost categories based on empirical benchmarking:
- Signature operations: 500,000 units each (maintains parity with existing sigops budget)
- Hashing operations: 50 units per byte hashed
- OP_ROLL: 48 units per stack entry moved
- Fast operations (comparing, zeroing): 2 units per byte
- Copying operations: 3 units per byte
- Other operations: 4 units per byte
The BIP documents how each cost is derived. For example, OP_ROLL’s cost assumes 24 bytes per stack element (pointer + size + capacity in C++ std::vector), yielding 48 units per element moved (24 bytes × 2 units/byte for copying overhead).
Worst-case validation
To verify that varops actually constrains computational cost, Russell and co-author Julian Moik benchmarked maximally expensive scripts across 14 machines spanning multiple architectures:
- Platforms: Apple M1/M2/M4, AMD Ryzen (3600, 5800U, 9950X), Intel (i5-12500, i7-7700, i7-8700, i9-9900K, N150), Raspberry Pi 5
- Operating systems: macOS, Linux (x86_64 and ARM64), Windows
For each machine, they constructed scripts that fill an entire 4MB block while staying within the varops budget, then measured validation time against the baseline of 80,000 Schnorr signature checks (the existing worst case).
On all 14 tested machines, the worst-case varops-enabled block validates faster than the worst-case signature-only block. The full benchmark data, analysis scripts, and methodology are publicly available.
What gets restored
The companion BIP proposes Tapscript v2 (leaf version 0xc2), which would:
Re-enable disabled opcodes
Splice operations:
- OP_CAT: Concatenate two stack elements
- OP_SUBSTR: Extract substring by offset and length
- OP_LEFT/OP_RIGHT: Take bytes from left/right of element
Bitwise operations:
- OP_INVERT, OP_AND, OP_OR, OP_XOR: Bitwise logic
- OP_UPSHIFT/OP_DOWNSHIFT: Raw bitshifts (renamed from LSHIFT/RSHIFT, now unsigned)
Arithmetic operations:
- OP_2MUL/OP_2DIV: Shift by one bit (multiply/divide by 2)
- OP_MUL: Arbitrary-precision multiplication
- OP_DIV/OP_MOD: Division and modulo
Remove arbitrary limits
- Stack element size: Increased from 520 bytes to 4,000,000 bytes (block size)
- Total stack size: 8,000,000 bytes maximum (allows copying 4MB elements)
- Stack element count: Increased from 1,000 to 32,768 elements
- Number representation: Arbitrary-precision unsigned little-endian integers (no 32-bit limit)
Design changes
Unsigned-only arithmetic: Negative numbers are not supported in v2 Tapscript. OP_NEGATE, OP_1NEGATE, and OP_ABS become OP_SUCCESS opcodes. This simplifies implementation and interaction between bitwise and arithmetic operations.
Minimal-length encoding: Numbers must be stored with no trailing zero bytes. Comparison and verification operations enforce this.
Limited legacy hashing: OP_RIPEMD160 and OP_SHA1 remain restricted to 520-byte operands. They’re less optimized than SHA256 and have limited use cases.
Implementation details
The BIP specifies sophisticated algorithms for the restored math opcodes:
OP_MUL uses word-by-word multiplication with proper carry propagation. Cost: (length(A) + length(B)) * 3 + (length(A) + 7) / 8 * length(B) * 27
OP_DIV and OP_MOD implement Knuth’s Algorithm D from The Art of Computer Programming Volume 2. Both cost: length(A) * 18 + length(B) * 4 + length(A)^2 * 2 / 3
These operations check their varops cost before execution and fail immediately if the budget would be exceeded, preventing resource exhaustion attacks.
What this enables
While the BIP proposals focus on primitives rather than applications, the restored opcodes would enable:
Covenants and smart contracts
OP_CAT combined with CHECKSIG operations allows transaction introspection by concatenating transaction components and comparing their hash to the actual sighash. This enables:
- Vaults: Time-delayed withdrawal with cancellation paths
- Allowlists: Constraining where funds can be sent
- Recursive covenants: Outputs that enforce conditions on their future spends
Layer 2 improvements
- Multi-party channels: More than two participants in a Lightning channel
- Exit mechanisms: Unilateral exits from shared UTXOs without jeopardizing other users’ funds
- State tracking: Merkle trees tracking balances in shared UTXOs
Advanced cryptography
- Post-quantum signatures: OP_CAT enables Lamport signatures
- Tree signatures: More efficient multisig alternatives
- BitVM optimizations: Enhanced computation verification
The Great Script Restoration context
Russell’s BIPs are part of a broader initiative called the Great Script Restoration (GSR), which aims to shift the Bitcoin development conversation from narrow, use-case-specific proposals (APO, CTV, VAULT) to a comprehensive restoration of Script’s original vision.
As Bitcoin Magazine’s Shinobi explained in May 2024:
“Rather than attempting to comprehensively address the expressivity and programmability needed to scale Bitcoin in a fundamental way, each of the proposals over the last few years was designed to either give a small increase in scalability or improve a single narrow functionality deemed desirable.”
GSR’s philosophy: Rather than bikeshedding over which minimal opcode to add next, restore the full toolkit and let developers explore what’s actually useful.
Where it stands
Current status (as of March 2026):
- BIP PR #2118 submitted to bitcoin/bips repository
- Draft status, version 0.2.0 (varops budget), version 0.1.0 (script restoration)
- Reference implementation in progress
Co-authors: Rusty Russell and Julian Moik
Soft fork mechanism: New Tapscript leaf version (0xc2), backward compatible with existing Taproot
License: 3-clause BSD
Sources
BIP PR #2118, Bitcoin-dev mailing list discussion, Delving Bitcoin benchmarking thread, Rusty Russell’s blog post, Bitcoin Magazine - The Great Script Restoration, varopsData benchmark repository. Data/status as of March 15, 2026.