summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.mediawiki20
-rw-r--r--bip-0008.mediawiki68
-rw-r--r--bip-0008/states.dot34
-rw-r--r--bip-0008/states.pngbin25677 -> 46310 bytes
-rw-r--r--bip-0008/states.svg173
-rw-r--r--bip-0009.mediawiki2
-rw-r--r--bip-0039.mediawiki14
-rw-r--r--bip-0039/bip-0039-wordlists.md4
-rw-r--r--bip-0049.mediawiki2
-rw-r--r--bip-0114.mediawiki2
-rw-r--r--bip-0119.mediawiki2
-rw-r--r--bip-0124.mediawiki2
-rw-r--r--bip-0135.mediawiki2
-rw-r--r--bip-0155.mediawiki23
-rw-r--r--bip-0174.mediawiki34
-rw-r--r--bip-0322.mediawiki196
-rw-r--r--bip-0325.mediawiki23
-rw-r--r--bip-0340.mediawiki6
-rw-r--r--bip-0340/reference.py5
-rw-r--r--bip-0340/test-vectors.py2
-rw-r--r--bip-0341.mediawiki2
-rw-r--r--bip-0342.mediawiki2
22 files changed, 342 insertions, 276 deletions
diff --git a/README.mediawiki b/README.mediawiki
index ca28339..83120ab 100644
--- a/README.mediawiki
+++ b/README.mediawiki
@@ -398,7 +398,7 @@ Those proposing changes should consider that ultimately consent may rest with th
| Bustapay :: a practical coinjoin protocol
| Ryan Havar
| Informational
-| Proposed
+| Replaced
|-
| [[bip-0080.mediawiki|80]]
|
@@ -546,13 +546,13 @@ Those proposing changes should consider that ultimately consent may rest with th
| Thomas Kerin, Mark Friedenbach
| Standard
| Final
-|-
+|- style="background-color: #ffcfcf"
| [[bip-0114.mediawiki|114]]
| Consensus (soft fork)
| Merkelized Abstract Syntax Tree
| Johnson Lau
| Standard
-| Draft
+| Rejected
|- style="background-color: #ffcfcf"
| [[bip-0115.mediawiki|115]]
| Consensus (soft fork)
@@ -616,13 +616,13 @@ Those proposing changes should consider that ultimately consent may rest with th
| Eric Lombrozo
| Process
| Active
-|-
+|- style="background-color: #ffcfcf"
| [[bip-0124.mediawiki|124]]
| Applications
| Hierarchical Deterministic Script Templates
| Eric Lombrozo, William Swanson
| Informational
-| Draft
+| Rejected
|- style="background-color: #ffffcf"
| [[bip-0125.mediawiki|125]]
| Applications
@@ -679,13 +679,13 @@ Those proposing changes should consider that ultimately consent may rest with th
| Tom Zander
| Standard
| Rejected
-|-
+|- style="background-color: #ffcfcf"
| [[bip-0135.mediawiki|135]]
|
| Generalized version bits voting
| Sancho Panza
| Informational
-| Draft
+| Rejected
|-
| [[bip-0136.mediawiki|136]]
| Applications
@@ -938,13 +938,13 @@ Those proposing changes should consider that ultimately consent may rest with th
| Karl-Johan Alm
| Standard
| Draft
-|-
+|- style="background-color: #ffffcf"
| [[bip-0325.mediawiki|325]]
| Applications
| Signet
-| Karl-Johan Alm
+| Karl-Johan Alm, Anthony Towns
| Standard
-| Draft
+| Proposed
|-
| [[bip-0330.mediawiki|330]]
| Peer Services
diff --git a/bip-0008.mediawiki b/bip-0008.mediawiki
index 6fa8cea..7030a20 100644
--- a/bip-0008.mediawiki
+++ b/bip-0008.mediawiki
@@ -37,8 +37,8 @@ Each soft fork deployment is specified by the following per-chain parameters (fu
# The '''name''' specifies a very brief description of the soft fork, reasonable for use as an identifier. For deployments described in a single BIP, it is recommended to use the name "bipN" where N is the appropriate BIP number.
# The '''bit''' determines which bit in the nVersion field of the block is to be used to signal the soft fork lock-in and activation. It is chosen from the set {0,1,2,...,28}.
# The '''startheight''' specifies the height of the first block at which the bit gains its meaning.
-# The '''timeoutheight''' specifies a block height at which the miner signalling ends. Once this height has been reached, if the soft fork has not yet locked in (excluding this block's bit state), the deployment is either considered failed on all descendants of the block (but see the exception during '''FAILING''' state), or, if '''lockinontimeout'' is true, transitions to the '''LOCKED_IN''' state.
-# The '''lockinontimeout''' boolean if set to true, will transition state to '''LOCKED_IN''' at timeoutheight if not already '''LOCKED_IN''' or '''ACTIVE'''.
+# The '''timeoutheight''' specifies a block height at which the miner signalling ends. Once this height has been reached, if the soft fork has not yet locked in (excluding this block's bit state), the deployment is considered failed on all descendants of the block.
+# The '''lockinontimeout''' boolean if set to true, blocks are required to signal in the final period, ensuring the soft fork has locked in by timeoutheight.
===Selection guidelines===
@@ -53,16 +53,18 @@ The following guidelines are suggested for selecting these parameters for a soft
A later deployment using the same bit is possible as long as the startheight is after the previous one's
timeoutheight or activation, but it is discouraged until necessary, and even then recommended to have a pause in between to detect buggy software.
+'''startheight''' and '''timeoutheight''' must be an exact multiple of 2016 (ie, at a retarget boundary), and '''timeoutheight''' must be at least 4096 blocks (2 retarget intervals) after '''startheight'''.
+
===States===
With each block and soft fork, we associate a deployment state. The possible states are:
# '''DEFINED''' is the first state that each soft fork starts out as. The genesis block is by definition in this state for each deployment.
# '''STARTED''' for blocks at or beyond the startheight.
-# '''LOCKED_IN''' for one retarget period after the first retarget period with STARTED blocks of which at least threshold have the associated bit set in nVersion, or for one retarget period after the timeout when '''lockinontimeout''' is true.
+# '''MUST_SIGNAL''' for one retarget period prior to the timeout, if LOCKED_IN was not reached and '''lockinontimeout''' is true.
+# '''LOCKED_IN''' for one retarget period after the first retarget period with STARTED (or MUST_SIGNAL) blocks of which at least threshold have the associated bit set in nVersion.
# '''ACTIVE''' for all blocks after the LOCKED_IN retarget period.
-# '''FAILING''' for one retarget period after the timeout, if LOCKED_IN was not reached and '''lockinontimeout''' is false.
-# '''FAILED''' for all blocks after the FAILING retarget period.
+# '''FAILED''' for all blocks after the timeoutheight if LOCKED_IN is not reached.
===Bit flags===
@@ -77,19 +79,18 @@ for the purposes of this proposal, and support two future upgrades for different
When a block nVersion does not have top bits 001, it is treated as if all
bits are 0 for the purposes of deployments.
-Miners must continue setting the bit in LOCKED_IN phase so uptake is visible and acknowledged.
-Blocks without the applicable bit set are invalid during this period.
-For flexibility, this rule does NOT require the top 3 bits to be set any particular way.
-
===New consensus rules===
The new consensus rules for each soft fork are enforced for each block that has ACTIVE state.
+During the MUST_SIGNAL and LOCKED_IN phases, blocks that fail to signal are invalid.
+For flexibility, during the LOCKED_IN phase only, this rule does NOT require the top 3 bits to be set any particular way.
+
===State transitions===
<img src="bip-0008/states.png" align="middle"></img>
-During the STARTED state if the '''lockinontimeout''' is set to true, the state will transition to LOCKED_IN when '''timeoutheight''' is reached.
+Note that when '''lockinontimeout''' is true, the LOCKED_IN state will be reached no later than at a height of '''timeoutheight''', and ACTIVE will be reached no later than at a height of '''timeoutheight + 2016'''.
The genesis block has state DEFINED for each deployment, by definition.
@@ -121,7 +122,8 @@ We remain in the initial state until we reach the start block height.
After a period in the STARTED state, we tally the bits set,
and transition to LOCKED_IN if a sufficient number of blocks in the past period set the deployment bit in their
version numbers. The threshold is ≥1916 blocks (95% of 2016), or ≥1512 for testnet (75% of 2016).
-If the threshold hasn't been met, and we reach the timeout, then we either transition to LOCKED_IN state anyway (if lockinontimeout is true), or we transition to FAILING.
+If the threshold hasn't been met, lockinontimeout is true, and we are at the last period before the timeout, then we transition to MUST_SIGNAL.
+If the threshold hasn't been met and we reach the timeout, we transition directly to FAILED.
Note that a block's state never depends on its own nVersion; only on that of its ancestors.
@@ -131,28 +133,22 @@ Note that a block's state never depends on its own nVersion; only on that of its
for (i = 0; i < 2016; i++) {
walk = walk.parent;
if (walk.nVersion & 0xE0000000 == 0x20000000 && (walk.nVersion >> bit) & 1 == 1) {
- count++;
+ ++count;
}
}
if (count >= threshold) {
return LOCKED_IN;
+ } else if (lockinontimeout && block.height + 2016 >= timeoutheight) {
+ return MUST_SIGNAL;
} else if (block.height >= timeoutheight) {
- return (lockinontimeout == true) ? LOCKED_IN : FAILING;
+ return FAILED;
}
return STARTED;
-If the deployment is not LOCKED_IN by the timeout (or '''lockinontimeout'''), it has a single retarget period during which it may still become active, only by unanimous signalling in every block.
-This state exists such that if '''lockinontimeout''' is set to true later, it remains compatible with the original deployment.
+If we have finished a period of MUST_SIGNAL, we transition directly to LOCKED_IN.
- case FAILING:
- walk = block;
- for (i = 0; i < 2016; i++) {
- walk = walk.parent;
- if (walk.nVersion & 0xE0000000 == 0x20000000 && ((walk.nVersion >> bit) & 1) != 1) {
- return FAILED;
- }
- }
- return ACTIVE;
+ case MUST_SIGNAL:
+ return LOCKED_IN;
After a retarget period of LOCKED_IN, we automatically transition to ACTIVE.
@@ -178,6 +174,25 @@ current retarget period (i.e. up to and including its ancestor with height block
it is possible to implement the mechanism above efficiently and safely by caching the resulting state of every multiple-of-2016
block, indexed by its parent.
+===Mandatory signalling===
+
+Blocks received while in the MUST_SIGNAL and LOCKED_IN phases must be checked to ensure that they signal. For example:
+
+ if (GetStateForBlock(block) == MUST_SIGNAL) {
+ if ((block.nVersion & 0xE0000000) != 0x20000000 || ((block.nVersion >> bit) & 1) != 1) {
+ return state.Invalid(BlockValidationResult::RECENT_CONSENSUS_CHANGE, "bad-version-bip8-must-signal");
+ }
+ }
+ if (GetStateForBlock(block) == LOCKED_IN) {
+ if (((block.nVersion >> bit) & 1) != 1) {
+ return state.Invalid(BlockValidationResult::RECENT_CONSENSUS_CHANGE, "bad-version-bip8-locked-in");
+ }
+ }
+
+Implementations should be careful not to ban peers that send blocks that are invalid due to not signalling (or blocks that build on those blocks), as that would allow an incompatible chain that is only briefly longer than the compliant chain to cause a split of the p2p network. If that occurred, nodes that have not set ''lockinontimeout'' may not see new blocks in the compliant chain, and thus not reorg to it at the point when it has more work, and would thus not be following the valid chain with the most work.
+
+Implementations with ''lockinontimeout'' set to true may potentially follow a lower work chain than nodes with ''lockinontimeout'' set to false for an extended period. In order for this not to result in a net split nodes with ''lockinontimeout'' set to true, those nodes may need to preferentially connect to each other. Deployments proposing that implementations set ''lockinontimeout'' to true should either use parameters that do not risk there being a higher work alternative chain, or specify a mechanism for implementations that support the deployment to preferentially peer with each other.
+
===Warning mechanism===
To support upgrade warnings, an extra "unknown upgrade" is tracked, using the "implicit bit" mask = (block.nVersion & ~expectedVersion) != 0. Mask will be non-zero whenever an unexpected bit is set in nVersion. Whenever LOCKED_IN for the unknown upgrade is detected, the software should warn loudly about the upcoming soft fork. It should warn even more loudly after the next retarget period (when the unknown upgrade is in the ACTIVE state).
@@ -211,7 +226,7 @@ The template Object is also extended:
The "version" key of the template is retained, and used to indicate the server's preference of deployments.
If versionbits is being used, "version" MUST be within the versionbits range of [0x20000000...0x3FFFFFFF].
Miners MAY clear or set bits in the block version WITHOUT any special "mutable" key, provided they are listed among the template's "vbavailable" and (when clearing is desired) NOT included as a bit in "vbrequired".
-Servers MUST set bits in "vbrequired" for deployments in LOCKED_IN state, to ensure blocks produced are valid.
+Servers MUST set bits in "vbrequired" for deployments in MUST_SIGNAL and LOCKED_IN states, to ensure blocks produced are valid.
Softfork deployment names listed in "rules" or as keys in "vbavailable" may be prefixed by a '!' character.
Without this prefix, GBT clients may assume the rule will not impact usage of the template as-is; typical examples of this would be when previously valid transactions cease to be valid, such as BIPs 16, 65, 66, 68, 112, and 113.
@@ -225,9 +240,8 @@ https://github.com/bitcoin/bitcoin/compare/master...luke-jr:bip8
==Contrasted with BIP 9==
-* The '''lockinontimeout''' flag is added. BIP 9 would only transition to the FAILED state when timeout was reached.
+* The '''lockinontimeout''' flag is added, providing a way to guarantee transition to LOCKED_IN.
* Block heights are used for the deployment monotonic clock, rather than median-time-past.
-* The last-ditch effort during a new FAILING state is added to allow '''lockinontimeout''' to be safely set after the initial deployment.
==Backwards compatibility==
diff --git a/bip-0008/states.dot b/bip-0008/states.dot
new file mode 100644
index 0000000..aa919ff
--- /dev/null
+++ b/bip-0008/states.dot
@@ -0,0 +1,34 @@
+digraph {
+ rankdir=TD;
+
+ node [style="rounded,filled,bold", shape=box, fixedsize=true, width=1.5, fontname="Arial"];
+
+ edge [weight = 100];
+ "DEFINED" -> "STARTED" [label="height >= start_height"];
+ "STARTED" -> "MUST_SIGNAL" [label="height + 2016 >= timeoutheight AND lockinontimeout"];
+ "STARTED" -> "FAILED" [label="height >= timeoutheight\nAND\nNOT lockinontimeout"];
+ "LOCKED_IN" -> "ACTIVE" [label="always"];
+ "MUST_SIGNAL" -> "LOCKED_IN" [label="always"];
+
+ edge [weight = 1];
+ "STARTED" -> "LOCKED_IN" [label="height < timeoutheight\nAND\nthreshold reached"];
+
+ "FAILED" -> "LOCKED_IN" [style=invis];
+
+ "DEFINED":sw -> "DEFINED":nw;
+ "STARTED":sw -> "STARTED":nw;
+ "ACTIVE":sw -> "ACTIVE":nw;
+ "FAILED":sw -> "FAILED":nw;
+
+ "STARTED" [fillcolor="#a0a0ff"];
+ "MUST_SIGNAL" [fillcolor="#a0a0ff"];
+ "LOCKED_IN" [fillcolor="#ffffa0"];
+ "ACTIVE" [fillcolor="#a0ffa0"];
+ "FAILED" [fillcolor="#ffa0a0"];
+
+ { rank=same; "STARTED" "MUST_SIGNAL" }
+ { rank=same; "FAILED" "LOCKED_IN" }
+ { rank=sink; "ACTIVE" }
+}
+
+
diff --git a/bip-0008/states.png b/bip-0008/states.png
index 76f6cb7..6477ed3 100644
--- a/bip-0008/states.png
+++ b/bip-0008/states.png
Binary files differ
diff --git a/bip-0008/states.svg b/bip-0008/states.svg
index f2e4b34..3503c34 100644
--- a/bip-0008/states.svg
+++ b/bip-0008/states.svg
@@ -1,55 +1,120 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 848 464" width="905" height="495">
- <defs>
- <style type="text/css"><![CDATA[
- rect {
- fill: white;
- stroke: black;
- stroke-width: 1;
- }
- text {
- fill: black;
- }
- svg>path {
- stroke: black;
- stroke-width: 2;
- fill: none;
- marker-end: url(#arrow);
- }
- ]]></style>
- <marker id="arrow" markerWidth="13" markerHeight="13" refX="8" refY="6" orient="auto">
- <path d="M0,2 L0,11 L8,6 L0,2" style="fill: black;" />
- </marker>
- </defs>
-
- <rect x="112" y="48" width="128" height="32"/>
- <text x="176" y="72" font-size="20" text-anchor="middle">DEFINED</text>
- <path d="M 128 80 a 24 32 0 1 1 0 -32"/><!-- loop -->
- <path d="M 176 80 l 0 96"/>
- <text x="182" y="128" font-size="12" text-anchor="start">startheight &lt;= height</text>
- <rect x="112" y="176" width="128" height="32"/>
- <text x="176" y="200" font-size="20" text-anchor="middle">STARTED</text>
- <path d="M 128 208 a 24 32 0 1 1 0 -32"/><!-- loop -->
- <path d="M 176 208 l 0 96"/>
- <text x="182" y="232" font-size="12" text-anchor="start">(lockinontimeout == false) AND (height &lt; timeoutheight) AND (threshold reached)</text>
- <text x="304" y="256" font-size="12" text-anchor="start">OR</text>
- <text x="182" y="280" font-size="12" text-anchor="start">(lockinontimeout == true) AND ((height &gt;= timeoutheight) OR (threshold reached))</text>
- <rect x="112" y="304" width="128" height="32"/>
- <text x="176" y="328" font-size="20" text-anchor="middle">LOCKED_IN</text>
- <path d="M 176 336 l 0 48"/>
- <text x="182" y="360" font-size="12" text-anchor="start">Always</text>
- <rect x="112" y="384" width="128" height="32"/>
- <text x="176" y="408" font-size="20" text-anchor="middle">ACTIVE</text>
- <path d="M 128 416 a 24 32 0 1 1 0 -32"/><!-- loop -->
-
- <rect x="640" y="176" width="128" height="32"/>
- <text x="704" y="200" font-size="20" text-anchor="middle">FAILING</text>
- <path d="M 240 192 l 400 0"/>
- <text x="408" y="184" font-size="12" text-anchor="middle">(lockinontimeout == false) AND (timeoutheight &lt;= height)</text>
- <path d="M 704 208 l 0 176"/>
- <text x="720" y="296" font-size="12" text-anchor="start">NOT all blocks signal</text>
- <path d="M 656 208 c 0 196 -416 176 -416 176"/>
- <text x="544" y="352" font-size="12" text-anchor="start">all blocks signal</text>
- <rect x="640" y="384" width="128" height="32"/>
- <text x="704" y="408" font-size="20" text-anchor="middle">FAILED</text>
- <path d="M 756 416 a 24 32 0 1 0 0 -32"/><!-- loop -->
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.42.3 (20191010.1750)
+ -->
+<!-- Title: %3 Pages: 1 -->
+<svg width="563pt" height="348pt"
+ viewBox="0.00 0.00 563.00 348.37" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 344.37)">
+<title>%3</title>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-344.37 559,-344.37 559,4 -4,4"/>
+<!-- DEFINED -->
+<g id="node1" class="node">
+<title>DEFINED</title>
+<path fill="lightgrey" stroke="black" stroke-width="2" d="M114,-333.75C114,-333.75 30,-333.75 30,-333.75 24,-333.75 18,-327.75 18,-321.75 18,-321.75 18,-309.75 18,-309.75 18,-303.75 24,-297.75 30,-297.75 30,-297.75 114,-297.75 114,-297.75 120,-297.75 126,-303.75 126,-309.75 126,-309.75 126,-321.75 126,-321.75 126,-327.75 120,-333.75 114,-333.75"/>
+<text text-anchor="middle" x="72" y="-312.05" font-family="Arial" font-size="14.00">DEFINED</text>
+</g>
+<!-- DEFINED&#45;&gt;DEFINED -->
+<g id="edge8" class="edge">
+<title>DEFINED:sw&#45;&gt;DEFINED:nw</title>
+<path fill="none" stroke="black" d="M18,-297.75C12,-287.25 0,-287.25 0,-315.75 0,-334.01 4.92,-340.57 10.04,-340.17"/>
+<polygon fill="black" stroke="black" points="12.41,-342.75 18,-333.75 8.02,-337.3 12.41,-342.75"/>
+</g>
+<!-- STARTED -->
+<g id="node2" class="node">
+<title>STARTED</title>
+<path fill="#a0a0ff" stroke="black" stroke-width="2" d="M114,-246.75C114,-246.75 30,-246.75 30,-246.75 24,-246.75 18,-240.75 18,-234.75 18,-234.75 18,-222.75 18,-222.75 18,-216.75 24,-210.75 30,-210.75 30,-210.75 114,-210.75 114,-210.75 120,-210.75 126,-216.75 126,-222.75 126,-222.75 126,-234.75 126,-234.75 126,-240.75 120,-246.75 114,-246.75"/>
+<text text-anchor="middle" x="72" y="-225.05" font-family="Arial" font-size="14.00">STARTED</text>
+</g>
+<!-- DEFINED&#45;&gt;STARTED -->
+<g id="edge1" class="edge">
+<title>DEFINED&#45;&gt;STARTED</title>
+<path fill="none" stroke="black" d="M72,-297.55C72,-285.91 72,-270.3 72,-256.99"/>
+<polygon fill="black" stroke="black" points="75.5,-256.93 72,-246.93 68.5,-256.93 75.5,-256.93"/>
+<text text-anchor="middle" x="133" y="-268.55" font-family="Times,serif" font-size="14.00">height &gt;= start_height</text>
+</g>
+<!-- STARTED&#45;&gt;STARTED -->
+<g id="edge9" class="edge">
+<title>STARTED:sw&#45;&gt;STARTED:nw</title>
+<path fill="none" stroke="black" d="M18,-210.75C12,-200.25 0,-200.25 0,-228.75 0,-247.01 4.92,-253.57 10.04,-253.17"/>
+<polygon fill="black" stroke="black" points="12.41,-255.75 18,-246.75 8.02,-250.3 12.41,-255.75"/>
+</g>
+<!-- MUST_SIGNAL -->
+<g id="node3" class="node">
+<title>MUST_SIGNAL</title>
+<path fill="#a0a0ff" stroke="black" stroke-width="2" d="M543,-246.75C543,-246.75 459,-246.75 459,-246.75 453,-246.75 447,-240.75 447,-234.75 447,-234.75 447,-222.75 447,-222.75 447,-216.75 453,-210.75 459,-210.75 459,-210.75 543,-210.75 543,-210.75 549,-210.75 555,-216.75 555,-222.75 555,-222.75 555,-234.75 555,-234.75 555,-240.75 549,-246.75 543,-246.75"/>
+<text text-anchor="middle" x="501" y="-225.05" font-family="Arial" font-size="14.00">MUST_SIGNAL</text>
+</g>
+<!-- STARTED&#45;&gt;MUST_SIGNAL -->
+<g id="edge2" class="edge">
+<title>STARTED&#45;&gt;MUST_SIGNAL</title>
+<path fill="none" stroke="black" d="M126.33,-228.75C205.44,-228.75 352.08,-228.75 436.54,-228.75"/>
+<polygon fill="black" stroke="black" points="436.77,-232.25 446.77,-228.75 436.77,-225.25 436.77,-232.25"/>
+<text text-anchor="middle" x="286.5" y="-235.55" font-family="Times,serif" font-size="14.00">height + 2016 &gt;= timeoutheight AND lockinontimeout</text>
+</g>
+<!-- FAILED -->
+<g id="node4" class="node">
+<title>FAILED</title>
+<path fill="#ffa0a0" stroke="black" stroke-width="2" d="M114,-129.75C114,-129.75 30,-129.75 30,-129.75 24,-129.75 18,-123.75 18,-117.75 18,-117.75 18,-105.75 18,-105.75 18,-99.75 24,-93.75 30,-93.75 30,-93.75 114,-93.75 114,-93.75 120,-93.75 126,-99.75 126,-105.75 126,-105.75 126,-117.75 126,-117.75 126,-123.75 120,-129.75 114,-129.75"/>
+<text text-anchor="middle" x="72" y="-108.05" font-family="Arial" font-size="14.00">FAILED</text>
+</g>
+<!-- STARTED&#45;&gt;FAILED -->
+<g id="edge3" class="edge">
+<title>STARTED&#45;&gt;FAILED</title>
+<path fill="none" stroke="black" d="M72,-210.28C72,-191.69 72,-161.99 72,-140.25"/>
+<polygon fill="black" stroke="black" points="75.5,-140 72,-130 68.5,-140 75.5,-140"/>
+<text text-anchor="middle" x="139" y="-181.55" font-family="Times,serif" font-size="14.00">height &gt;= timeoutheight</text>
+<text text-anchor="middle" x="139" y="-166.55" font-family="Times,serif" font-size="14.00">AND</text>
+<text text-anchor="middle" x="139" y="-151.55" font-family="Times,serif" font-size="14.00">NOT lockinontimeout</text>
+</g>
+<!-- LOCKED_IN -->
+<g id="node5" class="node">
+<title>LOCKED_IN</title>
+<path fill="#ffffa0" stroke="black" stroke-width="2" d="M543,-129.75C543,-129.75 459,-129.75 459,-129.75 453,-129.75 447,-123.75 447,-117.75 447,-117.75 447,-105.75 447,-105.75 447,-99.75 453,-93.75 459,-93.75 459,-93.75 543,-93.75 543,-93.75 549,-93.75 555,-99.75 555,-105.75 555,-105.75 555,-117.75 555,-117.75 555,-123.75 549,-129.75 543,-129.75"/>
+<text text-anchor="middle" x="501" y="-108.05" font-family="Arial" font-size="14.00">LOCKED_IN</text>
+</g>
+<!-- STARTED&#45;&gt;LOCKED_IN -->
+<g id="edge6" class="edge">
+<title>STARTED&#45;&gt;LOCKED_IN</title>
+<path fill="none" stroke="black" d="M126.15,-214.34C151.63,-207.94 182.41,-200.1 210,-192.75 281.79,-173.62 299.35,-167.41 371,-147.75 392.5,-141.85 416.03,-135.49 437.09,-129.83"/>
+<polygon fill="black" stroke="black" points="438.14,-133.17 446.89,-127.19 436.32,-126.41 438.14,-133.17"/>
+<text text-anchor="middle" x="434" y="-181.55" font-family="Times,serif" font-size="14.00">height &lt; timeoutheight</text>
+<text text-anchor="middle" x="434" y="-166.55" font-family="Times,serif" font-size="14.00">AND</text>
+<text text-anchor="middle" x="434" y="-151.55" font-family="Times,serif" font-size="14.00">threshold reached</text>
+</g>
+<!-- MUST_SIGNAL&#45;&gt;LOCKED_IN -->
+<g id="edge5" class="edge">
+<title>MUST_SIGNAL&#45;&gt;LOCKED_IN</title>
+<path fill="none" stroke="black" d="M501,-210.28C501,-191.69 501,-161.99 501,-140.25"/>
+<polygon fill="black" stroke="black" points="504.5,-140 501,-130 497.5,-140 504.5,-140"/>
+<text text-anchor="middle" x="520" y="-166.55" font-family="Times,serif" font-size="14.00">always</text>
+</g>
+<!-- FAILED&#45;&gt;FAILED -->
+<g id="edge11" class="edge">
+<title>FAILED:sw&#45;&gt;FAILED:nw</title>
+<path fill="none" stroke="black" d="M18,-93.75C12,-83.25 0,-83.25 0,-111.75 0,-130.01 4.92,-136.57 10.04,-136.17"/>
+<polygon fill="black" stroke="black" points="12.41,-138.75 18,-129.75 8.02,-133.3 12.41,-138.75"/>
+</g>
+<!-- FAILED&#45;&gt;LOCKED_IN -->
+<!-- ACTIVE -->
+<g id="node6" class="node">
+<title>ACTIVE</title>
+<path fill="#a0ffa0" stroke="black" stroke-width="2" d="M543,-42.75C543,-42.75 459,-42.75 459,-42.75 453,-42.75 447,-36.75 447,-30.75 447,-30.75 447,-18.75 447,-18.75 447,-12.75 453,-6.75 459,-6.75 459,-6.75 543,-6.75 543,-6.75 549,-6.75 555,-12.75 555,-18.75 555,-18.75 555,-30.75 555,-30.75 555,-36.75 549,-42.75 543,-42.75"/>
+<text text-anchor="middle" x="501" y="-21.05" font-family="Arial" font-size="14.00">ACTIVE</text>
+</g>
+<!-- LOCKED_IN&#45;&gt;ACTIVE -->
+<g id="edge4" class="edge">
+<title>LOCKED_IN&#45;&gt;ACTIVE</title>
+<path fill="none" stroke="black" d="M501,-93.55C501,-81.91 501,-66.3 501,-52.99"/>
+<polygon fill="black" stroke="black" points="504.5,-52.93 501,-42.93 497.5,-52.93 504.5,-52.93"/>
+<text text-anchor="middle" x="520" y="-64.55" font-family="Times,serif" font-size="14.00">always</text>
+</g>
+<!-- ACTIVE&#45;&gt;ACTIVE -->
+<g id="edge10" class="edge">
+<title>ACTIVE:sw&#45;&gt;ACTIVE:nw</title>
+<path fill="none" stroke="black" d="M447,-6.75C441,3.75 429,3.75 429,-24.75 429,-43.01 433.92,-49.57 439.04,-49.17"/>
+<polygon fill="black" stroke="black" points="441.41,-51.75 447,-42.75 437.02,-46.3 441.41,-51.75"/>
+</g>
+</g>
</svg>
diff --git a/bip-0009.mediawiki b/bip-0009.mediawiki
index a68bb80..f90919a 100644
--- a/bip-0009.mediawiki
+++ b/bip-0009.mediawiki
@@ -217,7 +217,7 @@ Soft forks right now are typically treated as booleans: they go from an inactive
The failure timeout allows eventual reuse of bits even if a soft fork was
never activated, so it's clear that the new use of the bit refers to a
-new BIP. It's deliberately very course grained, to take into account
+new BIP. It's deliberately very coarse-grained, to take into account
reasonable development and deployment delays. There are unlikely to be
enough failed proposals to cause a bit shortage.
diff --git a/bip-0039.mediawiki b/bip-0039.mediawiki
index 2b95c51..c5ab9bb 100644
--- a/bip-0039.mediawiki
+++ b/bip-0039.mediawiki
@@ -18,7 +18,7 @@
This BIP describes the implementation of a mnemonic code or mnemonic sentence --
a group of easy to remember words -- for the generation of deterministic wallets.
-It consists of two parts: generating the mnemonic, and converting it into a
+It consists of two parts: generating the mnemonic and converting it into a
binary seed. This seed can be later used to generate deterministic wallets using
BIP-0032 or similar methods.
@@ -29,7 +29,7 @@ handling of raw binary or hexadecimal representations of a wallet seed. The
sentence could be written on paper or spoken over the telephone.
This guide is meant to be a way to transport computer-generated randomness with
-a human readable transcription. It's not a way to process user-created
+a human-readable transcription. It's not a way to process user-created
sentences (also known as brainwallets) into a wallet seed.
==Generating the mnemonic==
@@ -46,7 +46,7 @@ as an index into a wordlist. Finally, we convert these numbers into words and
use the joined words as a mnemonic sentence.
The following table describes the relation between the initial entropy
-length (ENT), the checksum length (CS) and the length of the generated mnemonic
+length (ENT), the checksum length (CS), and the length of the generated mnemonic
sentence (MS) in words.
<pre>
@@ -67,12 +67,12 @@ MS = (ENT + CS) / 11
An ideal wordlist has the following characteristics:
a) smart selection of words
- - the wordlist is created in such way that it's enough to type the first four
+ - the wordlist is created in such a way that it's enough to type the first four
letters to unambiguously identify the word
b) similar words avoided
- word pairs like "build" and "built", "woman" and "women", or "quick" and "quickly"
- not only make remembering the sentence difficult, but are also more error
+ not only make remembering the sentence difficult but are also more error
prone and more difficult to guess
c) sorted wordlists
@@ -97,7 +97,7 @@ This seed can be later used to generate deterministic wallets using BIP-0032 or
similar methods.
The conversion of the mnemonic sentence to a binary seed is completely independent
-from generating the sentence. This results in rather simple code; there are no
+from generating the sentence. This results in a rather simple code; there are no
constraints on sentence structure and clients are free to implement their own
wordlists or even whole sentence generators, allowing for flexibility in wordlists
for typo detection or other purposes.
@@ -168,7 +168,9 @@ Rust:
Swift:
* https://github.com/CikeQiu/CKMnemonic
* https://github.com/yuzushioh/WalletKit
+* https://github.com/pengpengliu/BIP39
* https://github.com/matter-labs/web3swift/blob/develop/Sources/web3swift/KeystoreManager/BIP39.swift
+* https://github.com/zcash-hackworks/MnemonicSwift
C++:
* https://github.com/libbitcoin/libbitcoin-system/blob/master/include/bitcoin/system/wallet/mnemonic.hpp
diff --git a/bip-0039/bip-0039-wordlists.md b/bip-0039/bip-0039-wordlists.md
index 5971197..f2c173c 100644
--- a/bip-0039/bip-0039-wordlists.md
+++ b/bip-0039/bip-0039-wordlists.md
@@ -94,8 +94,8 @@ Words chosen using the following rules:
1. Words are 4-8 letters long.
2. Words can be uniquely determined typing the first 4 letters.
3. Only words containing all letters without diacritical marks. (It was the hardest task, because in one third of all Czech letters has diacritical marks.)
-4. Only nouns, werbs and adverbs, no other word types. All words are in basic form.
-5. No personal names or geografical names.
+4. Only nouns, verbs and adverbs, no other word types. All words are in basic form.
+5. No personal names or geographical names.
6. No very similar words with 1 letter of difference.
7. Words are sorting according English alphabet (Czech sorting has difference in "ch").
8. No words already used in other language mnemonic sets (english, italian, french, spanish). Letters with diacritical marks from these sets are counted as analogous letters without diacritical marks.
diff --git a/bip-0049.mediawiki b/bip-0049.mediawiki
index 0029003..7d8d2c7 100644
--- a/bip-0049.mediawiki
+++ b/bip-0049.mediawiki
@@ -26,7 +26,7 @@ will detect the accounts and handle them appropriately.
===Considerations===
Two generally different approaches are possible for current BIP44 capable wallets:
-1) Allow the user to use the same account(s) that they already uses, but add segregated witness encoded addresses to it.
+1) Allow the user to use the same account(s) that they already use, but add segregated witness encoded addresses to it.
1.1) Use the same public keys as defined in BIP44, but in addition to the normal P2PKH address also derive the P2SH address from it.
diff --git a/bip-0114.mediawiki b/bip-0114.mediawiki
index 21d0b6c..410e84c 100644
--- a/bip-0114.mediawiki
+++ b/bip-0114.mediawiki
@@ -5,7 +5,7 @@
Author: Johnson Lau <jl2012@xbt.hk>
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0114
- Status: Draft
+ Status: Rejected
Type: Standards Track
Created: 2016-04-02
License: PD
diff --git a/bip-0119.mediawiki b/bip-0119.mediawiki
index 7a87b24..730ffb9 100644
--- a/bip-0119.mediawiki
+++ b/bip-0119.mediawiki
@@ -266,7 +266,7 @@ segwit transaction in which case it must be only the exact redeemscript. P2SH is
(unless the P2SH hash is broken) with CHECKTEMPLATEVERIFY because the template hash must commit
to the ScriptSig, which must contain the redeemscript, which is a hash cycle.
-To prevent succeptibility to malleability when not using a segwit input, we also commit to the
+To prevent malleability when not using a segwit input, we also commit to the
scriptsig. This makes it possible to use a 2 input CHECKTEMPLATEVERIFY with a legacy pre-signed
spend, as long as the exact scriptsig for the legacy output is committed. This is more robust than
simply disallowing any scriptSig to be set with CHECKTEMPLATEVERIFY.
diff --git a/bip-0124.mediawiki b/bip-0124.mediawiki
index a5929ac..69cb134 100644
--- a/bip-0124.mediawiki
+++ b/bip-0124.mediawiki
@@ -6,7 +6,7 @@
William Swanson <swansontec@gmail.com>
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0124
- Status: Draft
+ Status: Rejected
Type: Informational
Created: 2015-11-20
License: PD
diff --git a/bip-0135.mediawiki b/bip-0135.mediawiki
index 89d3077..1324746 100644
--- a/bip-0135.mediawiki
+++ b/bip-0135.mediawiki
@@ -5,7 +5,7 @@
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0135
https://bitco.in/forum/threads/bip9-generalized-version-bits-voting-bip-genvbvoting.1968/
- Status: Draft
+ Status: Rejected
Type: Informational
Created: 2017-03-29
License: CC0-1.0
diff --git a/bip-0155.mediawiki b/bip-0155.mediawiki
index 1364a3f..ab3c0fc 100644
--- a/bip-0155.mediawiki
+++ b/bip-0155.mediawiki
@@ -46,7 +46,7 @@ The <code>addrv2</code> message is defined as a message where <code>pchCommand =
It is serialized in the standard encoding for P2P messages.
Its format is similar to the current <code>addr</code> message format
<ref>[https://bitcoin.org/en/developer-reference#addr Bitcoin Developer Reference: addr message]</ref>, with the difference that the
-fixed 16-byte IP address is replaced by a network ID and a variable-length address, and the time and services format has been changed to VARINT.
+fixed 16-byte IP address is replaced by a network ID and a variable-length address, and the services format has been changed to [https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer CompactSize].
This means that the message contains a serialized <code>std::vector</code> of the following structure:
@@ -55,13 +55,13 @@ This means that the message contains a serialized <code>std::vector</code> of th
!Name
!Description
|-
-| <code>VARINT</code> (unsigned)
+| <code>uint32_t</code>
| <code>time</code>
-| Time that this node was last seen as connected to the network. A time in Unix epoch time format, up to 64 bits wide.
+| Time that this node was last seen as connected to the network. A time in Unix epoch time format.
|-
-| <code>VARINT</code> (unsigned)
+| <code>CompactSize</code>
| <code>services</code>
-| Service bits. A 64-wide bit field.
+| Service bits. A bit field that is 64 bits wide, encoded in [https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer CompactSize].
|-
| <code>uint8_t</code>
| <code>networkID</code>
@@ -134,7 +134,7 @@ See the appendices for the address encodings to be used for the various networks
Introduce a new message type <code>sendaddrv2</code>. Sending such a message indicates that a node can understand and prefers to receive <code>addrv2</code> messages instead of <code>addr</code> messages. I.e. "Send me addrv2".
-<code>sendaddrv2</code> SHOULD be sent after receiving the <code>verack</code> message from the peer.
+The <code>sendaddrv2</code> message MUST only be sent in response to the <code>version</code> message from a peer and prior to sending the <code>verack</code> message.
For older peers, that did not emit <code>sendaddrv2</code>, keep sending the legacy <code>addr</code> message, ignoring addresses with the newly introduced address types.
@@ -144,15 +144,13 @@ The reference implementation is available at (to be done)
==Acknowledgements==
-- Jonas Schnelli: change <code>services</code> field to VARINT, to make the message more compact in the likely case instead of always using 8 bytes.
-
-- Luke-Jr: change <code>time</code> field to VARINT, for post-2038 compatibility.
+- Jonas Schnelli: change <code>services</code> field to [https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer CompactSize], to make the message more compact in the likely case instead of always using 8 bytes.
- Gregory Maxwell: various suggestions regarding extensibility
==Appendix A: Tor v2 address encoding==
-The new message introduces a separate network ID for <code>TORV2</code>.
+The new message introduces a separate network ID for <code>TORV2</code>.
Clients MUST send Tor hidden service addresses with this network ID, with the 80-bit hidden service ID in the address field. This is the same as the representation in the legacy <code>addr</code> message, minus the 6 byte prefix of the OnionCat wrapping.
@@ -166,10 +164,11 @@ onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion"
CHECKSUM = H(".onion checksum" | PUBKEY | VERSION)[:2]
where:
- - PUBKEY is the 32 bytes ed25519 master pubkey of the hidden service.
- - VERSION is an one byte version field (default value '\x03')
+ - PUBKEY is the 32 bytes ed25519 master pubkey of the hidden service
+ - VERSION is a one byte version field (default value '\x03')
- ".onion checksum" is a constant string
- CHECKSUM is truncated to two bytes before inserting it in onion_address
+ - H() is the SHA3-256 cryptographic hash function
</pre>
Tor v3 addresses MUST be sent with the <code>TORV3</code> network ID, with the 32-byte PUBKEY part in the address field. As VERSION will always be '\x03' in the case of v3 addresses, this is enough to reconstruct the onion address.
diff --git a/bip-0174.mediawiki b/bip-0174.mediawiki
index 65fa9a9..c424c5d 100644
--- a/bip-0174.mediawiki
+++ b/bip-0174.mediawiki
@@ -200,25 +200,25 @@ The currently defined per-input types are defined as follows:
** Value: The UTF-8 encoded commitment message string for the proof-of-reserves. See [[bip-0127.mediawiki|BIP 127]] for more information.
*** <tt>{porCommitment}</tt>
-* Type: RIPEMD160 preimage <tt>PSBT_RIPEMD160 = 0x0a</tt>
+* Type: RIPEMD160 preimage <tt>PSBT_IN_RIPEMD160 = 0x0a</tt>
** Key: The resulting hash of the preimage
*** <tt>{0x0a}|{20-byte hash}</tt>
** Value: The hash preimage, encoded as a byte vector, which must equal the key when run through the `RIPEMD160` algorithm
*** <tt>{preimage}</tt>
-* Type: SHA256 preimage <tt>PSBT_SHA256 = 0x0b</tt>
+* Type: SHA256 preimage <tt>PSBT_IN_SHA256 = 0x0b</tt>
** Key: The resulting hash of the preimage
*** <tt>{0x0b}|{32-byte hash}</tt>
** Value: The hash preimage, encoded as a byte vector, which must equal the key when run through the `SHA256` algorithm
*** <tt>{preimage}</tt>
-* Type: HASH160 preimage <tt>PSBT_HASH160 = 0x0c</tt>
+* Type: HASH160 preimage <tt>PSBT_IN_HASH160 = 0x0c</tt>
** Key: The resulting hash of the preimage
*** <tt>{0x0c}|{20-byte hash}</tt>
** Value: The hash preimage, encoded as a byte vector, which must equal the key when run through the `SHA256` algorithm followed by the `RIPEMD160` algorithm
*** <tt>{preimage}</tt>
-* Type: HASH256 preimage <tt>PSBT_HASH256 = 0x0d</tt>
+* Type: HASH256 preimage <tt>PSBT_IN_HASH256 = 0x0d</tt>
** Key: The resulting hash of the preimage
*** <tt>{0x0d}|{32-byte hash}</tt>
** Value: The hash preimage, encoded as a byte vector, which must equal the key when run through the `SHA256` algorithm twice
@@ -350,9 +350,9 @@ It is useful when there are additional data that they need attached to a PSBT bu
The proprietary use type is not to be used by any public specification and there is no expectation that any publicly available software be able to understand any specific meanings of it and the subtypes.
This type must be used for internal processes only.
-==Responsibilities==
+==Roles==
-Using the transaction format involves many different responsibilities. Multiple responsibilities can be handled by a single entity, but each responsibility is specialized in what it should be capable of doing.
+Using the transaction format involves many different roles. Multiple roles can be handled by a single entity, but each role is specialized in what it should be capable of doing.
===Creator===
@@ -373,7 +373,7 @@ The Signer must only accept a PSBT.
The Signer must only use the UTXOs provided in the PSBT to produce signatures for inputs.
Before signing a non-witness input, the Signer must verify that the TXID of the non-witness UTXO matches the TXID specified in the unsigned transaction.
Before signing a witness input, the Signer must verify that the witnessScript (if provided) matches the hash specified in the UTXO or the redeemScript, and the redeemScript (if provided) matches the hash in the UTXO.
-The Signer may choose to fail to sign a segwit input if a non-witness UTXO is not provided. <ref>'''Why would non-witness UTXOs be provided for segwit inputs?''' The sighash algorithm for Segwit specified in BIP 173 is known to have an issue where an attacker could trick a user to sending Bitcoin to fees if they are able to convince the user to sign a malicious transaction multiple times. This is possible because the amounts in <tt>PSBT_IN_WITNESS_UTXO<tt> of other segwit inputs can be modified without effecting the signature for a particular input. In order to prevent this kind of attack, many wallets are requiring that the full previous transaction (i.e. <tt>PSBT_IN_NON_WITNESS_UTXO</tt>) be provided to ensure that the amounts of other inputs are not being tampered with.</ref>
+The Signer may choose to fail to sign a segwit input if a non-witness UTXO is not provided. <ref>'''Why would non-witness UTXOs be provided for segwit inputs?''' The sighash algorithm for Segwit specified in BIP 173 is known to have an issue where an attacker could trick a user to sending Bitcoin to fees if they are able to convince the user to sign a malicious transaction multiple times. This is possible because the amounts in <tt>PSBT_IN_WITNESS_UTXO</tt> of other segwit inputs can be modified without effecting the signature for a particular input. In order to prevent this kind of attack, many wallets are requiring that the full previous transaction (i.e. <tt>PSBT_IN_NON_WITNESS_UTXO</tt>) be provided to ensure that the amounts of other inputs are not being tampered with.</ref>
The Signer should not need any additional data sources, as all necessary information is provided in the PSBT format.
The Signer must only add data to a PSBT.
Any signatures created by the Signer must be added as a "Partial Signature" key-value pair for the respective input it relates to.
@@ -839,6 +839,26 @@ Any data types, their associated scope and BIP number must be defined here
| [[bip-0127.mediawiki|BIP 127]]
|-
| Input
+| 10
+| PSBT_IN_RIPEMD160
+| BIP 174
+|-
+| Input
+| 11
+| PSBT_IN_SHA256
+| BIP 174
+|-
+| Input
+| 12
+| PSBT_IN_HASH160
+| BIP 174
+|-
+| Input
+| 13
+| PSBT_IN_HASH256
+| BIP 174
+|-
+| Input
| 252
| PSBT_IN_PROPRIETARY
| BIP 174
diff --git a/bip-0322.mediawiki b/bip-0322.mediawiki
index 95991e6..e515b56 100644
--- a/bip-0322.mediawiki
+++ b/bip-0322.mediawiki
@@ -13,119 +13,99 @@
== Abstract ==
-A standard for interoperable generic signed messages based on the Bitcoin Script format.
-
-== Background ==
-
-* Assume two actors, a prover <code>P</code> and a verifier <code>V</code>.
-* <code>P</code> wants to prove that they own the private key <code>k</code> associated with a given address <code>A</code> (which in turn is derived from the pubkey <code>kG</code>).
-* Let <code>V</code> generate a message <code>M</code> and hand this to <code>P</code>.
-* <code>P</code> generates a signature <code>S</code> by signing the message <code>M</code> using <code>k</code>. Given <code>S</code>, <code>V</code> can prove that <code>P</code> has the private key associated with <code>A</code>.
-
-The astute reader will notice that the above is missing a critical part, namely the pubkey <code>kG</code>, without which the verifier cannot actually verify the message. The current message signing standard solves this via a cryptographic trick, wherein the signature <code>S</code> above is a special "recoverable signature" type. Given the message <code>M</code> and the signature <code>S</code>, it is then possible to recover the pubkey <code>kG</code>. The system thus derives the address for the pubkey <code>kG</code>, and if it does not match <code>A</code>, the proof is deemed invalid.
-
-While this is a neat trick, it unnecessarily restricts and complicates the message signing mechanism; for instance, it is currently not possible to sign a message for a P2SH address, because there is no pubkey to recover from the resulting signature.
+A standard for interoperable signed messages based on the Bitcoin Script format, either for proving fund availability, or committing to a message as the intended recipient of funds sent to the invoice address.
== Motivation ==
-The current message signing standard only works for P2PKH (1...) addresses. By extending it to use a Bitcoin Script based approach, it could be made more generic without causing a too big burden on implementers, who most likely have access to Bitcoin Script interpreters already.
-
-== Specification ==
+The current message signing standard only works for P2PKH (1...) invoice addresses. We propose to extend and generalize the standard by using a Bitcoin Script based approach. This approach minimizes the burden for implementers as message signing can be expected to be part of a library or project that includes Bitcoin Script interpreters already.
-A new structure <code>SignatureProof</code> is added, which is a simple serializable scriptSig & witness container.
+Additionally, the current message signing only proves that the message has been committed to by the recipient of a given invoice address.
+It does not prove anything about the invoice address itself, nor that the signer has access to the private keys used to implement this invoice.
+More importantly, it does not prove ownership nor access to any funds, even if the same private key would be a valid signer for spending them - and this is a commonly desired use case.
-=== SignatureProof container ===
+== Specification ==
-{|class="wikitable" style="text-align: center;"
-|-
-!Type
-!Length
-!Name
-!Comment
-|-
-|VarInt||1-8||scriptsiglen||Number of bytes in scriptSig data
-|-
-|Uint8*||[scriptsiglen]||scriptsig||ScriptSig data
-|-
-|VarInt||1-8||witlen||Number of entries in witness stack
-|-
-|Uint8[]*||[witlen]||wit||Witness stack, as [witlen] uint8* vectors, each one prepended with a varint of its size
-|}
+This BIP follows the specification of BIP-325 challenges and solutions (see Signet comparison below).
-In some cases, the scriptsig or wit may be empty. If both are empty, the proof is incomplete.
+Let there be two virtual transactions to_spend and to_sign.
-=== Result Codes ===
+The "to_spend" transaction is:
-A verification call will return a result code according to the table below.
+ nVersion = 0
+ nLockTime = 0
+ vin[0].prevout.hash = 0000...000
+ vin[0].prevout.n = 0xFFFFFFFF
+ vin[0].nSequence = 0
+ vin[0].scriptSig = OP_0 PUSH32[ message_hash ]
+ vin[0].scriptWitness = []
+ vout[0].nValue = 0
+ vout[0].scriptPubKey = message_challenge
-{|class="wikitable" style="text-align: center;"
-|-
-!Code
-!Description
-|-
-|INCOMPLETE||Empty proof.
-|-
-|INCONCLUSIVE||The given proof was consensus-valid but policy-invalid.
-|-
-|VALID||The proof was valid.
-|-
-|INVALID||The proof was invalid
-|-
-|ERROR||An error was encountered
-|}
+where message_hash is a BIP340-tagged hash of the message, i.e. sha256_tag(m), where tag = "BIP0322-signed-message", and message_challenge is the to be proven (public) key script.
+For proving funds, message_challenge shall be simply OP_TRUE.
-== Signing and Verifying ==
+The "to_sign" transaction is:
-If the challenge consists of an address is in the P2PKH (legacy) format, sign using the legacy format (further information below). Otherwise continue as stated below.
+ nVersion = 0 or as appropriate (e.g. 2, for time locks)
+ nLockTime = 0 or as appropriate (for time locks)
+ vin[0].prevout.hash = to_spend.txid
+ vin[0].prevout.n = 0
+ vin[0].nSequence = 0 or as appropriate (for time locks)
+ vin[0].scriptWitness = message_signature
+ vout[0].nValue = 0
+ vout[0].scriptPubKey = OP_RETURN
-For both cases, generate a sighash based on the given scriptPubKey and message as follows:
+When a proof of funds is being created, additional inputs should be included for virtually spending transaction outputs of desired value.
-# Define the message pre-image as the sequence "Bitcoin Signed Message:\n" concatenated with the message, encoded in UTF-8 using Normalization Form Compatibility Decomposition (NFKD)
-# Let sighash = sha256(sha256(scriptPubKey || pre-image))
+* All signatures must use the SIGHASH_ALL flag.
+* The proof is considered valid, inconclusive, or invalid based on whether the to_sign transaction is a valid spend of the to_spend transaction or not, according to the rules specified in the "Consensus and standard flags" section below.
+* Proofs of funds may be encumbered with the in_future flag, according to the rules specified in the "Locktime and Sequence" section below, in which case we refer to the result in text form as "valid_in_future", "inconclusive_in_future", etc.
-A private key may be used directly to sign a message. In this case, its P2WPKH bech32 address shall be derived, and used as the input.
+Proofs of funds are the base64-encoding of the to_spend and to_sign transactions concatenated in standard network serialisation, and proofs without additional inputs or time locks (simple proofs) are the base64-encoding of the to_sign script witness.
-=== Signing ===
+A validator must verify it is valid and meets the description of virtual transactions as specified above. See "Validation" below.
-The signature is generated as follows:
+=== Validation ===
-# Derive the private key privkey for the scriptPubKey; FAIL if not VALID
-# Generate and return a signature sig with privkey=privkey, sighash=sighash
-
-=== Verifying ===
+To validate a simple proof, the following steps must be taken:
-Verify a proof, given a standard flags value, a script sig, an optional witness, and a derived sighash as described above.
+# construct the to_spend and to_sign transactions, based on the specification above
+# check the signature using consensus rules, then upgradable rules
-While omitted below, ERROR is returned if an unforeseen error occurs at any point in the process. A concrete example of this is if a legacy proof is given as input to a non-legacy address; the deserialization of the proof will fail in this case, and this should result in an ERROR result.
+To validate a proof of funds, the following steps must be taken:
-# Verify Script with flags=consensus flags (currently P2SH, DERSIG, NULLDUMMY, CLTV, CSV, WITNESS), scriptSig=script sig, scriptPubKey=scriptPubKey, witness=witness, and sighash=sighash
-# Return INVALID if verification fails
-# Verify Script with flags=standard flags (above plus STRICTENC, MINIMALDATA, etc.), scriptSig=script sig, scriptPubKey=scriptPubKey, witness=witness, and sighash=sighash
-# Return VALID if verification succeeds, otherwise return INCONCLUSIVE
+# deserialize the to_spend and to_sign transactions from the proof, and fail if the proof contains extraneous bytes
+# verify that the to_sign transaction uses all inputs covered by the proof of funds, exactly once
+# reconstruct the to_spend' and to_sign' transactions, based on the specification above, copying the version, lock time, and sequence values
+# verify that to_spend = to_spend', that to_sign has at least 1 input, has exactly 1 output, and that to_sign.vin[0] = to_sign'.vin[0]
+# set the "in_future" flag if the transaction's lock time is in the future according to consensus rules
+# establish a "coins map", a mapping of outpoints (hash, vout) to coins (scriptPubKey, amount), initialized to coins_map(to_spend.txid, 0) = (to_spend.vout[0], 0)
+# for each proof of fund input, set the corresponding values in the coins map; abort if the input cannot be found
+# check the signature of each input using consensus rules, then upgradable rules
== Legacy format ==
-The legacy format is restricted to the legacy P2PKH address format.
+New proofs should use the new format for all invoice address formats, including P2PKH.
-Any other input (i.e. non-P2PKH address format) must be signed using the new format described above.
+The legacy format MAY be used, but must be restricted to the legacy P2PKH invoice address format.
=== Signing ===
-Given the P2PKH address <code>a</code> and the message <code>m</code>, and the pubkey-hash function <code>pkh(P) = ripemd160(sha256(P))</code>:
+Given the P2PKH invoice address <code>a</code> and the message <code>m</code>, and the pubkey-hash function <code>pkh(P) = ripemd160(sha256(P))</code>:
# let <code>p</code> be the pubkey-hash <code>pkh(P)</code> for the pubkey <code>P</code>, contained in <code>a</code>
# let <code>x</code> be the private key associated with <code>P</code> so that <code>pkh(xG) = p</code>
-# let <code>digest</code> be <code>SHA56d("Bitcoin Signed Message:\n"||m)</code>
+# let <code>digest</code> be <code>SHA56d(0x18||"Bitcoin Signed Message:\n"||compactint(len(m))||m)</code>
# create a compact signature <code>sig</code> (aka "recoverable ECDSA signature") using <code>x</code> on <code>digest</code>
The resulting proof is <code>sig</code>, serialized using the base64 encoding.
=== Verifying ===
-Given the P2PKH address <code>a</code>, the message <code>m</code>, the compact signature <code>sig</code>, and the pubkey-hash function <code>pkh(P) = ripemd160(sha256(P))</code>:
+Given the P2PKH invoice address <code>a</code>, the message <code>m</code>, the compact signature <code>sig</code>, and the pubkey-hash function <code>pkh(P) = ripemd160(sha256(P))</code>:
# let <code>p</code> be the pubkey-hash <code>pkh(P)</code> for the pubkey <code>P</code>, contained in <code>a</code>
-# let <code>digest</code> be <code>SHA56d("Bitcoin Signed Message:\n"||m)</code>
+# let <code>digest</code> be <code>SHA56d(0x18||"Bitcoin Signed Message:\n"||compactint(len(m))||m)</code>
# attempt pubkey recovery for <code>digest</code> using the signature <code>sig</code> and store the resulting pubkey into <code>Q</code>
## fail verification if pubkey recovery above fails
# let <code>q</code> be the pubkey-hash <code>pkh(Q)</code> for the pubkey <code>Q</code>
@@ -137,7 +117,7 @@ This specification is backwards compatible with the legacy signmessage/verifymes
== Reference implementation ==
-# Pull request to Bitcoin Core: https://github.com/bitcoin/bitcoin/pull/16440
+TODO
== Acknowledgements ==
@@ -153,9 +133,9 @@ This document is licensed under the Creative Commons CC0 1.0 Universal license.
== Consensus and standard flags ==
-Each flag is associated with some type of enforced rule (most often a soft fork). There are two sets of flags: consensus flags (which result in a block being rejected, if violated), and policy flags (which result in a transaction being accepted only if it is contained within an actual block, and rejected otherwise, if violated). The policy flags are a super-set of the consensus flags.
+Each flag is associated with some type of enforced rule (most often a soft fork). There are two sets of flags: consensus flags (which result in a block being rejected, if violated), and upgradable flags (which are typically policy-rejected by nodes specifically for the purpose of future network upgrades). The upgradable flags are a super-set of the consensus flags.
-BIP322 specifies that a proof that validates for both rulesets is valid, a proof that validates for consensus rules, but not for policy rules, is "inconclusive", and a proof that does not validate for consensus rules is "invalid" (regardless of policy rule validation).
+This BIP specifies that a proof that validates for both rulesets is valid, a proof that validates for consensus rules, but not for upgradable rules, is "inconclusive", and a proof that does not validate for consensus rules is "invalid" (regardless of upgradable rule validation).
The ruleset sometimes changes. This BIP does not intend to be complete, nor does it indicate enforcement of rules, it simply lists the rules as they stand at the point of writing.
@@ -168,7 +148,7 @@ The ruleset sometimes changes. This BIP does not intend to be complete, nor does
* CHECKSEQUENCEVERIFY: enable CHECKSEQUENCEVERIFY ([https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki BIP112])
* WITNESS: enable WITNESS ([https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141])
-=== Policy rules ===
+=== Upgradable rules ===
All of the above, plus (subject to change):
@@ -185,62 +165,4 @@ All of the above, plus (subject to change):
== Test vectors ==
-(TODO: update test vectors, which are based on previous iteration where signature proofs contained additional data)
-
-== Native segwit test vector ==
-
-<pre>
-address = bcrt1qe7nte4zk4ayly5tc53dtdjupgkz0lr8azx3rzz
-scriptpubkey = 0014cfa6bcd456af49f25178a45ab6cb814584ff8cfd
-message = hello
-preimage = 0014cfa6bcd456af49f25178a45ab6cb814584ff8cfd426974636f696e205369
- 676e6564204d6573736167653a0a68656c6c6f
- (scriptpubkey || "Bitcoin Signed Message:\nhello")
-sighash = 790eef86c204f0bff969ff822121317aa34eff0215dbd30ccf031e7b2f3f0cc1
- (sha256d(preimage), displayed in big-endian)
-</pre>
-
-The proof becomes:
-
-<pre>
-HEX: 01000000010002473044022075b4fb40421d55c55462879cb352a85eeb3af2138d3f0290
- 2c9143f12870f5f70220119c2995c1661138142f3899c1fd6d1af7e790e0e081be72db9c
- e7bf5b5b932901210290beccd02b73eca57467b2b6f1e47161a9b76a5e67586e7c1dee9e
- a6e2dcd869
-
-Base64: AQAAAAEAAkcwRAIgdbT7QEIdVcVUYoecs1KoXus68hONPwKQLJFD8Shw9fcCIBGcKZXBZhE4
- FC84mcH9bRr355Dg4IG+ctuc579bW5MpASECkL7M0Ctz7KV0Z7K28eRxYam3al5nWG58He6e
- puLc2Gk=
-</pre>
-
-Split into components:
-
-{|class="wikitable" style="text-align: center;"
-|-
-!Type
-!Length
-!Name
-!Value
-!Comment
-|-
-|Uint32||4||flags||<code>01000000</code>||proof format version
-|-
-|Uint8||1||entries||<code>01</code>||1 entry
-|-
-|VarInt||1-8||scriptsiglen||<code>00</code>||0 byte scriptsig
-|-
-|VarInt||1-8||wit entries||<code>02</code>||2 witness stack entries
-|-
-|VarInt||1-8||entry1len||<code>47</code>||71 byte entry
-|-
-|Uint8[71]||71||entry1||<code>3044022075b4fb40421d55c55462879cb352a85eeb3af213
-8d3f02902c9143f12870f5f70220119c2995c1661138142f
-3899c1fd6d1af7e790e0e081be72db9ce7bf5b5b932901</code>||Witness stack item 1
-|-
-|VarInt||1-8||entry2len||<code>21</code>||33 byte entry
-|-
-|Uint8[33]||33||entry2||<code>0290beccd02b73eca57467b2b6f1e47161a9b76a5e67586e
-7c1dee9ea6e2dcd869</code>||Witness stack item 2
-|}
-
-The above test vector is for a bech32 P2WPKH (native segwit) address. (Once BIP solidifies, will add test vector for other types.)
+TODO
diff --git a/bip-0325.mediawiki b/bip-0325.mediawiki
index 4b45030..5a9f3f1 100644
--- a/bip-0325.mediawiki
+++ b/bip-0325.mediawiki
@@ -3,9 +3,10 @@
Layer: Applications
Title: Signet
Author: Karl-Johan Alm <karljohan-alm@garage.co.jp>
+ Anthony Towns <aj@erisian.com.au>
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0325
- Status: Draft
+ Status: Proposed
Type: Standards Track
Created: 2019-03-20
License: CC0-1.0
@@ -21,19 +22,20 @@ Testnet is a great place to try out new things without risking real money, but i
A new type of test network would be more suitable for integration testing by organizations such as exchanges, or testing of next generation Layer-2 protocols like Eltoo or sidechain pegs. The goal is not to be perfectly reliable but rather to have a predictable amount of unreliability. You want a test network to behave like mainnet (i.e. no thousands of block reorgs) while also making it easier to trigger expected but rare events like a 6-block reorg. Regtest is not suitable for longer-term scenarios involving multiple independent parties because creating blocks costs nothing, so any party can completely control the test network.
-
== Specification ==
A new type of network ("signet"), which takes an additional consensus parameter called the challenge (scriptPubKey). The challenge can be a simple pubkey (P2PKH style), or a k-of-n multisig, or any other script you would want.
-The witness commitment of the coinbase transaction is extended to include a secondary commitment (the signature/solution) of either:
+Signet requires all blocks to have a BIP 141 commitment in the coinbase transaction. In order to provide a non-empty solution to the block challenge the block's BIP 141 commitment's optional data must include an additional commitment of the signature/solution for the block:
1-5 bytes - Push the following (4 + x + y) bytes
4 bytes - Signet header (0xecc7daa2)
x bytes - scriptSig
y bytes - scriptWitness
-The scriptSig is serialized by first encoding its length as CompactSize. If the scriptWitness is empty, it is encoded as 0 bytes, otherwise it is encoded in the usual way (see BIP 141 "witness" encoding).
+In the special case where an empty solution is valid (ie scriptSig and scriptWitness are both empty) this additional commitment can optionally be left out. This special case is to allow non-signet-aware block generation code to be used to test a custom signet chain where the challenge is trivially true.
+
+The scriptSig is serialized by first encoding its length as CompactSize. The scriptWitness stack is serialized as described in BIP 141.
Any push operations that do not start with the 4 byte Signet header are ignored. Multiple push operations with the 4 byte Signet header are ignored except for the first instance of the header.
@@ -60,8 +62,10 @@ The "to_sign" transaction is:
vin[0].prevout.hash = to_spend.txid
vin[0].prevout.n = 0
vin[0].nSequence = 0
+ vin[0].sigScript = [ signet_solution sigScript (x bytes), if any ]
+ vin[0].scriptWitness = [ signet_solution scriptWitness (y bytes), if any ]
vout[0].nValue = 0
- vout[0].scriptPubKey = signet_challenge
+ vout[0].scriptPubKey = OP_RETURN
The scriptSig and/or scriptWitness for <code>vin[0]</code> are filled in from the Signet header push above.
@@ -77,11 +81,12 @@ The genesis block is the same for all signet networks, whereas the message start
=== Genesis Block ===
-* Time stamp: 1534313275
-* Nonce: 100123
-* Difficulty: 1e2adc28
+* Time stamp: 1598918400
+* Nonce: 52613770
+* Difficulty: 0x1e0377ae
+* Version: 1
-The resulting genesis block hash is 0000032d7f67af9ec7b7152aea0fe7c95b9804ff973265e252f245e0ae61799d, and the block hex is 0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a3bc3735b28dc2a1e1b8701000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000.
+The resulting genesis block hash is 00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6, and the block hex is 0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a008f4d5fae77031e8ad222030101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000.
=== Message Start ===
diff --git a/bip-0340.mediawiki b/bip-0340.mediawiki
index 9502a69..f22194f 100644
--- a/bip-0340.mediawiki
+++ b/bip-0340.mediawiki
@@ -110,7 +110,7 @@ The following conventions are used, with constants as defined for [https://www.s
** The function ''bytes(x)'', where ''x'' is an integer, returns the 32-byte encoding of ''x'', most significant byte first.
** The function ''bytes(P)'', where ''P'' is a point, returns ''bytes(x(P))''.
** The function ''int(x)'', where ''x'' is a 32-byte array, returns the 256-bit unsigned integer whose most significant byte first encoding is ''x''.
-** The function ''has_even_y(P)'', where ''P'' is a point, returns ''y(P) mod 2 = 0''.
+** The function ''has_even_y(P)'', where ''P'' is a point for which ''not is_infinite(P)'', returns ''y(P) mod 2 = 0''.
** The function ''lift_x(x)'', where ''x'' is an integer in range ''0..p-1'', returns the point ''P'' for which ''x(P) = x''<ref>
Given a candidate X coordinate ''x'' in the range ''0..p-1'', there exist either exactly two or exactly zero valid Y coordinates. If no valid Y coordinate exists, then ''x'' is not a valid X coordinate either, i.e., no point ''P'' exists for which ''x(P) = x''. The valid Y coordinates for a given candidate ''x'' are the square roots of ''c = x<sup>3</sup> + 7 mod p'' and they can be computed as ''y = &plusmn;c<sup>(p+1)/4</sup> mod p'' (see [https://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus Quadratic residue]) if they exist, which can be checked by squaring and comparing with ''c''.</ref> and ''has_even_y(P)'', or fails if no such point exists. The function ''lift_x(x)'' is equivalent to the following pseudocode:
*** Let ''c = x<sup>3</sup> + 7 mod p''.
@@ -184,7 +184,9 @@ The algorithm ''Verify(pk, m, sig)'' is defined as:
* Let ''s = int(sig[32:64])''; fail if ''s &ge; n''.
* Let ''e = int(hash<sub>BIP0340/challenge</sub>(bytes(r) || bytes(P) || m)) mod n''.
* Let ''R = s⋅G - e⋅P''.
-* Fail if ''not has_even_y(R)'' or ''x(R) &ne; r''.
+* Fail if ''is_infinite(R)''.
+* Fail if ''not has_even_y(R)''.
+* Fail if ''x(R) &ne; r''.
* Return success iff no failure occurred before reaching this point.
For every valid secret key ''sk'' and message ''m'', ''Verify(PubKey(sk),m,Sign(sk,m))'' will succeed.
diff --git a/bip-0340/reference.py b/bip-0340/reference.py
index 5d17db5..5b38c0a 100644
--- a/bip-0340/reference.py
+++ b/bip-0340/reference.py
@@ -26,13 +26,15 @@ def tagged_hash(tag: str, msg: bytes) -> bytes:
tag_hash = hashlib.sha256(tag.encode()).digest()
return hashlib.sha256(tag_hash + tag_hash + msg).digest()
-def is_infinity(P: Optional[Point]) -> bool:
+def is_infinite(P: Optional[Point]) -> bool:
return P is None
def x(P: Point) -> int:
+ assert not is_infinite(P)
return P[0]
def y(P: Point) -> int:
+ assert not is_infinite(P)
return P[1]
def point_add(P1: Optional[Point], P2: Optional[Point]) -> Optional[Point]:
@@ -83,6 +85,7 @@ def hash_sha256(b: bytes) -> bytes:
return hashlib.sha256(b).digest()
def has_even_y(P: Point) -> bool:
+ assert not is_infinite(P)
return y(P) % 2 == 0
def pubkey_gen(seckey: bytes) -> bytes:
diff --git a/bip-0340/test-vectors.py b/bip-0340/test-vectors.py
index e5b8847..d1bf6b2 100644
--- a/bip-0340/test-vectors.py
+++ b/bip-0340/test-vectors.py
@@ -6,7 +6,7 @@ def is_square(x):
def has_square_y(P):
"""Determine if P has a square Y coordinate. Used in an earlier draft of BIP340."""
- assert not is_infinity(P)
+ assert not is_infinite(P)
return is_square(P[1])
def vector0():
diff --git a/bip-0341.mediawiki b/bip-0341.mediawiki
index 7ac5bf8..0f8d32a 100644
--- a/bip-0341.mediawiki
+++ b/bip-0341.mediawiki
@@ -193,7 +193,7 @@ def taproot_tweak_seckey(seckey0, h):
</source>
The following function, <code>taproot_output_script</code>, returns a byte array with the scriptPubKey (see [[bip-0141.mediawiki|BIP141]]).
-<code>ser_script</code> refers to a function that prefixes its input with a CCompactSize-encoded length.
+<code>ser_script</code> refers to a function that prefixes its input with a CompactSize-encoded length.
<source lang="python">
def taproot_tree_helper(script_tree):
diff --git a/bip-0342.mediawiki b/bip-0342.mediawiki
index 3cf87a3..7e00a2e 100644
--- a/bip-0342.mediawiki
+++ b/bip-0342.mediawiki
@@ -125,7 +125,7 @@ In summary, the semantics of signature validation is identical to BIP340, except
In addition to changing the semantics of a number of opcodes, there are also some changes to the resource limitations:
* '''Script size limit''' The maximum script size of 10000 bytes does not apply. Their size is only implicitly bounded by the block weight limit.<ref>'''Why is a limit on script size no longer needed?''' Since there is no <code>scriptCode</code> directly included in the signature hash (only indirectly through a precomputable tapleaf hash), the CPU time spent on a signature check is no longer proportional to the size of the script being executed.</ref>
* '''Non-push opcodes limit''' The maximum non-push opcodes limit of 201 per script does not apply.<ref>'''Why is a limit on the number of opcodes no longer needed?''' An opcode limit only helps to the extent that it can prevent data structures from growing unboundedly during execution (both because of memory usage, and because of time that may grow in proportion to the size of those structures). The size of stack and altstack is already independently limited. By using O(1) logic for <code>OP_IF</code>, <code>OP_NOTIF</code>, <code>OP_ELSE</code>, and <code>OP_ENDIF</code> as suggested [https://bitslog.com/2017/04/17/new-quadratic-delays-in-bitcoin-scripts/ here] and implemented [https://github.com/bitcoin/bitcoin/pull/16902 here], the only other instance can be avoided as well.</ref>
-* '''Sigops limit''' The sigops in tapscripts do not count towards the block-wide limit of 80000 (weighted). Instead, there is a per-script sigops ''budget''. The budget equals 50 + the total serialized size in bytes of the transaction input's witness (including the <code>CCompactSize</code> prefix). Executing a signature opcode (<code>OP_CHECKSIG</code>, <code>OP_CHECKSIGVERIFY</code>, or <code>OP_CHECKSIGADD</code>) with a non-empty signature decrements the budget by 50. If that brings the budget below zero, the script fails immediately. Signature opcodes with unknown public key type and non-empty signature are also counted.<ref>'''The tapscript sigop limit''' The signature opcode limit protects against scripts which are slow to verify due to excessively many signature operations. In tapscript the number of signature opcodes does not count towards the BIP141 or legacy sigop limit. The old sigop limit makes transaction selection in block construction unnecessarily difficult because it is a second constraint in addition to weight. Instead, the number of tapscript signature opcodes is limited by witness weight. Additionally, the limit applies to the transaction input instead of the block and only actually executed signature opcodes are counted. Tapscript execution allows one signature opcode per 50 witness weight units plus one free signature opcode.</ref><ref>'''Parameter choice of the sigop limit''' Regular witnesses are unaffected by the limit as their weight is composed of public key and (<code>SIGHASH_ALL</code>) signature pairs with ''33 + 65'' weight units each (which includes a 1 weight unit <code>CCompactSize</code> tag). This is also the case if public keys are reused in the script because a signature's weight alone is 65 or 66 weight units. However, the limit increases the fees of abnormal scripts with duplicate signatures (and public keys) by requiring additional weight. The weight per sigop factor 50 corresponds to the ratio of BIP141 block limits: 4 mega weight units divided by 80,000 sigops. The "free" signature opcode permitted by the limit exists to account for the weight of the non-witness parts of the transaction input.</ref><ref>'''Why are only signature opcodes counted toward the budget, and not for example hashing opcodes or other expensive operations?''' It turns out that the CPU cost per witness byte for verification of a script consisting of the maximum density of signature checking opcodes (taking the 50 WU/sigop limit into account) is already very close to that of scripts packed with other opcodes, including hashing opcodes (taking the 520 byte stack element limit into account) and <code>OP_ROLL</code> (taking the 1000 stack element limit into account). That said, the construction is very flexible, and allows adding new signature opcodes like <code>CHECKSIGFROMSTACK</code> to count towards the limit through a soft fork. Even if in the future new opcodes are introduced which change normal script cost there is no need to stuff the witness with meaningless data. Instead, the taproot annex can be used to add weight to the witness without increasing the actual witness size.</ref>.
+* '''Sigops limit''' The sigops in tapscripts do not count towards the block-wide limit of 80000 (weighted). Instead, there is a per-script sigops ''budget''. The budget equals 50 + the total serialized size in bytes of the transaction input's witness (including the <code>CompactSize</code> prefix). Executing a signature opcode (<code>OP_CHECKSIG</code>, <code>OP_CHECKSIGVERIFY</code>, or <code>OP_CHECKSIGADD</code>) with a non-empty signature decrements the budget by 50. If that brings the budget below zero, the script fails immediately. Signature opcodes with unknown public key type and non-empty signature are also counted.<ref>'''The tapscript sigop limit''' The signature opcode limit protects against scripts which are slow to verify due to excessively many signature operations. In tapscript the number of signature opcodes does not count towards the BIP141 or legacy sigop limit. The old sigop limit makes transaction selection in block construction unnecessarily difficult because it is a second constraint in addition to weight. Instead, the number of tapscript signature opcodes is limited by witness weight. Additionally, the limit applies to the transaction input instead of the block and only actually executed signature opcodes are counted. Tapscript execution allows one signature opcode per 50 witness weight units plus one free signature opcode.</ref><ref>'''Parameter choice of the sigop limit''' Regular witnesses are unaffected by the limit as their weight is composed of public key and (<code>SIGHASH_ALL</code>) signature pairs with ''33 + 65'' weight units each (which includes a 1 weight unit <code>CompactSize</code> tag). This is also the case if public keys are reused in the script because a signature's weight alone is 65 or 66 weight units. However, the limit increases the fees of abnormal scripts with duplicate signatures (and public keys) by requiring additional weight. The weight per sigop factor 50 corresponds to the ratio of BIP141 block limits: 4 mega weight units divided by 80,000 sigops. The "free" signature opcode permitted by the limit exists to account for the weight of the non-witness parts of the transaction input.</ref><ref>'''Why are only signature opcodes counted toward the budget, and not for example hashing opcodes or other expensive operations?''' It turns out that the CPU cost per witness byte for verification of a script consisting of the maximum density of signature checking opcodes (taking the 50 WU/sigop limit into account) is already very close to that of scripts packed with other opcodes, including hashing opcodes (taking the 520 byte stack element limit into account) and <code>OP_ROLL</code> (taking the 1000 stack element limit into account). That said, the construction is very flexible, and allows adding new signature opcodes like <code>CHECKSIGFROMSTACK</code> to count towards the limit through a soft fork. Even if in the future new opcodes are introduced which change normal script cost there is no need to stuff the witness with meaningless data. Instead, the taproot annex can be used to add weight to the witness without increasing the actual witness size.</ref>.
* '''Stack + altstack element count limit''' The existing limit of 1000 elements in the stack and altstack together after every executed opcode remains. It is extended to also apply to the size of initial stack.
* '''Stack element size limit''' The existing limit of maximum 520 bytes per stack element remains, both in the initial stack and in push opcodes.