You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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>
Copy file name to clipboardExpand all lines: bip-unknown-script-restoration.mediawiki
+73-68Lines changed: 73 additions & 68 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -19,12 +19,14 @@
19
19
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.
20
20
21
21
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.
28
30
29
31
===Copyright===
30
32
@@ -41,18 +43,18 @@ Unfortunately, these restrictions removed much of the ability for users to contr
41
43
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]].
42
44
43
45
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.
48
50
49
51
===Rationale===
50
52
51
53
There needs to be some limit on memory usage, to avoid a memory-based denial of service.
52
54
53
55
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.
54
56
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.
56
58
57
59
This makes 32,768 a reasonable upper limit for stack elements.
58
60
@@ -68,23 +70,43 @@ The following opcodes are renamed OP_SUCCESSx, and cause validation to immediate
68
70
69
71
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.
70
72
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
+
71
93
===Non-Arithmetic Opcodes Dealing With Stack Numbers===
72
94
73
95
The following opcodes are redefined in v2 Tapscript to read numbers from the stack as arbitrary-length little-endian values (instead of CScriptNum):
74
96
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
82
104
83
105
These opcodes are redefined in v2 Tapscript to write numbers to the stack as minimal-length little-endian values (instead of CScriptNum):
84
106
85
-
1. OP_CHECKSIGADD
86
-
2. OP_DEPTH
87
-
3. OP_SIZE
107
+
# OP_CHECKSIGADD
108
+
# OP_DEPTH
109
+
# OP_SIZE
88
110
89
111
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>):
90
112
@@ -210,7 +232,7 @@ OP_LEFT only needs to read its OFFSET operand (truncation is free), whereas OP_R
210
232
# Pop B off the stack.
211
233
# Pop A off the stack.
212
234
# 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).
214
236
# Push A onto the stack.
215
237
|-
216
238
|OP_XOR
@@ -222,17 +244,17 @@ OP_LEFT only needs to read its OFFSET operand (truncation is free), whereas OP_R
222
244
# Pop B off the stack.
223
245
# Pop A off the stack.
224
246
# 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).
226
248
# Push A onto the stack.
227
249
|}
228
250
229
251
=====Rationale=====
230
252
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.
232
254
233
255
====Bitshift Opcodes====
234
256
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).
236
258
237
259
{|
238
260
! Opcode
@@ -264,7 +286,7 @@ Note that these are raw bitshifts, unlike the sign-preserving arithmetic shifts
264
286
# Pop BITS off the stack.
265
287
# Pop A off the stack.
266
288
# 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.
268
290
# Truncate A to remove value(BITS) / 8 bytes from the end (or all bytes, if value(BITS) / 8 > length(A)).
269
291
# Push A onto the stack.
270
292
|}
@@ -496,24 +518,6 @@ The varops costs of the following opcodes are defined in [[bip-unknown-varops-bu
496
518
497
519
Those with costs not defined here have a cost of 0 (they do not operate on variable-length stack objects).
498
520
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
-
517
521
==Backwards compatibility==
518
522
519
523
This BIP defines a previously unused (and thus, always-successful) tapscript version, for backwards compatibility.
@@ -529,13 +533,14 @@ Work in progress:
529
533
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!
530
534
531
535
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!
539
544
540
545
==Appendix A: Cost Model Calculations for Multiply and Divide==
541
546
@@ -544,10 +549,10 @@ Multiplication and division require multiple passes over the operands, meaning a
544
549
===Multiplication Cost===
545
550
546
551
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)
551
556
552
557
Note: we do not assume Karatsuba, Toom-Cook or other optimizations.
553
558
@@ -557,29 +562,29 @@ However, benchmarking reveals that the inner loop overhead (branch misprediction
557
562
558
563
This is slightly asymmetric: in practice an implementation usually finds that CPU pipelining means choosing B as the larger operand is optimal.
559
564
560
-
===Division Cost====
565
+
===Division Cost===
561
566
562
567
For division, the steps break down like so:
563
568
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
565
570
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.
567
572
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).
569
574
570
-
4. Compare: cost = length(A) * 2 (COMPARING)
575
+
# Compare: cost = length(A) * 2 (COMPARING)
571
576
572
-
5. Subtract: cost = length(A) * 6 (ARITH)
577
+
# Subtract: cost = length(A) * 6 (ARITH)
573
578
574
-
6. for (length(A) - NormalizedLength(B)) in words:
575
-
1. Multiply word by B -> scratch: cost = NormalizedLength(B) * 6 (ARITH)
## Add B into A (no overflow): cost = length(A) * 6 (ARITH)
583
+
## Shrink A by 1 word.
579
584
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
581
586
582
-
8. OP_DIV: trim trailing zeros: cost = length(A) * 4
587
+
# OP_DIV: trim trailing zeros: cost = length(A) * 4
583
588
584
589
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:
0 commit comments