1
0
mirror of https://github.com/bitcoinbook/bitcoinbook synced 2024-11-12 10:58:55 +00:00
bitcoinbook/chapters/signatures.adoc

425 lines
19 KiB
Plaintext
Raw Normal View History

[[c_signatures]]
2023-03-05 20:37:16 +00:00
=== Signatures
FIXME
[[digital_sigs]]
=== Digital Signatures (ECDSA)
2023-03-05 20:37:16 +00:00
[[sighashes]]
=== Signature Hashes (Sighashes)
((("transactions", "digital signatures and", id="Tdigsig06")))So far, we
have not delved into any detail about "digital signatures." In this
section we look at how digital signatures work and how they can present
proof of ownership of a private key without revealing that private key.
2023-03-05 20:37:16 +00:00
FIXME
((("digital signatures", "algorithm used")))((("Elliptic Curve Digital
Signature Algorithm (ECDSA)")))The digital signature algorithm used in
bitcoin is the _Elliptic Curve Digital Signature Algorithm_, or _ECDSA_.
ECDSA is the algorithm used for digital signatures based on elliptic
curve private/public key pairs, as described in <<elliptic_curve>>.
ECDSA is used by the script functions +OP_CHECKSIG+,
+OP_CHECKSIGVERIFY+, +OP_CHECKMULTISIG+, and +OP_CHECKMULTISIGVERIFY+.
Any time you see those in a locking script, the unlocking script must
contain an ECDSA signature.
((("digital signatures", "purposes of")))A digital signature serves
three purposes in bitcoin (see the following sidebar). First, the
signature proves that the owner of the private key, who is by
implication the owner of the funds, has _authorized_ the spending of
those funds. Secondly, the proof of authorization is _undeniable_
(nonrepudiation). Thirdly, the signature proves that the transaction (or
specific parts of the transaction) have not and _cannot be modified_ by
anyone after it has been signed.
Note that each transaction input is signed independently. This is
critical, as neither the signatures nor the inputs have to belong to or
be applied by the same "owners." In fact, a specific transaction scheme
called "CoinJoin" uses this fact to create multi-party transactions for
privacy.
[NOTE]
====
Each transaction input and any signature it may contain is _completely_
independent of any other input or signature. Multiple parties can
collaborate to construct transactions and sign only one input each.
====
[[digital_signature_definition]]
.Wikipedia's Definition of a "Digital Signature"
****
((("digital signatures", "defined")))A digital signature is a
mathematical scheme for demonstrating the authenticity of a digital
message or documents. A valid digital signature gives a recipient reason
to believe that the message was created by a known sender
(authentication), that the sender cannot deny having sent the message
(nonrepudiation), and that the message was not altered in transit
(integrity).
_Source: https://en.wikipedia.org/wiki/Digital_signature_
****
==== How Digital Signatures Work
((("digital signatures", "how they work")))A digital signature is a
_mathematical scheme_ that consists of two parts. The first part is an
algorithm for creating a signature, using a private key (the signing
key), from a message (the transaction). The second part is an algorithm
that allows anyone to verify the signature, given also the message and a
public key.
===== Creating a digital signature
In bitcoin's implementation of the ECDSA algorithm, the "message" being
signed is the transaction, or more accurately a hash of a specific
subset of the data in the transaction (see <<sighash_types>>). The
signing key is the user's private key. The result is the signature:
latexmath:[\(Sig = F_{sig}(F_{hash}(m), dA)\)]
where:
* _dA_ is the signing private key
* _m_ is the transaction (or parts of it)
* _F_~_hash_~ is the hashing function
* _F_~_sig_~ is the signing algorithm
* _Sig_ is the resulting signature
More details on the mathematics of ECDSA can be found in <<ecdsa_math>>.
The function _F_~_sig_~ produces a signature +Sig+ that is composed of
two values, commonly referred to as +R+ and +S+:
----
Sig = (R, S)
----
((("Distinguished Encoding Rules (DER)")))Now that the two values +R+
and +S+ have been calculated, they are serialized into a byte-stream
using an international standard encoding scheme called the
_Distinguished Encoding Rules_, or _DER_.
[[seralization_of_signatures_der]]
===== Serialization of signatures (DER)
Let's look at the transaction Alice ((("use cases", "buying coffee",
id="alicesixtwo")))created again. In the transaction input there is an
unlocking script that contains the following DER-encoded signature from
Alice's wallet:
----
3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e381301
----
That signature is a serialized byte-stream of the +R+ and +S+ values
produced by Alice's wallet to prove she owns the private key authorized
to spend that output. The serialization format consists of nine elements
as follows:
* +0x30+&#x2014;indicating the start of a DER sequence
* +0x45+&#x2014;the length of the sequence (69 bytes)
* +0x02+&#x2014;an integer value follows
* +0x21+&#x2014;the length of the integer (33 bytes)
* +R+&#x2014;++00884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb++
* +0x02+&#x2014;another integer follows
* +0x20+&#x2014;the length of the integer (32 bytes)
* +S+&#x2014;++4b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813++
* A suffix (+0x01+) indicating the type of hash used (+SIGHASH_ALL+)
See if you can decode Alice's serialized (DER-encoded) signature using
this list. The important numbers are +R+ and +S+; the rest of the data
is part of the DER encoding scheme.
==== Verifying the Signature
((("digital signatures", "verifying")))To verify the signature, one must
have the signature (+R+ and +S+), the serialized transaction, and the
public key (that corresponds to the private key used to create the
signature). Essentially, verification of a signature means "Only the
owner of the private key that generated this public key could have
produced this signature on this transaction."
The signature verification algorithm takes the message (a hash of the
transaction or parts of it), the signer's public key and the signature
(+R+ and +S+ values), and returns TRUE if the signature is valid for
this message and public key.
[[sighash_types]]
==== Signature Hash Types (SIGHASH)
((("digital signatures", "signature hash
types")))((("commitment")))Digital signatures are applied to messages,
which in the case of bitcoin, are the transactions themselves. The
signature implies a _commitment_ by the signer to specific transaction
data. In the simplest form, the signature applies to the entire
transaction, thereby committing all the inputs, outputs, and other
transaction fields. However, a signature can commit to only a subset of
the data in a transaction, which is useful for a number of scenarios as
we will see in this section.
((("SIGHASH flags")))Bitcoin signatures have a way of indicating which
part of a transaction's data is included in the hash signed by the
private key using a +SIGHASH+ flag. The +SIGHASH+ flag is a single byte
that is appended to the signature. Every signature has a +SIGHASH+ flag
and the flag can be different from input to input. A transaction with
three signed inputs may have three signatures with different +SIGHASH+
flags, each signature signing (committing) different parts of the
transaction.
Remember, each input may contain a signature in its unlocking script. As
a result, a transaction that contains several inputs may have signatures
with different +SIGHASH+ flags that commit different parts of the
transaction in each of the inputs. Note also that bitcoin transactions
may contain inputs from different "owners," who may sign only one input
in a partially constructed (and invalid) transaction, collaborating with
others to gather all the necessary signatures to make a valid
transaction. Many of the +SIGHASH+ flag types only make sense if you
think of multiple participants collaborating outside the Bitcoin network
and updating a partially signed transaction.
[role="pagebreak-before"]
There are three +SIGHASH+ flags: +ALL+, +NONE+, and +SINGLE+, as shown
in <<sighash_types_and_their>>.
[[sighash_types_and_their]]
.SIGHASH types and their meanings
[options="header"]
|=======================
|+SIGHASH+ flag| Value | Description
| +ALL+ | 0x01 | Signature applies to all inputs and outputs
| +NONE+ | 0x02 | Signature applies to all inputs, none of the outputs
| +SINGLE+ | 0x03 | Signature applies to all inputs but only the one output with the same index number as the signed input
|=======================
In addition, there is a modifier flag +SIGHASH_ANYONECANPAY+, which can
be combined with each of the preceding flags. When +ANYONECANPAY+ is
set, only one input is signed, leaving the rest (and their sequence
numbers) open for modification. The +ANYONECANPAY+ has the value +0x80+
and is applied by bitwise OR, resulting in the combined flags as shown
in <<sighash_types_with_modifiers>>.
[[sighash_types_with_modifiers]]
.SIGHASH types with modifiers and their meanings
[options="header"]
|=======================
|SIGHASH flag| Value | Description
| ALL\|ANYONECANPAY | 0x81 | Signature applies to one input and all outputs
| NONE\|ANYONECANPAY | 0x82 | Signature applies to one input, none of the outputs
| SINGLE\|ANYONECANPAY | 0x83 | Signature applies to one input and the output with the same index number
|=======================
The way +SIGHASH+ flags are applied during signing and verification is
that a copy of the transaction is made and certain fields within are
truncated (set to zero length and emptied). The resulting transaction is
serialized. The +SIGHASH+ flag is added to the end of the serialized
transaction and the result is hashed. The hash itself is the "message"
that is signed. Depending on which +SIGHASH+ flag is used, different
parts of the transaction are truncated. The resulting hash depends on
different subsets of the data in the transaction. By including the
+SIGHASH+ as the last step before hashing, the signature commits the
+SIGHASH+ type as well, so it can't be changed (e.g., by a miner).
[NOTE]
====
All +SIGHASH+ types sign the transaction +nLocktime+ field (see
<<nlocktime>>). In addition, the +SIGHASH+ type
itself is appended to the transaction before it is signed, so that it
can't be modified once signed.
====
In the example of Alice's transaction (see the list in
<<seralization_of_signatures_der>>), we saw that the last part of the
DER-encoded signature was +01+, which is the +SIGHASH_ALL+ flag. This
locks the transaction data, so Alice's signature is committing the state
of all inputs and outputs. This is the most common signature form.
Let's look at some of the other +SIGHASH+ types and how they can be used
in practice:
+ALL|ANYONECANPAY+ :: ((("charitable donations")))((("use cases",
"charitable donations")))This construction can be used to make a
"crowdfunding&#x201d;-style transaction. Someone attempting to raise
funds can construct a transaction with a single output. The single
output pays the "goal" amount to the fundraiser. Such a transaction is
obviously not valid, as it has no inputs. However, others can now amend
it by adding an input of their own, as a donation. They sign their own
input with +ALL|ANYONECANPAY+. Unless enough inputs are gathered to
reach the value of the output, the transaction is invalid. Each donation
is a "pledge," which cannot be collected by the fundraiser until the
entire goal amount is raised.
+NONE+ :: This construction can be used to create a "bearer check" or
"blank check" of a specific amount. It commits to the input, but allows
the output locking script to be changed. Anyone can write their own
Bitcoin address into the output locking script and redeem the
transaction. However, the output value itself is locked by the
signature.
+NONE|ANYONECANPAY+ :: This construction can be used to build a "dust
collector." Users who have tiny UTXO in their wallets can't spend these
without the cost in fees exceeding the value of the dust. With this type
of signature, the dust UTXO can be donated for anyone to aggregate and
spend whenever they want.
((("Bitmask Sighash Modes")))There are some proposals to modify or
expand the +SIGHASH+ system. One such proposal is _Bitmask Sighash
Modes_ by Blockstream's Glenn Willen, as part of the Elements project.
This aims to create a flexible replacement for +SIGHASH+ types that
allows "arbitrary, miner-rewritable bitmasks of inputs and outputs" that
can express "more complex contractual precommitment schemes, such as
signed offers with change in a distributed asset exchange."
[NOTE]
====
You will not see +SIGHASH+ flags presented as an option in a user's
wallet application. With few exceptions, wallets construct P2PKH scripts
and sign with +SIGHASH_ALL+ flags. To use a different +SIGHASH+ flag,
you would have to write software to construct and sign transactions.
More importantly, +SIGHASH+ flags can be used by special-purpose bitcoin
applications that enable novel uses.
====
[[ecdsa_math]]
==== ECDSA Math
((("Elliptic Curve Digital Signature Algorithm (ECDSA)")))As mentioned
previously, signatures are created by a mathematical function _F_~_sig_~
that produces a signature composed of two values _R_ and _S_. In this
section we look at the function _F_~_sig_~ in more detail.
((("public and private keys", "key pairs", "ephemeral")))The signature
algorithm first generates an _ephemeral_ (temporary) private public key
pair. This temporary key pair is used in the calculation of the _R_ and
_S_ values, after a transformation involving the signing private key and
the transaction hash.
The temporary key pair is based on a random number _k_, which is used as
the temporary private key. From _k_, we generate the corresponding
temporary public key _P_ (calculated as _P = k*G_, in the same way
bitcoin public keys are derived; see <<public_key_derivation>>). The _R_ value of the
digital signature is then the x coordinate of the ephemeral public key
_P_.
From there, the algorithm calculates the _S_ value of the signature,
such that:
_S_ = __k__^-1^ (__Hash__(__m__) + __dA__ * __R__) _mod p_
where:
* _k_ is the ephemeral private key
* _R_ is the x coordinate of the ephemeral public key
* _dA_ is the signing private key
* _m_ is the transaction data
* _p_ is the prime order of the elliptic curve
Verification is the inverse of the signature generation function, using
the _R_, _S_ values and the public key to calculate a value _P_, which
is a point on the elliptic curve (the ephemeral public key used in
signature creation):
_P_ = __S__^-1^ * __Hash__(__m__) * _G_ + __S__^-1^ * _R_ * _Qa_
where:
- _R_ and _S_ are the signature values
- _Qa_ is Alice's public key
- _m_ is the transaction data that was signed
- _G_ is the elliptic curve generator point
If the x coordinate of the calculated point _P_ is equal to _R_, then
the verifier can conclude that the signature is valid.
Note that in verifying the signature, the private key is neither known
nor revealed.
[TIP]
====
ECDSA is necessarily a fairly complicated piece of math; a full
explanation is beyond the scope of this book. A number of great guides
online take you through it step by step: search for "ECDSA explained" or
try this one: http://bit.ly/2r0HhGB[].
====
==== The Importance of Randomness in Signatures
((("digital signatures", "randomness in")))As we saw in <<ecdsa_math>>,
the signature generation algorithm uses a random key _k_, as the basis
for an ephemeral private/public key pair. The value of _k_ is not
important, _as long as it is random_. If the same value _k_ is used to
produce two signatures on different messages (transactions), then the
signing _private key_ can be calculated by anyone. Reuse of the same
value for _k_ in a signature algorithm leads to exposure of the private
key!
[WARNING]
====
((("warnings and cautions", "digital signatures")))If the same value _k_
is used in the signing algorithm on two different transactions, the
private key can be calculated and exposed to the world!
====
This is not just a theoretical possibility. We have seen this issue lead
to exposure of private keys in a few different implementations of
transaction-signing algorithms in bitcoin. People have had funds stolen
because of inadvertent reuse of a _k_ value. The most common reason for
reuse of a _k_ value is an improperly initialized random-number
generator.
((("random numbers", "random number generation")))((("entropy", "random
number generation")))((("deterministic initialization")))To avoid this
vulnerability, the industry best practice is to not generate _k_ with a
random-number generator seeded with entropy, but instead to use a
deterministic-random process seeded with the transaction data itself.
This ensures that each transaction produces a different _k_. The
industry-standard algorithm for deterministic initialization of _k_ is
defined in https://tools.ietf.org/html/rfc6979[RFC 6979], published by
the Internet Engineering Task Force.
If you are implementing an algorithm to sign transactions in bitcoin,
you _must_ use RFC 6979 or a similarly deterministic-random algorithm to
ensure you generate a different _k_ for each transaction.((("",
startref="Tdigsig06")))
==== Segregated Witness' New Signing Algorithm
Segregated Witness modifies the semantics of the four signature
verification functions (+CHECKSIG+, +CHECKSIGVERIFY+, +CHECKMULTISIG+,
and +CHECKMULTISIGVERIFY+), changing the way a transaction commitment
hash is calculated.
Signatures in bitcoin transactions are applied on a _commitment hash_,
which is calculated from the transaction data, locking specific parts of
the data indicating the signer's commitment to those values. For
example, in a simple +SIGHASH_ALL+ type signature, the commitment hash
includes all inputs and outputs.
Unfortunately, the way the commitment hash was calculated introduced the
possibility that a node verifying the signature can be forced to perform
a significant number of hash computations. Specifically, the hash
operations increase in O(n^2^) with respect to the number of signature
operations in the transaction. An attacker could therefore create a
transaction with a very large number of signature operations, causing
the entire Bitcoin network to have to perform hundreds or thousands of
hash operations to verify the transaction.
Segwit represented an opportunity to address this problem by changing
the way the commitment hash is calculated. For segwit version 0 witness
programs, signature verification occurs using an improved commitment
hash algorithm as specified in BIP-143.
The new algorithm achieves two important goals. Firstly, the number of
hash operations increases by a much more gradual O(n) to the number of
signature operations, reducing the opportunity to create
denial-of-service attacks with overly complex transactions. Secondly,
the commitment hash now also includes the value (amounts) of each input
as part of the commitment. This means that a signer can commit to a
specific input value without needing to "fetch" and check the previous
transaction referenced by the input. In the case of offline devices,
such as hardware wallets, this greatly simplifies the communication
between the host and the hardware wallet, removing the need to stream
previous transactions for validation. A hardware wallet can accept the
input value "as stated" by an untrusted host. Since the signature is
invalid if that input value is not correct, the hardware wallet doesn't
need to validate the value before signing the input.