Skip to content

Commit 7d29c19

Browse files
committed
fixup!
Great feedback from Murch: 1. Lots of markdown instead of mediawiki formatting fixed. 2. Input count max fixed (explanatory only, but still a good fix). 3. Justification for detailed by-byte nature of descriptions added to global Rationale. 4. Note on truncation moved earlier, and expanded. 5. OP_OR/OP_XOR clarified to make it clear that A is altered "in-place". 6. Clarification on early termination (and thus cost) of OR and XOR. 7. nee is spelled "née" (Julian suggested replacing it, but let's try to keep some culture alive!). 8. Murch is now thanked in the thanks section. In particular, Murch's confusion was enlightening. I had not appreciated that the reduction in script capability (removing all bitops and limiting operand size) made endian of stack objects very much an *implementation detail*, thus these descriptions are battling with people's head-canon of how Bitcoin's Stack Is Just Numbers. Mere words can only do so much to address this issue, but I've tried, and at least I'm now aware of this. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
1 parent c40bbe2 commit 7d29c19

1 file changed

Lines changed: 73 additions & 68 deletions

File tree

bip-unknown-script-restoration.mediawiki

Lines changed: 73 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
This BIP introduces a new tapleaf version (0xc2) which restores Bitcoin script to its pre-0.3.1 capability, relying on the Varops Budget in [[bip-unknown-varops-budget.mediawiki|BIP-varops]] to prevent the excessive computational time which caused CVE-2010-5137.
2020

2121
In particular, this BIP:
22-
- Reenables disabled opcodes.
23-
- Increases the maximum stack object size from 520 bytes to 4,000,000 bytes.
24-
- Introduces a total stack byte limit of 8,000,000 bytes.
25-
- Increases the maximum total number of stack objects from 1000 to 32768.
26-
- Removes the 32-bit size restriction on numerical values.
27-
- Treats all numerical values as unsigned.
22+
* Reenables disabled opcodes.
23+
* Increases the maximum stack object size from 520 bytes to 4,000,000 bytes.
24+
* Introduces a total stack byte limit of 8,000,000 bytes.
25+
* Increases the maximum total number of stack objects from 1,000 to 32,768.
26+
* Removes the 32-bit size restriction on numerical values.
27+
* Treats all numerical values as unsigned.
28+
29+
All opcodes are described in exact (painstaking) byte-by-byte operations, so that their varops budget can be easily derived. Note that this level of detail is unnecessary to users of script, only being of interest to implementers.
2830

2931
===Copyright===
3032

@@ -41,18 +43,18 @@ Unfortunately, these restrictions removed much of the ability for users to contr
4143
If a taproot leaf has a version of 0xc2, execution of opcodes is as defined below. All opcodes not explicitly defined here are treated exactly as defined by [[bip-0342.mediawiki|BIP342]].
4244

4345
Validation of a script fails if:
44-
- It exceeds the remaining varops budget for the transaction.
45-
- Any stack element exceeds 4,000,000 bytes.
46-
- The total size of all stack (and altstack) elements exceeds 8,000,000 bytes.
47-
- The number of stack elements (including altstack elements) exceeds 32768.
46+
* It exceeds the remaining varops budget for the transaction.
47+
* Any stack element exceeds 4,000,000 bytes.
48+
* The total size of all stack (and altstack) elements exceeds 8,000,000 bytes.
49+
* The number of stack elements (including altstack elements) exceeds 32,768.
4850
4951
===Rationale===
5052

5153
There needs to be some limit on memory usage, to avoid a memory-based denial of service.
5254

5355
Putting the entire transaction on the stack is a foreseeable use case, hence using the block size (4MB) as a limit makes sense. However, allowing 4MB stack elements is a significant increase in memory requirements, so a total limit of twice that many bytes (8MB) is introduced. Many stack operations require making at least one copy, so this allows such use.
5456

55-
Putting all outputs or inputs from the transaction on the stack as separate elements requires as much stack capacity as there are inputs or outputs. The smallest possible input is 34 bytes (allowing almost 26,411 inputs), and the smallest possible output is 9 bytes (allowing almost 111,111 outputs). However, empty outputs are rare and not economically interesting. Thus we consider smallest non-OP_RETURN standard output script, which is P2WPKH at 22 bytes, giving a minimum output size of 31 bytes, allowing 32,258 outputs in a maximally-sized transaction.
57+
Putting all outputs or inputs from the transaction on the stack as separate elements requires as much stack capacity as there are inputs or outputs. The smallest possible input is 41 bytes (allowing almost 24,390 inputs), and the smallest possible output is 9 bytes (allowing almost 111,111 outputs). However, empty outputs are rare and not economically interesting. Thus we consider smallest non-OP_RETURN standard output script, which is P2WPKH at 22 bytes, giving a minimum output size of 31 bytes, allowing 32,258 outputs in a maximally-sized transaction.
5658

5759
This makes 32,768 a reasonable upper limit for stack elements.
5860

@@ -68,23 +70,43 @@ The following opcodes are renamed OP_SUCCESSx, and cause validation to immediate
6870

6971
Negative numbers are not natively supported in v2 Tapscript. Arbitrary precision makes them difficult to manipulate and negative values are not used meaningfully in bitcoin transactions.
7072

73+
===Arbitrary-length Values, Endianness, and Normalization of Results===
74+
75+
The restoration of bit operations means that the little-endianness of stack values is once more exposed to the Script author, if they mix them with arithmetic operations. The restoration of arbitrary-length values additionally exposes the endianness to the implementation authors (who cannot simply load stack entries into registers), and requires explicit consideration when considering varops costs of operations.<ref>For example, removing trailing bytes from a stack element is almost free, whereas removing bytes from the front involves copying all remaining bytes.</ref>
76+
77+
Note that only arithmetic operations (those which treat operands as numbers) normalize their results: bit operations do not. Thus operations such as "0 OP_ADD" and "2 OP_MUL" will never result in a top stack entry with a trailing zero byte, but "0 OP_OR" and "1 OP_UPSHIFT" may.<ref>The original Bitcoin implementation had a similar operational split, but OP_LSHIFT and OP_RSHIFT did normalize, which was almost a requirement given that they also preserved the sign of the shifted operand</ref>
78+
79+
To be explicit, the following operations are defined as arithmetic and will normalize their results:
80+
81+
* OP_1ADD
82+
* OP_1SUB
83+
* OP_2MUL
84+
* OP_2DIV
85+
* OP_ADD
86+
* OP_SUB
87+
* OP_MUL
88+
* OP_DIV
89+
* OP_MOD
90+
* OP_MIN
91+
* OP_MAX
92+
7193
===Non-Arithmetic Opcodes Dealing With Stack Numbers===
7294

7395
The following opcodes are redefined in v2 Tapscript to read numbers from the stack as arbitrary-length little-endian values (instead of CScriptNum):
7496

75-
1. OP_CHECKLOCKTIMEVERIFY
76-
2. OP_CHECKSEQUENCEVERIFY
77-
3. OP_VERIFY
78-
4. OP_PICK
79-
5. OP_ROLL
80-
6. OP_IFDUP
81-
7. OP_CHECKSIGADD
97+
# OP_CHECKLOCKTIMEVERIFY
98+
# OP_CHECKSEQUENCEVERIFY
99+
# OP_VERIFY
100+
# OP_PICK
101+
# OP_ROLL
102+
# OP_IFDUP
103+
# OP_CHECKSIGADD
82104
83105
These opcodes are redefined in v2 Tapscript to write numbers to the stack as minimal-length little-endian values (instead of CScriptNum):
84106

85-
1. OP_CHECKSIGADD
86-
2. OP_DEPTH
87-
3. OP_SIZE
107+
# OP_CHECKSIGADD
108+
# OP_DEPTH
109+
# OP_SIZE
88110
89111
In addition, the [[bip-0342.mediawiki#specification|BIP-342 success requirement]] is modified to require a non-zero variable-length unsigned integer value (not <code>CastToBool()</code>):
90112

@@ -210,7 +232,7 @@ OP_LEFT only needs to read its OFFSET operand (truncation is free), whereas OP_R
210232
# Pop B off the stack.
211233
# Pop A off the stack.
212234
# If B is longer than A, swap B and A.
213-
# For each byte in B (the shorter operand): bitwise OR it with the equivalent byte in A.
235+
# For each byte in B (the shorter operand): bitwise OR it into the equivalent byte in A (altering A).
214236
# Push A onto the stack.
215237
|-
216238
|OP_XOR
@@ -222,17 +244,17 @@ OP_LEFT only needs to read its OFFSET operand (truncation is free), whereas OP_R
222244
# Pop B off the stack.
223245
# Pop A off the stack.
224246
# If B is longer than A, swap B and A.
225-
# For each byte in B (the shorter operand): exclusive OR it with the equivalent byte in A.
247+
# For each byte in B (the shorter operand): exclusive OR it into the equivalent byte in A (altering A).
226248
# Push A onto the stack.
227249
|}
228250

229251
=====Rationale=====
230252

231-
OP_AND, OP_OR and OP_XOR are assumed to fold the results into the longer of the two operands. This is an OTHER operation (i.e. cost is 2 per byte), but OP_AND needs to do this until one operand is exhausted, and then zero the rest (ZEROING, cost 1 per byte). OP_OR and OP_XOR can stop as soon as the shorter operand is exhausted.
253+
OP_AND, OP_OR and OP_XOR are assumed to fold the results into the longer of the two operands. This is an OTHER operation (i.e. cost is 2 per byte), but OP_AND needs to do this until one operand is exhausted, and then zero the rest (ZEROING, cost 1 per byte). OP_OR and OP_XOR can stop processing the operands as soon as the shorter operand is exhausted.
232254

233255
====Bitshift Opcodes====
234256

235-
Note that these are raw bitshifts, unlike the sign-preserving arithmetic shifts in Bitcoin v0.3.0, and as such they also do not truncate trailing zeroes from results: they are renamed OP_UPSHIFT (nee OP_LSHIFT) and OP_DOWNSHIFT (nee OP_RSHIFT).
257+
Note that these are raw bitshifts, unlike the sign-preserving arithmetic shifts in Bitcoin v0.3.0, and as such they also do not truncate trailing zeroes from results: they are renamed OP_UPSHIFT (née OP_LSHIFT) and OP_DOWNSHIFT (née OP_RSHIFT).
236258

237259
{|
238260
! Opcode
@@ -264,7 +286,7 @@ Note that these are raw bitshifts, unlike the sign-preserving arithmetic shifts
264286
# Pop BITS off the stack.
265287
# Pop A off the stack.
266288
# For BITOFF from 0 to (length(A)-1) * 8 - value(BITS):
267-
# Copy each bit in A from BITOFF + value(BITS) to BITOFF.
289+
## Copy each bit in A from BITOFF + value(BITS) to BITOFF.
268290
# Truncate A to remove value(BITS) / 8 bytes from the end (or all bytes, if value(BITS) / 8 > length(A)).
269291
# Push A onto the stack.
270292
|}
@@ -496,24 +518,6 @@ The varops costs of the following opcodes are defined in [[bip-unknown-varops-bu
496518
497519
Those with costs not defined here have a cost of 0 (they do not operate on variable-length stack objects).
498520

499-
===Normalization of Results===
500-
501-
Note that only arithmetic operations (those which treat operands as numbers) normalize their results: bit operations do not. Thus operations such as "0 OP_ADD" and "2 OP_MUL" will never result in a top stack entry with a trailing zero byte, but "0 OP_OR" and "1 OP_UPSHIFT" may.
502-
503-
To be clear, the following operations are arithmetic and will normalize their results:
504-
505-
* OP_1ADD
506-
* OP_1SUB
507-
* OP_2MUL
508-
* OP_2DIV
509-
* OP_ADD
510-
* OP_SUB
511-
* OP_MUL
512-
* OP_DIV
513-
* OP_MOD
514-
* OP_MIN
515-
* OP_MAX
516-
517521
==Backwards compatibility==
518522

519523
This BIP defines a previously unused (and thus, always-successful) tapscript version, for backwards compatibility.
@@ -529,13 +533,14 @@ Work in progress:
529533
This BIP would not exist without the thoughtful contributions of coders who considered all the facets carefully and thoroughly, and also my inspirational wife Alex and my kids who have been tirelessly supportive of my esoteric-seeming endeavors such as this!
530534

531535
In alphabetical order:
532-
- Anthony Towns
533-
- Brandon Black (aka Reardencode)
534-
- John Light
535-
- Jonas Nick
536-
- Rijndael (aka rot13maxi)
537-
- Steven Roose
538-
- FIXME: your name here!
536+
* Anthony Towns
537+
* Brandon Black (aka Reardencode)
538+
* John Light
539+
* Jonas Nick
540+
* Mark "Murch" Erhardt
541+
* Rijndael (aka rot13maxi)
542+
* Steven Roose
543+
* FIXME: your name here!
539544
540545
==Appendix A: Cost Model Calculations for Multiply and Divide==
541546

@@ -544,10 +549,10 @@ Multiplication and division require multiple passes over the operands, meaning a
544549
===Multiplication Cost===
545550

546551
For multiplication, the steps break down like so:
547-
1. Allocate and zero the result: cost = (length(A) + length(B)) * 2 (ZEROING)
548-
2. For each word in A:
549-
* Multiply by each word in B, into a scratch vector: cost = 6 * length(B) (ARITH)
550-
* Sum scratch vector at the word offset into the result: cost = 6 * length(B) (ARITH)
552+
# Allocate and zero the result: cost = (length(A) + length(B)) * 2 (ZEROING)
553+
# For each word in A:
554+
#* Multiply by each word in B, into a scratch vector: cost = 6 * length(B) (ARITH)
555+
#* Sum scratch vector at the word offset into the result: cost = 6 * length(B) (ARITH)
551556
552557
Note: we do not assume Karatsuba, Toom-Cook or other optimizations.
553558

@@ -557,29 +562,29 @@ However, benchmarking reveals that the inner loop overhead (branch misprediction
557562

558563
This is slightly asymmetric: in practice an implementation usually finds that CPU pipelining means choosing B as the larger operand is optimal.
559564

560-
===Division Cost====
565+
===Division Cost===
561566

562567
For division, the steps break down like so:
563568

564-
1. Bit shift both operands to set top bit of B (OP_UPSHIFT, without overflow for B): cost = length(A) * 6 + length(B) * 4
569+
# Bit shift both operands to set top bit of B (OP_UPSHIFT, without overflow for B): cost = length(A) * 6 + length(B) * 4
565570
566-
2. Trim trailing bytes. This costs according to the number of byte removed, but since that is subtractive on future costs, we ignore it.
571+
# Trim trailing bytes. This costs according to the number of byte removed, but since that is subtractive on future costs, we ignore it.
567572
568-
3. If B is longer, the answer is 0 already. So assume A is longer from now on (or equal length).
573+
# If B is longer, the answer is 0 already. So assume A is longer from now on (or equal length).
569574
570-
4. Compare: cost = length(A) * 2 (COMPARING)
575+
# Compare: cost = length(A) * 2 (COMPARING)
571576
572-
5. Subtract: cost = length(A) * 6 (ARITH)
577+
# Subtract: cost = length(A) * 6 (ARITH)
573578
574-
6. for (length(A) - NormalizedLength(B)) in words:
575-
1. Multiply word by B -> scratch: cost = NormalizedLength(B) * 6 (ARITH)
576-
2. Subtract scratch from A: cost = length(A) * 6 (ARITH)
577-
3. Add B into A (no overflow): cost = length(A) * 6 (ARITH)
578-
4. Shrink A by 1 word.
579+
# for (length(A) - NormalizedLength(B)) in words:
580+
## Multiply word by B -> scratch: cost = NormalizedLength(B) * 6 (ARITH)
581+
## Subtract scratch from A: cost = length(A) * 6 (ARITH)
582+
## Add B into A (no overflow): cost = length(A) * 6 (ARITH)
583+
## Shrink A by 1 word.
579584
580-
7. OP_MOD: shift A down, trim trailing zeroes: cost = length(A) * 4
585+
# OP_MOD: shift A down, trim trailing zeroes: cost = length(A) * 4
581586
582-
8. OP_DIV: trim trailing zeros: cost = length(A) * 4
587+
# OP_DIV: trim trailing zeros: cost = length(A) * 4
583588
584589
Note that the loop at step 6 shrinks A every time, so the *average* cost of each iteration is (NormalizedLength(B) * 6 + length(A) * 12) / 2. The cost of step 6 is:
585590

0 commit comments

Comments
 (0)