mirror of
https://github.com/bitcoinbook/bitcoinbook
synced 2024-11-29 19:38:25 +00:00
[Move only] Move content from CH06 & CH07 to new A&A chapter
A&A = Authorization & Authentication
This commit is contained in:
parent
de5367d5ab
commit
b2df51488b
321
ch06.asciidoc
321
ch06.asciidoc
@ -197,326 +197,6 @@ because Eugenia is spending more money, but because her transaction is
|
|||||||
more complex and larger in size--the fee is independent of the
|
more complex and larger in size--the fee is independent of the
|
||||||
transaction's bitcoin value.((("", startref="Tout06")))
|
transaction's bitcoin value.((("", startref="Tout06")))
|
||||||
|
|
||||||
[[tx_script]]
|
|
||||||
[role="pagebreak-before less_space_h1"]
|
|
||||||
=== Transaction Scripts and Script Language
|
|
||||||
|
|
||||||
((("transactions", "scripts and Script language",
|
|
||||||
id="Tsript06")))((("scripting", "transactions and",
|
|
||||||
id="Stransact06")))The bitcoin transaction script language, called
|
|
||||||
_Script_, is a Forth-like reverse-polish notation stack-based execution
|
|
||||||
language. If that sounds like gibberish, you probably haven't studied
|
|
||||||
1960s programming languages, but that's ok—we will explain it all
|
|
||||||
in this chapter. Both the locking script placed on an UTXO and the
|
|
||||||
unlocking script are written in this scripting language. When a
|
|
||||||
transaction is validated, the unlocking script in each input is executed
|
|
||||||
alongside the corresponding locking script to see if it satisfies the
|
|
||||||
spending condition.
|
|
||||||
|
|
||||||
Script is a very simple language that was designed to be limited in
|
|
||||||
scope and executable on a range of hardware, perhaps as simple as an
|
|
||||||
embedded device. It requires minimal processing and cannot do many of
|
|
||||||
the fancy things modern programming languages can do. For its use in
|
|
||||||
validating programmable money, this is a deliberate security feature.
|
|
||||||
|
|
||||||
((("Pay-to-Public-Key-Hash (P2PKH)")))Today, most transactions processed
|
|
||||||
through the Bitcoin network have the form "Payment to Bob's Bitcoin
|
|
||||||
address" and are based on a script called a Pay-to-Public-Key-Hash
|
|
||||||
script. However, bitcoin transactions are not limited to the "Payment
|
|
||||||
to Bob's Bitcoin address" script. In fact, locking scripts can be
|
|
||||||
written to express a vast variety of complex conditions. In order to
|
|
||||||
understand these more complex scripts, we must first understand the
|
|
||||||
basics of transaction scripts and script language.
|
|
||||||
|
|
||||||
In this section, we will demonstrate the basic components of the bitcoin
|
|
||||||
transaction scripting language and show how it can be used to express
|
|
||||||
simple conditions for spending and how those conditions can be satisfied
|
|
||||||
by unlocking scripts.
|
|
||||||
|
|
||||||
[TIP]
|
|
||||||
====
|
|
||||||
((("programmable money")))Bitcoin transaction validation is not based on
|
|
||||||
a static pattern, but instead is achieved through the execution of a
|
|
||||||
scripting language. This language allows for a nearly infinite variety
|
|
||||||
of conditions to be expressed. This is how bitcoin gets the power of
|
|
||||||
"programmable money."
|
|
||||||
====
|
|
||||||
|
|
||||||
==== Turing Incompleteness
|
|
||||||
|
|
||||||
((("Turing incompleteness")))The bitcoin transaction script language
|
|
||||||
contains many operators, but is deliberately limited in one important
|
|
||||||
way--there are no loops or complex flow control capabilities other than
|
|
||||||
conditional flow control. This ensures that the language is not _Turing
|
|
||||||
Complete_, meaning that scripts have limited complexity and predictable
|
|
||||||
execution times. Script is not a general-purpose language.
|
|
||||||
((("denial-of-service attacks")))((("denial-of-service attacks",
|
|
||||||
see="also security")))((("security", "denial-of-service attacks")))These
|
|
||||||
limitations ensure that the language cannot be used to create an
|
|
||||||
infinite loop or other form of "logic bomb" that could be embedded in a
|
|
||||||
transaction in a way that causes a denial-of-service attack against the
|
|
||||||
Bitcoin network. Remember, every transaction is validated by every full
|
|
||||||
node on the Bitcoin network. A limited language prevents the transaction
|
|
||||||
validation mechanism from being used as a vulnerability.
|
|
||||||
|
|
||||||
==== Stateless Verification
|
|
||||||
|
|
||||||
((("stateless verification")))The bitcoin transaction script language is
|
|
||||||
stateless, in that there is no state prior to execution of the script,
|
|
||||||
or state saved after execution of the script. Therefore, all the
|
|
||||||
information needed to execute a script is contained within the script. A
|
|
||||||
script will predictably execute the same way on any system. If your
|
|
||||||
system verifies a script, you can be sure that every other system in the
|
|
||||||
Bitcoin network will also verify the script, meaning that a valid
|
|
||||||
transaction is valid for everyone and everyone knows this. This
|
|
||||||
predictability of outcomes is an essential benefit of the Bitcoin
|
|
||||||
system.
|
|
||||||
|
|
||||||
[[tx_lock_unlock]]
|
|
||||||
==== Script Construction (Lock + Unlock)
|
|
||||||
|
|
||||||
Bitcoin's transaction validation engine relies on two types of scripts
|
|
||||||
to validate transactions: a locking script and an unlocking script.
|
|
||||||
|
|
||||||
((("locking scripts")))((("unlocking scripts")))((("scripting", "locking
|
|
||||||
scripts")))A locking script is a spending condition placed on an output:
|
|
||||||
it specifies the conditions that must be met to spend the output in the
|
|
||||||
future. ((("scriptPubKey")))Historically, the locking script was called
|
|
||||||
a _scriptPubKey_, because it usually contained a public key or Bitcoin
|
|
||||||
address (public key hash). In this book we refer to it as a "locking
|
|
||||||
script" to acknowledge the much broader range of possibilities of this
|
|
||||||
scripting technology. In most bitcoin applications, what we refer to as
|
|
||||||
a locking script will appear in the source code as +scriptPubKey+.
|
|
||||||
((("witnesses")))((("cryptographic puzzles")))You will also see the
|
|
||||||
locking script referred to as a _witness script_ (see <<segwit>>) or
|
|
||||||
more generally as a _cryptographic puzzle_. These terms all mean the
|
|
||||||
same thing, at different levels of abstraction.
|
|
||||||
|
|
||||||
An unlocking script is a script that "solves," or satisfies, the
|
|
||||||
conditions placed on an output by a locking script and allows the output
|
|
||||||
to be spent. Unlocking scripts are part of every transaction input. Most
|
|
||||||
of the time they contain a digital signature produced by the user's
|
|
||||||
wallet from his or her private key. ((("scriptSig")))Historically, the
|
|
||||||
unlocking script was called _scriptSig_, because it usually contained a
|
|
||||||
digital signature. In most bitcoin applications, the source code refers
|
|
||||||
to the unlocking script as +scriptSig+. You will also see the unlocking
|
|
||||||
script referred to as a _witness_ (see <<segwit>>). In this book, we
|
|
||||||
refer to it as an "unlocking script" to acknowledge the much broader
|
|
||||||
range of locking script requirements, because not all unlocking scripts
|
|
||||||
must contain signatures.
|
|
||||||
|
|
||||||
Every bitcoin validating node will validate transactions by executing
|
|
||||||
the locking and unlocking scripts together. Each input contains an
|
|
||||||
unlocking script and refers to a previously existing UTXO. The
|
|
||||||
validation software will copy the unlocking script, retrieve the UTXO
|
|
||||||
referenced by the input, and copy the locking script from that UTXO. The
|
|
||||||
unlocking and locking script are then executed in sequence. The input is
|
|
||||||
valid if the unlocking script satisfies the locking script conditions
|
|
||||||
(see <<script_exec>>). All the inputs are validated independently, as
|
|
||||||
part of the overall validation of the transaction.
|
|
||||||
|
|
||||||
Note that the UTXO is permanently recorded in the blockchain, and
|
|
||||||
therefore is invariable and is unaffected by failed attempts to spend it
|
|
||||||
by reference in a new transaction. Only a valid transaction that
|
|
||||||
correctly satisfies the conditions of the output results in the output
|
|
||||||
being considered as "spent" and removed from the set of unspent
|
|
||||||
transaction outputs (UTXO set).
|
|
||||||
|
|
||||||
<<scriptSig_and_scriptPubKey>> is an example of the unlocking and
|
|
||||||
locking scripts for the most common type of bitcoin transaction (a
|
|
||||||
payment to a public key hash), showing the combined script resulting
|
|
||||||
from the concatenation of the unlocking and locking scripts prior to
|
|
||||||
script validation.
|
|
||||||
|
|
||||||
[[scriptSig_and_scriptPubKey]]
|
|
||||||
.Combining scriptSig and scriptPubKey to evaluate a transaction script
|
|
||||||
image::images/mbc2_0603.png["scriptSig_and_scriptPubKey"]
|
|
||||||
|
|
||||||
===== The script execution stack
|
|
||||||
|
|
||||||
Bitcoin's scripting language is called a stack-based language because it
|
|
||||||
uses a data structure called a _stack_. A stack is a very simple data
|
|
||||||
structure that can be visualized as a stack of cards. A stack allows two
|
|
||||||
operations: push and pop. Push adds an item on top of the stack. Pop
|
|
||||||
removes the top item from the stack. Operations on a stack can only act
|
|
||||||
on the topmost item on the stack. A stack data structure is also called
|
|
||||||
a Last-In-First-Out, or "LIFO" queue.
|
|
||||||
|
|
||||||
The scripting language executes the script by processing each item from
|
|
||||||
left to right. Numbers (data constants) are pushed onto the stack.
|
|
||||||
Operators push or pop one or more parameters from the stack, act on
|
|
||||||
them, and might push a result onto the stack. For example, +OP_ADD+ will
|
|
||||||
pop two items from the stack, add them, and push the resulting sum onto
|
|
||||||
the stack.
|
|
||||||
|
|
||||||
Conditional operators evaluate a condition, producing a boolean result
|
|
||||||
of TRUE or FALSE. For example, +OP_EQUAL+ pops two items from the stack
|
|
||||||
and pushes TRUE (TRUE is represented by the number 1) if they are equal
|
|
||||||
or FALSE (represented by zero) if they are not equal. Bitcoin
|
|
||||||
transaction scripts usually contain a conditional operator, so that they
|
|
||||||
can produce the TRUE result that signifies a valid transaction.
|
|
||||||
|
|
||||||
===== A simple script
|
|
||||||
|
|
||||||
Now let's apply what we've learned about scripts and stacks to some simple examples.
|
|
||||||
|
|
||||||
In <<simplemath_script>>, the script +2 3 OP_ADD 5 OP_EQUAL+
|
|
||||||
demonstrates the arithmetic addition operator +OP_ADD+, adding two
|
|
||||||
numbers and putting the result on the stack, followed by the conditional
|
|
||||||
operator +OP_EQUAL+, which checks that the resulting sum is equal to
|
|
||||||
+5+. For brevity, the +OP_+ prefix is omitted in the step-by-step
|
|
||||||
example. For more details on the available script operators and
|
|
||||||
functions, see <<tx_script_ops>>.
|
|
||||||
|
|
||||||
Although most locking scripts refer to a public key hash (essentially, a
|
|
||||||
Bitcoin address), thereby requiring proof of ownership to spend the
|
|
||||||
funds, the script does not have to be that complex. Any combination of
|
|
||||||
locking and unlocking scripts that results in a TRUE value is valid. The
|
|
||||||
simple arithmetic we used as an example of the scripting language is
|
|
||||||
also a valid locking script that can be used to lock a transaction
|
|
||||||
output.
|
|
||||||
|
|
||||||
Use part of the arithmetic example script as the locking script:
|
|
||||||
|
|
||||||
----
|
|
||||||
3 OP_ADD 5 OP_EQUAL
|
|
||||||
----
|
|
||||||
|
|
||||||
which can be satisfied by a transaction containing an input with the
|
|
||||||
unlocking script:
|
|
||||||
|
|
||||||
----
|
|
||||||
2
|
|
||||||
----
|
|
||||||
|
|
||||||
The validation software combines the locking and unlocking scripts and
|
|
||||||
the resulting script is:
|
|
||||||
|
|
||||||
----
|
|
||||||
2 3 OP_ADD 5 OP_EQUAL
|
|
||||||
----
|
|
||||||
|
|
||||||
As we saw in the step-by-step example in <<simplemath_script>>, when
|
|
||||||
this script is executed, the result is +OP_TRUE+, making the transaction
|
|
||||||
valid. Not only is this a valid transaction output locking script, but
|
|
||||||
the resulting UTXO could be spent by anyone with the arithmetic skills
|
|
||||||
to know that the number 2 satisfies the script.
|
|
||||||
|
|
||||||
[TIP]
|
|
||||||
====
|
|
||||||
((("transactions", "valid and invalid")))Transactions are valid if the
|
|
||||||
top result on the stack is +TRUE+ (noted as ++{0x01}++), any
|
|
||||||
other nonzero value, or if the stack is empty after script execution.
|
|
||||||
Transactions are invalid if the top value on the stack is +FALSE+ (a
|
|
||||||
zero-length empty value, noted as ++{}++) or if script
|
|
||||||
execution is halted explicitly by an operator, such as +OP_VERIFY+,
|
|
||||||
+OP_RETURN+, or a conditional terminator such as +OP_ENDIF+. See
|
|
||||||
<<tx_script_ops>> for details.
|
|
||||||
====
|
|
||||||
|
|
||||||
[[simplemath_script]]
|
|
||||||
.Bitcoin's script validation doing simple math
|
|
||||||
image::images/mbc2_0604.png["TxScriptSimpleMathExample"]
|
|
||||||
|
|
||||||
[role="pagebreak-before"]
|
|
||||||
The following is a slightly more complex script, which calculates ++2 +
|
|
||||||
7 -- 3 + 1++. Notice that when the script contains several operators in
|
|
||||||
a row, the stack allows the results of one operator to be acted upon by
|
|
||||||
the next operator:
|
|
||||||
|
|
||||||
----
|
|
||||||
2 7 OP_ADD 3 OP_SUB 1 OP_ADD 7 OP_EQUAL
|
|
||||||
----
|
|
||||||
|
|
||||||
Try validating the preceding script yourself using pencil and paper.
|
|
||||||
When the script execution ends, you should be left with the value +TRUE+
|
|
||||||
on the stack.
|
|
||||||
|
|
||||||
[[script_exec]]
|
|
||||||
===== Separate execution of unlocking and locking scripts
|
|
||||||
|
|
||||||
((("security", "locking and unlocking scripts")))In the original Bitcoin
|
|
||||||
client, the unlocking and locking scripts were concatenated and executed
|
|
||||||
in sequence. For security reasons, this was changed in 2010, because of
|
|
||||||
a vulnerability that allowed a malformed unlocking script to push data
|
|
||||||
onto the stack and corrupt the locking script. In the current
|
|
||||||
implementation, the scripts are executed separately with the stack
|
|
||||||
transferred between the two executions, as described next.
|
|
||||||
|
|
||||||
First, the unlocking script is executed, using the stack execution
|
|
||||||
engine. If the unlocking script is executed without errors (e.g., it has
|
|
||||||
no "dangling" operators left over), the main stack is copied and the
|
|
||||||
locking script is executed. If the result of executing the locking
|
|
||||||
script with the stack data copied from the unlocking script is "TRUE,"
|
|
||||||
the unlocking script has succeeded in resolving the conditions imposed
|
|
||||||
by the locking script and, therefore, the input is a valid authorization
|
|
||||||
to spend the UTXO. If any result other than "TRUE" remains after
|
|
||||||
execution of the combined script, the input is invalid because it has
|
|
||||||
failed to satisfy the spending conditions placed on the UTXO.
|
|
||||||
|
|
||||||
|
|
||||||
[[p2pkh]]
|
|
||||||
==== Pay-to-Public-Key-Hash (P2PKH)
|
|
||||||
|
|
||||||
((("Pay-to-Public-Key-Hash (P2PKH)")))The vast majority of transactions
|
|
||||||
processed on the Bitcoin network spend outputs locked with a
|
|
||||||
Pay-to-Public-Key-Hash or "P2PKH" script. These outputs contain a
|
|
||||||
locking script that locks the output to a public key hash, more commonly
|
|
||||||
known as a Bitcoin address. An output locked by a P2PKH script can be
|
|
||||||
unlocked (spent) by presenting a public key and a digital signature
|
|
||||||
created by the corresponding private key (see <<digital_sigs>>).
|
|
||||||
|
|
||||||
((("use cases", "buying coffee")))For example, let's look at Alice's
|
|
||||||
payment to Bob's Cafe again. Alice made a payment of 0.015 bitcoin to
|
|
||||||
the cafe's Bitcoin address. That transaction output would have a locking
|
|
||||||
script of the form:
|
|
||||||
|
|
||||||
----
|
|
||||||
OP_DUP OP_HASH160 <Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG
|
|
||||||
----
|
|
||||||
|
|
||||||
The +Cafe Public Key Hash+ is equivalent to the Bitcoin address of the
|
|
||||||
cafe, without the Base58Check encoding. Most applications would show the
|
|
||||||
_public key hash_ in hexadecimal encoding and not the familiar Bitcoin
|
|
||||||
address Base58Check format that begins with a "1."
|
|
||||||
|
|
||||||
The preceding locking script can be satisfied with an unlocking script
|
|
||||||
of the form:
|
|
||||||
|
|
||||||
----
|
|
||||||
<Cafe Signature> <Cafe Public Key>
|
|
||||||
----
|
|
||||||
|
|
||||||
The two scripts together would form the following combined validation
|
|
||||||
script:
|
|
||||||
|
|
||||||
----
|
|
||||||
<Cafe Signature> <Cafe Public Key> OP_DUP OP_HASH160
|
|
||||||
<Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG
|
|
||||||
----
|
|
||||||
|
|
||||||
When executed, this combined script will evaluate to TRUE if, and only
|
|
||||||
if, the unlocking script matches the conditions set by the locking
|
|
||||||
script. In other words, the result will be TRUE if the unlocking script
|
|
||||||
has a valid signature from the cafe's private key that corresponds to
|
|
||||||
the public key hash set as an encumbrance.
|
|
||||||
|
|
||||||
Figures pass:[<a data-type="xref" href="#P2PubKHash1"
|
|
||||||
data-xrefstyle="select: labelnumber">#P2PubKHash1</a>] and pass:[<a
|
|
||||||
data-type="xref" href="#P2PubKHash2" data-xrefstyle="select:
|
|
||||||
labelnumber">#P2PubKHash2</a>] show (in two parts) a step-by-step
|
|
||||||
execution of the combined script, which will prove this is a valid
|
|
||||||
transaction.((("", startref="Tsript06")))((("",
|
|
||||||
startref="Stransact06")))
|
|
||||||
|
|
||||||
[[P2PubKHash1]]
|
|
||||||
.Evaluating a script for a P2PKH transaction (part 1 of 2)
|
|
||||||
image::images/mbc2_0605.png["Tx_Script_P2PubKeyHash_1"]
|
|
||||||
|
|
||||||
[[P2PubKHash2]]
|
|
||||||
.Evaluating a script for a P2PKH transaction (part 2 of 2)
|
|
||||||
image::images/mbc2_0606.png["Tx_Script_P2PubKeyHash_2"]
|
|
||||||
|
|
||||||
[[digital_sigs]]
|
[[digital_sigs]]
|
||||||
=== Digital Signatures (ECDSA)
|
=== Digital Signatures (ECDSA)
|
||||||
|
|
||||||
@ -892,4 +572,3 @@ If you are implementing an algorithm to sign transactions in bitcoin,
|
|||||||
you _must_ use RFC 6979 or a similarly deterministic-random algorithm to
|
you _must_ use RFC 6979 or a similarly deterministic-random algorithm to
|
||||||
ensure you generate a different _k_ for each transaction.((("",
|
ensure you generate a different _k_ for each transaction.((("",
|
||||||
startref="Tdigsig06")))
|
startref="Tdigsig06")))
|
||||||
|
|
||||||
|
1404
ch07.asciidoc
1404
ch07.asciidoc
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user