mirror of
https://github.com/bitcoinbook/bitcoinbook
synced 2024-12-23 07:08:13 +00:00
CH07: Add MAST, P2C, scriptless multisignature, taproot, tapscript
This commit is contained in:
parent
fe575bb33e
commit
1a27ee296e
@ -1311,7 +1311,7 @@ using SHA256 without RIPEMD160 is that P2WSH commitments are 32 bytes
|
|||||||
For the Pay-to-Taproot (P2TR) output, the witness program is a point on
|
For the Pay-to-Taproot (P2TR) output, the witness program is a point on
|
||||||
the secp256k1 curve. It may be a simple public key, but in most cases
|
the secp256k1 curve. It may be a simple public key, but in most cases
|
||||||
it should be a public key that commits to some additional data. We'll
|
it should be a public key that commits to some additional data. We'll
|
||||||
learn more about that commitment in <<FIXME_later_chapter_about_taproot>>.
|
learn more about that commitment in <<taproot>>.
|
||||||
|
|
||||||
For the example of a future segwit version, we simply use the highest
|
For the example of a future segwit version, we simply use the highest
|
||||||
possible segwit version number (16) and the smallest allowed witness
|
possible segwit version number (16) and the smallest allowed witness
|
||||||
|
@ -114,6 +114,7 @@ possible to store private keys more securely than public keys.
|
|||||||
.Deterministic key generation: a deterministic sequence of keys derived from a seed for a wallet database
|
.Deterministic key generation: a deterministic sequence of keys derived from a seed for a wallet database
|
||||||
image::images/mbc2_0502.png["Deterministic Wallet"]
|
image::images/mbc2_0502.png["Deterministic Wallet"]
|
||||||
|
|
||||||
|
[[public_child_key_derivation]]
|
||||||
==== Public Child Key Derivation
|
==== Public Child Key Derivation
|
||||||
|
|
||||||
In <<public_key_derivation>>, we learned how to create a public key from a private key
|
In <<public_key_derivation>>, we learned how to create a public key from a private key
|
||||||
|
@ -1245,6 +1245,7 @@ account directly.
|
|||||||
Here's the redeemScript that Mohammed designs to achieve this (line
|
Here's the redeemScript that Mohammed designs to achieve this (line
|
||||||
number prefixed as XX):
|
number prefixed as XX):
|
||||||
|
|
||||||
|
[[variable_timelock_multisig]]
|
||||||
.Variable Multi-Signature with Timelock
|
.Variable Multi-Signature with Timelock
|
||||||
----
|
----
|
||||||
01 OP_IF
|
01 OP_IF
|
||||||
@ -1626,7 +1627,7 @@ Even though Alice's wallet has no support for segwit, the payment it
|
|||||||
creates can be spent by Bob with a segwit transaction.((("",
|
creates can be spent by Bob with a segwit transaction.((("",
|
||||||
startref="aliced")))
|
startref="aliced")))
|
||||||
|
|
||||||
===== Pay-to-Witness-Script-Hash inside Pay-to-Script-Hash
|
===== Nested Pay-to-Witness-Script-Hash
|
||||||
|
|
||||||
Similarly, a P2WSH witness program for a multisig script or other
|
Similarly, a P2WSH witness program for a multisig script or other
|
||||||
complicated script can be embedded inside a P2SH script and address,
|
complicated script can be embedded inside a P2SH script and address,
|
||||||
@ -1697,3 +1698,367 @@ OP_HASH160 86762607e8fe87c0c37740cddee880988b9455b2 OP_EQUAL
|
|||||||
Mohammed's company can then construct segwit transactions to spend these
|
Mohammed's company can then construct segwit transactions to spend these
|
||||||
payments, taking advantage of segwit features including lower
|
payments, taking advantage of segwit features including lower
|
||||||
transaction fees.
|
transaction fees.
|
||||||
|
|
||||||
|
=== Merklized Alternative Script Trees (MAST)
|
||||||
|
|
||||||
|
Using +OP_IF+, you can authorize multiple different spending conditions,
|
||||||
|
but this approach has several undesirable aspects:
|
||||||
|
|
||||||
|
- _Weight (cost):_ every condition you add increases the size of the
|
||||||
|
script, increasing the weight of the transaction and the amount of fee
|
||||||
|
that will need to be paid in order to spend bitcoins protected by
|
||||||
|
that script.
|
||||||
|
|
||||||
|
- _Limited size:_ even if you're willing to pay for extra conditions,
|
||||||
|
there's a limit to the maximum number you can put in a script. For
|
||||||
|
example, legacy script is limited to 10,000 bytes, practically
|
||||||
|
limiting you to a few hundred conditional branches at most. Even if
|
||||||
|
you could create a script as large as an entire block, it could still
|
||||||
|
only contain about 20,000 useful branches. That's a lot for simple
|
||||||
|
payments but tiny compared to some imagined uses of Bitcoin.
|
||||||
|
|
||||||
|
- _Lack of privacy:_ every condition you add to your script becomes
|
||||||
|
public knowledge when you spend bitcoins protected by that script.
|
||||||
|
For example, Mohammed's lawyer and business partners will be able to
|
||||||
|
see the entire script in <<variable_timelock_multisig>> whenever
|
||||||
|
anyone spends from it. That means their lawyer, even if he's not
|
||||||
|
needed for signing, will be able to track all of their transactions.
|
||||||
|
|
||||||
|
However, Bitcoin already uses a data structure known as a merkle tree
|
||||||
|
that allows verifying an element is a member of a set without
|
||||||
|
needing to identify every other member of the set.
|
||||||
|
|
||||||
|
We'll learn more about merkle trees in <<merkle_trees>>, but the
|
||||||
|
essential information is that members of the set of information we want
|
||||||
|
(e.g. authorization conditions of any length) can be passed into a hash
|
||||||
|
function to create a short commitment (called a _leaf_ of the merkle
|
||||||
|
tree). Each of those leaves is then paired with another leaf
|
||||||
|
and hashed again, creating a commitment to the leaves, called a
|
||||||
|
_branch_ commitment. A commitment to a pair of branches can be created
|
||||||
|
the same way. This step is repeated for the branches until only one
|
||||||
|
identifier remains, called the _merkle root_. Using our example script
|
||||||
|
from <<variable_timelock_multisig>>, we construct a merkle tree for each
|
||||||
|
of the three authorization conditions in <<diagram_mast1>>.
|
||||||
|
|
||||||
|
[[diagram_mast1]]
|
||||||
|
.A MAST with three sub-scripts
|
||||||
|
image::../images/mast1.dot.png["A MAST with three sub-scripts"]
|
||||||
|
|
||||||
|
We can now create a compact membership proof that proves a particular
|
||||||
|
authorization condition is a member of the merkle tree without
|
||||||
|
disclosing any details about the other members of the merkle tree. See
|
||||||
|
<<diagram_mast2>> and note that the nodes with diagonal corners can be
|
||||||
|
computed from other data provided by the user, so they don't need to be
|
||||||
|
specified at spend time.
|
||||||
|
|
||||||
|
[[diagram_mast2]]
|
||||||
|
.A MAST membership proof for one of the sub-scripts
|
||||||
|
image::../images/mast2.dot.png["A MAST membership proof for one of the sub-scripts"]
|
||||||
|
|
||||||
|
The hash digests used to create the commitments are each 32-bytes, so
|
||||||
|
proving the above spend is authorized (using a merkle tree and the
|
||||||
|
particular conditions) and authenticated (using signatures) uses 383
|
||||||
|
bytes. By comparison, the same spend without a merkle tree (i.e.
|
||||||
|
providing all possible authorization conditions) uses 412 bytes.
|
||||||
|
|
||||||
|
Saving 29 bytes (7%) in this example doesn't fully
|
||||||
|
capture the potential savings. The binary-tree nature of a merkle tree
|
||||||
|
means that you only need an additional 32-byte commitment every time
|
||||||
|
you double the number of members in the set (in this case, authorization
|
||||||
|
conditions). In this case, with three conditions, we need to use three
|
||||||
|
commitments (one of them being the merkle root, which will need to be
|
||||||
|
included in the authorization data); we could also have four
|
||||||
|
commitments for the same cost. An extra commitment would give us up to
|
||||||
|
eight conditions. With just 16 commitments--512 bytes of commitments--we could have
|
||||||
|
over 32,000 authorization conditions, far more that could be effectively
|
||||||
|
used in an entire block of +OP_IF+ statements. With 128 commitments
|
||||||
|
(4,096 bytes), the number of conditions we could create in theory far
|
||||||
|
exceeds the number of conditions that all the computers in the world
|
||||||
|
could create.
|
||||||
|
|
||||||
|
It's commonly the case that not every authorization condition is equally
|
||||||
|
as likely to be used. In the our example case, we expect Mohammed and
|
||||||
|
his partners to spend their money frequently; the time delayed
|
||||||
|
conditions only exist in case something goes wrong. We can re-structure
|
||||||
|
our tree with this knowledge in <<diagram_mast3>>.
|
||||||
|
|
||||||
|
[[diagram_mast3]]
|
||||||
|
.A MAST with the most-expected script in the best position
|
||||||
|
image::../images/mast3.dot.png["A MAST with the most-expected script in the best position"]
|
||||||
|
|
||||||
|
Now we only need to provide two commitments for the common case (saving 32
|
||||||
|
bytes), although we still need three commitments for the less common cases.
|
||||||
|
If you know (or can guess) the probabilities of
|
||||||
|
using the different authorization conditions, you can use the Huffman
|
||||||
|
algorithm to place them into a maximally-efficient tree; see BIP341 for
|
||||||
|
details.
|
||||||
|
|
||||||
|
Regardless of how the tree is constructed, we can see in the above
|
||||||
|
examples that we're only revealing the actual authorization conditions
|
||||||
|
that get used. The other conditions remain private. It even remains
|
||||||
|
private the number of conditions: a tree could have a single condition
|
||||||
|
or a trillion conditions--there's no way for someone looking only at the
|
||||||
|
onchain data for a single transaction to tell.
|
||||||
|
|
||||||
|
Except for increasing the complexity of Bitcoin slightly, there are no
|
||||||
|
significant downsides of MAST for Bitcoin and there were two solid
|
||||||
|
proposals for it, BIP114 and BIP116, before an improved approach was
|
||||||
|
discovered, which we'll see in <<taproot>>.
|
||||||
|
|
||||||
|
[[pay_to_contract]]
|
||||||
|
=== Pay to Contract (P2C)
|
||||||
|
|
||||||
|
As we saw in <<public_child_key_derivation>>, the math of Elliptic Curve
|
||||||
|
Cryptography (ECC) allows Alice to use a private key to derive a public
|
||||||
|
key that she gives to Bob. He can add an arbitrary value to that public
|
||||||
|
key create a derived public key. If he gives that arbitrary value to Alice, she can
|
||||||
|
add it to her private key to derive the private key for the derived
|
||||||
|
public key. In short, Bob can create child public keys for which only
|
||||||
|
Alice can create the corresponding private keys. This is useful for
|
||||||
|
BIP32-style Hierarchical Deterministic (HD) wallet recovery, but it can
|
||||||
|
also serve another use.
|
||||||
|
|
||||||
|
Let's imagine Bob wants to buy something from Alice but he also wants to
|
||||||
|
be able prove later what he paid for in case there's any dispute. Alice
|
||||||
|
and Bob agree on the name of the item or service being sold, e.g.
|
||||||
|
"Alice's podcast episode #123", and transform that description into a
|
||||||
|
number by hashing it and interpreting the hash digest as a number. Bob
|
||||||
|
adds that number to Alice's public key and pays it. The process is
|
||||||
|
called _key tweaking_ and the number is known as a _tweak_.
|
||||||
|
|
||||||
|
Alice can spend the funds by tweaking her private key using the same
|
||||||
|
number (tweak).
|
||||||
|
|
||||||
|
Later, Bob can prove to anyone what he paid Alice by revealing her
|
||||||
|
underlying key and the description they used. Anyone can verify that
|
||||||
|
the public key which was paid equals the underlying key plus the
|
||||||
|
hash commitment to the description. If Alice admits that key is hers,
|
||||||
|
then she received the payment. If Alice spent the funds, this further
|
||||||
|
proves she knew the description at the time she signed the spending
|
||||||
|
transaction, since she could only create a valid signature for the
|
||||||
|
tweaked public key if she knew the tweak (the description).
|
||||||
|
|
||||||
|
If neither Alice or Bob decided to publicly reveal the description they
|
||||||
|
use, the payment between them looks like any other payment. There's no
|
||||||
|
privacy loss.
|
||||||
|
|
||||||
|
Because P2C is private by default, we can't know how often it is used
|
||||||
|
for its original purpose--in theory every payment could be using it,
|
||||||
|
although we consider that unlikely. However, P2C is widely used today
|
||||||
|
in a slightly different form, which we'll see in <<taproot>>.
|
||||||
|
|
||||||
|
=== Scriptless Multisignature
|
||||||
|
|
||||||
|
In <<multisig>>, we looked at scripts which require signatures from
|
||||||
|
multiple keys. However, there's another way to require cooperation from
|
||||||
|
multiple keys, which is also confusingly called _multisignature_. To
|
||||||
|
distinguish between the two types in this section, we'll call the
|
||||||
|
version involving `OP_CHECKSIG`-style opcodes _script multisignatures_
|
||||||
|
and the other version _scriptless multisignatures_.
|
||||||
|
|
||||||
|
Scriptless multisignatures involves each participant creating their own
|
||||||
|
secret the same way they create a private key. We'll call this secret a
|
||||||
|
_partial private key_, although we should note that it's the same length
|
||||||
|
as a regular full private key. From the partial private key, each
|
||||||
|
participant derives a partial public key using the same algorithm used
|
||||||
|
for regular public keys we described in <<public_key_derivation>>. Each
|
||||||
|
participant shares their partial public keys with all the other
|
||||||
|
participants and then combines all of the keys together to create the
|
||||||
|
scriptless multisignature public key.
|
||||||
|
|
||||||
|
This combined public key looks the same as any other Bitcoin public key.
|
||||||
|
A third party can't distinguish between a multi-party public key and an
|
||||||
|
ordinary key generated by a single user.
|
||||||
|
|
||||||
|
To spend bitcoins protected by the scriptless multisignature public key,
|
||||||
|
each participant generates a partial signature. The partial signatures
|
||||||
|
are then combined to create a regular full signature. There are
|
||||||
|
many known methods for creating and combining the partial signatures;
|
||||||
|
we'll look at this topic more in <<c_signatures>>. Similar to the public
|
||||||
|
keys for scriptless multisignatures, the signatures generated by this
|
||||||
|
process look the same as any other Bitcoin signature. Third parties
|
||||||
|
can't determine whether a signature was created by a single person or a
|
||||||
|
million people cooperating with each other.
|
||||||
|
|
||||||
|
Scriptless multisignatures are smaller and more private than scripted
|
||||||
|
multisignatures. For scripted multisignatures, the number of bytes
|
||||||
|
placed in a transaction increases for every key and signature involved.
|
||||||
|
For scriptless multisignatures, the size is constant--a million
|
||||||
|
participants each providing their own partial key and partial signature
|
||||||
|
puts exactly the same amount of data in a transaction as an individual
|
||||||
|
using a single key and signature. The story is the same for privacy:
|
||||||
|
because each new key or signature adds data to a transaction, scripted
|
||||||
|
multisignatures disclose data about how many keys and signatures are
|
||||||
|
being used--which may make it easy to figure out which transactions were
|
||||||
|
created by which group of participants. But, because every scriptless
|
||||||
|
multisignatures looks identical to every other scriptless
|
||||||
|
multisignature and every single-signature, no privacy-reducing data is
|
||||||
|
leaked.
|
||||||
|
|
||||||
|
There are two downsides of scriptless multisignatures. The first is
|
||||||
|
that all known secure algorithms for creating them for Bitcoin require more
|
||||||
|
rounds of interaction or more careful management of state (or both) than
|
||||||
|
scripted multisignature. This can be challenging in cases where
|
||||||
|
signatures are being generated by nearly stateless hardware signing
|
||||||
|
devices and the keys are physically distributed. For example, if you
|
||||||
|
keep a hardware signing device in a bank safe deposit box, you would
|
||||||
|
need to visit that box once to create a scripted multisignature but
|
||||||
|
possibly two or three times for a scriptless multisignature.
|
||||||
|
|
||||||
|
The other downside is that threshold signing doesn't reveal who signed.
|
||||||
|
In scripted threshold signing, Alice, Bob, and Carol agree (for example)
|
||||||
|
that any two of them signing will be sufficient to spend the funds.
|
||||||
|
If Alice and Bob sign, this requires putting signatures from each of
|
||||||
|
them on chain, proving to anyone who knows their keys that they signed
|
||||||
|
and Carol didn't. In scriptless threshold signing, a signature from
|
||||||
|
Alice and Bob is indistinguishable from a signature between Alice and
|
||||||
|
Carol or Bob and Carol. This is beneficial for privacy, but it means
|
||||||
|
that, even if Carol claims she didn't sign, she can't
|
||||||
|
prove that she didn't, which may be bad for accountability and
|
||||||
|
auditability.
|
||||||
|
|
||||||
|
For many users and use cases, the always reduced sized and increased
|
||||||
|
privacy of multisignatures outweighs its occasional challenges for
|
||||||
|
creating and auditing signatures.
|
||||||
|
|
||||||
|
[[taproot]]
|
||||||
|
=== Taproot
|
||||||
|
|
||||||
|
One reason people choose to use Bitcoin is that it's possible to create
|
||||||
|
contracts with highly predictable outcomes. Legal contracts enforced by
|
||||||
|
a court of law depend in part on decisions by the judges and jurors
|
||||||
|
involved in the case. By contrast, Bitcoin contracts often require
|
||||||
|
actions by their participants but are otherwise enforced by thousands of
|
||||||
|
full nodes all running functionally identical code. When given the same
|
||||||
|
contract and the same input, every full node will always produce the
|
||||||
|
same result. Any deviation would mean that Bitcoin was broken.
|
||||||
|
Human judges and juries can be much more flexible than software, but
|
||||||
|
when that flexibility isn't wanted or needed, the predictability of
|
||||||
|
Bitcoin contracts is a major asset.
|
||||||
|
|
||||||
|
If all of the participants in a contract recognize that its outcome has
|
||||||
|
become completely predictable, there's not actually any need for them to
|
||||||
|
continue using the contract. They could just do whatever the contract
|
||||||
|
compels them to do and then terminate the contract. In society, this
|
||||||
|
is how most contracts terminate: if the interested parties are
|
||||||
|
satisfied, they never take the contract before a judge or jury. In
|
||||||
|
Bitcoin, it means that any contract which will use a significant amount
|
||||||
|
of block space to settle should also provide a clause that allows it to
|
||||||
|
instead be settled by mutual satisfaction.
|
||||||
|
|
||||||
|
In MAST and with scriptless multisignatures, a mutual satisfaction
|
||||||
|
clause is easy to design. We simply make one of the top leaves of the
|
||||||
|
script tree a scriptless multisignature between all interested parties.
|
||||||
|
We already saw a complex contract between several parties with a
|
||||||
|
simple mutual satisfaction clause in <<diagram_mast3>>. We could make
|
||||||
|
that more optimized by switching from scripted multisignature to
|
||||||
|
scriptless multisignature.
|
||||||
|
|
||||||
|
That's reasonably efficient and private. If the mutual satisfaction
|
||||||
|
clause is used, we only need to provide a single merkle branch and all
|
||||||
|
we reveal is that a signature was involved (it could be from one person
|
||||||
|
or it could be from thousands of different participants). But
|
||||||
|
developers in 2018 realized that we could do better if we also used
|
||||||
|
pay-to-contract.
|
||||||
|
|
||||||
|
In our previous description of pay-to-contract in <<pay_to_contract>>,
|
||||||
|
we tweaked a public key to commit to the text of an agreement between
|
||||||
|
Alice and Bob. We can instead commit to the program code of a contract
|
||||||
|
by committing to the root of a MAST. The public key we tweak
|
||||||
|
is a regular Bitcoin public key, meaning it could require a signature
|
||||||
|
from a single person or it could require a signature from multiple
|
||||||
|
people (or it could be created in a special way to make it impossible to
|
||||||
|
generate a signature for it). That means we can satisfy the contract
|
||||||
|
either with a single signature from all interested parties or by
|
||||||
|
revealing the MAST branch we want to use. That commitment tree
|
||||||
|
involving both a public key and a MAST is shown in [[diagram_taproot]].
|
||||||
|
|
||||||
|
[[diagram_taproot1]]
|
||||||
|
.A taproot with the public key committing to a merkle root
|
||||||
|
image::../images/taproot1.dot.png["A taproot with the public key committing to a merkle root"]
|
||||||
|
|
||||||
|
This makes the mutual satisfaction clause using a multisignature
|
||||||
|
extremely efficient and very private. It's even more private than it
|
||||||
|
may appear because any transaction created by a single user who wants it
|
||||||
|
to be satisfied by a single signature (or a multisignature generated by
|
||||||
|
multiple different wallets they control) looks identical onchain to a
|
||||||
|
mutual-satisfaction spend.
|
||||||
|
|
||||||
|
When spending is possible using just the key, such for a single signature
|
||||||
|
or scriptless multisignature, that is called _keypath spending_. When
|
||||||
|
the tree of scripts is used, that is called _scriptpath spending_.
|
||||||
|
For keypath spending, the data that gets put onchain is the public key
|
||||||
|
(in a witness program) and the signature (in the witness data).
|
||||||
|
|
||||||
|
For scriptpath spending, the onchain data also includes the public key,
|
||||||
|
which is placed in a witness program and called the _taproot output key_
|
||||||
|
in this context. The witness data includes the following information:
|
||||||
|
|
||||||
|
1. A version number
|
||||||
|
|
||||||
|
2. The underlying key--the key which existed before being tweaked by the
|
||||||
|
merkle root to produce the taproot output key. This underlying key
|
||||||
|
is called the _taproot internal key_
|
||||||
|
|
||||||
|
3. The script to execute
|
||||||
|
|
||||||
|
4. One 32-byte hash for each merkle branch connecting the script to the merkle root
|
||||||
|
|
||||||
|
5. Any data necessary to satisfy the script (such as signatures or hash preimages)
|
||||||
|
|
||||||
|
// Source for 33 bytes: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-February/017622.html
|
||||||
|
|
||||||
|
We're only aware of one significant described downside of taproot:
|
||||||
|
contracts whose participants want to use MAST but who don't want a
|
||||||
|
mutual satisfaction clause have to include a taproot internal key on the
|
||||||
|
blockchain, adding about 33 bytes of overhead. Given that almost
|
||||||
|
all contracts are expected to benefit from a mutual satisfaction clause,
|
||||||
|
or other multisignature clause that uses the top-level public key, and
|
||||||
|
all users benefit from the increased anonymity set of outputs looking
|
||||||
|
similar to each other, that rare overhead was not considered important
|
||||||
|
by most users who participated in taproot's activation.
|
||||||
|
|
||||||
|
Support for taproot was added to Bitcoin in a soft fork which activated
|
||||||
|
in November 2021.
|
||||||
|
|
||||||
|
=== Tapscript
|
||||||
|
|
||||||
|
Taproot enables MAST but only with a slightly different version of the
|
||||||
|
Bitcoin Script language than previously used, the new version being
|
||||||
|
called _tapscript_. The major differences include:
|
||||||
|
|
||||||
|
Scripted multisignature changes::
|
||||||
|
The old +OP_CHECKMULTSIG+ and +OP_CHECKMULTISIGVERIFY+ opcodes are
|
||||||
|
removed. Those opcodes don't combine well with one of the other
|
||||||
|
changes in the taproot soft fork, the ability to use schnorr signatures
|
||||||
|
with batch validation. A new +OP_CHECKSIGADD+ opcode is provided
|
||||||
|
instead. When it successfully verifies a signature, this new opcode
|
||||||
|
increments a counter by one, making it possible to conveniently count
|
||||||
|
how many signatures passed, which can be compared against the desired number
|
||||||
|
of successful signatures to reimplement the same behavior as
|
||||||
|
+OP_CHECKMULTISIG+.
|
||||||
|
|
||||||
|
Changes to all signatures::
|
||||||
|
All signature operations in tapscript use the schnorr signature
|
||||||
|
algorithm as defined in BIP340. We'll explore schnorr signatures more
|
||||||
|
in <<c_signatures>>.
|
||||||
|
+
|
||||||
|
Additionally, any signature-checking operation which is not expected
|
||||||
|
to succeed must be fed the value +OP_FALSE+ (also called +OP_0+)
|
||||||
|
instead of an actual signature. Providing anything else to a failed
|
||||||
|
signature-checking operation will cause the entire script to fail.
|
||||||
|
This also helps support batch validation of schnorr signatures.
|
||||||
|
|
||||||
|
OP_SUCCESSx opcodes::
|
||||||
|
Opcodes in previous versions of script which were unusable are now
|
||||||
|
redefined to be cause an entire script to succeed if they are used.
|
||||||
|
This allows future soft forks to redefine them as not succeeding, which
|
||||||
|
is a restriction and so is possible to do in a soft fork. (The
|
||||||
|
opposite, to define a not-succeeding operation as a success can only
|
||||||
|
be done in a hard fork, which is a much more challenging upgrade
|
||||||
|
path.)
|
||||||
|
|
||||||
|
Although we've looked at authorization and authentication in depth in
|
||||||
|
this chapter, we've skipped over one very important part of how Bitcoin
|
||||||
|
authenticates spenders: its signatures. We'll look at that next in
|
||||||
|
<<c_signatures>>.
|
||||||
|
21
images/mast1.dot
Normal file
21
images/mast1.dot
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
digraph merkle_tree {
|
||||||
|
splines=ortho;
|
||||||
|
node [shape=box, style="filled", color="black", fontcolor="black", fillcolor="white"];
|
||||||
|
|
||||||
|
"Merkle Root" -> "Hash AB";
|
||||||
|
"Merkle Root" -> "Hash C";
|
||||||
|
"Hash AB" -> "Hash A";
|
||||||
|
"Hash AB" -> "Hash B";
|
||||||
|
"Hash A" -> "A";
|
||||||
|
"Hash B" -> "B";
|
||||||
|
"Hash C" -> "C" [minlen = 2];
|
||||||
|
|
||||||
|
"Merkle Root" [label="Merkle Root"];
|
||||||
|
"Hash AB" [label="Hash AB"];
|
||||||
|
"Hash A" [label="Hash A"];
|
||||||
|
"Hash B" [label="Hash B"];
|
||||||
|
"Hash C" [label="Hash C"];
|
||||||
|
"A" [label="2 <M> <S> <Z> 3 OP_CHECKMULTISIG"];
|
||||||
|
"B" [label="<30 days> OP_CSV OP_DROP\n<Lawyer> OP_CHECKSIGVERIFY\n1 <M> <S> <Z> 3 OP_CHECKMULTISIG"];
|
||||||
|
"C" [label="<90 days> OP_CSV OP_DROP\n<Lawyer> OP_CHECKSIG"];
|
||||||
|
}
|
BIN
images/mast1.dot.png
Normal file
BIN
images/mast1.dot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.9 KiB |
21
images/mast2.dot
Normal file
21
images/mast2.dot
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
digraph merkle_tree {
|
||||||
|
splines=ortho;
|
||||||
|
node [shape=box, style="filled", color="black", fontcolor="black", fillcolor="white"];
|
||||||
|
|
||||||
|
"Merkle Root" -> "Hash AB";
|
||||||
|
"Merkle Root" -> "Hash C";
|
||||||
|
"Hash AB" -> "Hash A";
|
||||||
|
"Hash AB" -> "Hash B";
|
||||||
|
"Hash A" -> "A";
|
||||||
|
//"Hash B" -> "B";
|
||||||
|
//"Hash C" -> "C" [minlen = 2];
|
||||||
|
|
||||||
|
"Merkle Root" [label="Merkle Root", style = "diagonals"];
|
||||||
|
"Hash AB" [label="Hash AB", style = "diagonals" ];
|
||||||
|
"Hash A" [label="Hash A" style = "diagonals"];
|
||||||
|
"Hash B" [label="Hash B"];
|
||||||
|
"Hash C" [label="Hash C"];
|
||||||
|
"A" [label="2 <M> <S> <Z> 3 OP_CHECKMULTISIG"];
|
||||||
|
//"B" [label="<30 days> OP_CSV OP_DROP\n<Lawyer> OP_CHECKSIGVERIFY\n1 <M> <S> <Z> 3 OP_CHECKMULTISIG"];
|
||||||
|
//"C" [label="<90 days> OP_CSV OP_DROP\n<Lawyer> OP_CHECKSIG"];
|
||||||
|
}
|
BIN
images/mast2.dot.png
Normal file
BIN
images/mast2.dot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
21
images/mast3.dot
Normal file
21
images/mast3.dot
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
digraph merkle_tree {
|
||||||
|
splines=ortho;
|
||||||
|
node [shape=box, style="filled", color="black", fontcolor="black", fillcolor="white"];
|
||||||
|
|
||||||
|
"Merkle Root" -> "Hash AB";
|
||||||
|
"Merkle Root" -> "Hash C";
|
||||||
|
"Hash AB" -> "Hash A";
|
||||||
|
"Hash AB" -> "Hash B";
|
||||||
|
"Hash A" -> "A";
|
||||||
|
"Hash B" -> "B";
|
||||||
|
"Hash C" -> "C" [minlen = 2];
|
||||||
|
|
||||||
|
"Merkle Root" [label="Merkle Root"];
|
||||||
|
"Hash AB" [label="Hash AB"];
|
||||||
|
"Hash A" [label="Hash A"];
|
||||||
|
"Hash B" [label="Hash B"];
|
||||||
|
"Hash C" [label="Hash C"];
|
||||||
|
"C" [label="2 <M> <S> <Z> 3 OP_CHECKMULTISIG", style="filled", fillcolor="silver"];
|
||||||
|
"B" [label="<30 days> OP_CSV OP_DROP\n<Lawyer> OP_CHECKSIGVERIFY\n1 <M> <S> <Z> 3 OP_CHECKMULTISIG"];
|
||||||
|
"A" [label="<90 days> OP_CSV OP_DROP\n<Lawyer> OP_CHECKSIG"];
|
||||||
|
}
|
BIN
images/mast3.dot.png
Normal file
BIN
images/mast3.dot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
16
images/taproot1.dot
Normal file
16
images/taproot1.dot
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
digraph merkle_tree {
|
||||||
|
splines=ortho;
|
||||||
|
node [shape=box, style="filled", color="black", fontcolor="black", fillcolor="white"];
|
||||||
|
|
||||||
|
"Public Key" -> "Merkle Root"
|
||||||
|
"Merkle Root" -> "Hash A";
|
||||||
|
"Merkle Root" -> "Hash B";
|
||||||
|
"Hash A" -> "A";
|
||||||
|
"Hash B" -> "B";
|
||||||
|
|
||||||
|
"Merkle Root" [label="Merkle Root"];
|
||||||
|
"Hash A" [label="Hash A"];
|
||||||
|
"Hash B" [label="Hash B"];
|
||||||
|
"B" [label="Script 0"];
|
||||||
|
"A" [label="Script 1"];
|
||||||
|
}
|
BIN
images/taproot1.dot.png
Normal file
BIN
images/taproot1.dot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
Loading…
Reference in New Issue
Block a user