Skip to content

Commit d62ce10

Browse files
committed
Merge #34: Various improvements of Taproot signing example
30563ea Various improvements of Taproot signing example (Martin Habovštiak) Pull request description: The Taproot signing example had some parts that were unidiomatic, weirdly worded or just plain wrong. This change fixes some of them though not all. There's still things missing such as using `witness_mut` method on `SighashCache` and possibly things I missed because I was only looking for obvious things. ACKs for top commit: storopoli: ACK 30563ea apoelstra: ACK 30563ea Tree-SHA512: 43607b70679dfb4805954e198249f13ab94b455fde9e511e7df3c1aed9c107410797494864055fb20f07e09f54137321413081e9dfadd0f24ea60debcd46f8d8
2 parents bee4d82 + 30563ea commit d62ce10

File tree

1 file changed

+21
-26
lines changed

1 file changed

+21
-26
lines changed

cookbook/src/tx_taproot.md

+21-26
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ cargo add bitcoin --features "std, rand-std"
1111
First we'll need to import the following:
1212

1313
```rust
14-
use std::str::FromStr;
15-
1614
use bitcoin::hashes::Hash;
1715
use bitcoin::key::{Keypair, TapTweak, TweakedKeypair, UntweakedPublicKey};
1816
use bitcoin::locktime::absolute;
@@ -26,7 +24,6 @@ use bitcoin::{
2624

2725
Here is the logic behind these imports:
2826

29-
- `std::str::FromStr` is used to parse strings into Bitcoin primitives
3027
- `bitcoin::key` is used to tweak keys according to [BIP340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki)
3128
- `bitcoin::hashes::Hash` is used to hash data
3229
- `bitcoin::locktime::absolute` is used to create a locktime
@@ -68,10 +65,9 @@ Note that `senders_keys` is generic over the [`Signing`](https://docs.rs/secp256
6865
This is used to indicate that is an instance of `Secp256k1` and can be used for signing.
6966

7067
```rust
71-
# use std::str::FromStr;
7268
# use bitcoin::{Address, Network};
7369
fn receivers_address() -> Address {
74-
Address::from_str("bc1p0dq0tzg2r780hldthn5mrznmpxsxc0jux5f20fwj0z3wqxxk6fpqm7q0va")
70+
"bc1p0dq0tzg2r780hldthn5mrznmpxsxc0jux5f20fwj0z3wqxxk6fpqm7q0va".parse::<Address<_>>()
7571
.expect("a valid address")
7672
.require_network(Network::Bitcoin)
7773
.expect("valid address for mainnet")
@@ -80,11 +76,11 @@ fn receivers_address() -> Address {
8076

8177
`receivers_address` generates a receiver address.
8278
In a real application this would be the address of the receiver.
83-
We use the method `Address::from_str` to parse the string `"bc1p0dq0tzg2r780hldthn5mrznmpxsxc0jux5f20fwj0z3wqxxk6fpqm7q0va"`[^arbitrary_address] into an address.
84-
Hence, it is necessary to import the `std::str::FromStr` trait.
79+
We use the `parse` method on `&str` to parse `"bc1p0dq0tzg2r780hldthn5mrznmpxsxc0jux5f20fwj0z3wqxxk6fpqm7q0va"`[^arbitrary_address] as an address.
8580
Note that `bc1p0dq0tzg2r780hldthn5mrznmpxsxc0jux5f20fwj0z3wqxxk6fpqm7q0va` is a [Bech32](https://bitcoinops.org/en/topics/bech32/) address.
8681
This is an arbitrary, however valid, Bitcoin mainnet address.
87-
Hence we use the `require_network` method to ensure that the address is valid for mainnet.
82+
Bitcoin applications are usually configured with specific Bitcoin network at the start and use that.
83+
To prevent mistakes related to people sending satoshis to a wrong network we need to call the `require_network` method to ensure that the address is valid for the network, in our case mainnet.
8884

8985
```rust
9086
# use bitcoin::{Amount, OutPoint, ScriptBuf, TxOut, Txid};
@@ -129,14 +125,12 @@ and a value of the `const DUMMY_UTXO_AMOUNT` that we defined earlier.
129125
P2TR UTXOs could be tweaked ([`TweakedPublicKey`](https://docs.rs/bitcoin/0.32.0/bitcoin/key/struct.TweakedPublicKey.html))
130126
or untweaked ([`UntweakedPublicKey`](https://docs.rs/bitcoin/0.32.0/bitcoin/key/type.UntweakedPublicKey.html)).
131127
We are using the latter, since we are not going to tweak the key.
132-
We are using the [`OutPoint`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/transaction/struct.OutPoint.html) struct to represent the transaction output.
128+
We are using the [`OutPoint`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/transaction/struct.OutPoint.html) struct to represent the previous transaction output.
133129
Finally, we return the tuple `(out_point, utxo)`.
134130

135131
Now we are ready for our main function that will sign a transaction that spends a `p2tr` unspent output:
136132

137133
```rust
138-
# use std::str::FromStr;
139-
#
140134
# use bitcoin::hashes::Hash;
141135
# use bitcoin::key::{Keypair, TapTweak, TweakedKeypair, UntweakedPublicKey};
142136
# use bitcoin::locktime::absolute;
@@ -157,7 +151,7 @@ Now we are ready for our main function that will sign a transaction that spends
157151
# }
158152
#
159153
# fn receivers_address() -> Address {
160-
# Address::from_str("bc1p0dq0tzg2r780hldthn5mrznmpxsxc0jux5f20fwj0z3wqxxk6fpqm7q0va")
154+
# "bc1p0dq0tzg2r780hldthn5mrznmpxsxc0jux5f20fwj0z3wqxxk6fpqm7q0va".parse::<Address<_>>()
161155
# .expect("a valid address")
162156
# .require_network(Network::Bitcoin)
163157
# .expect("valid address for mainnet")
@@ -263,19 +257,19 @@ All of these are helper functions that we defined earlier.
263257
In `let input = TxIn {...}` we are instantiating the input for the transaction we are constructing
264258
Inside the [`TxIn`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/transaction/struct.TxIn.html) struct we are setting the following fields:
265259

266-
- `previous_output` is the outpoint of the dummy UTXO we are spending; it is a [`OutPoint`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/transaction/struct.OutPoint.html) type.
267-
- `script_sig` is the script code required to spend an output; it is a [`ScriptBuf`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/script/struct.ScriptBuf.html) type.
260+
- `previous_output` is the outpoint of the dummy UTXO we are spending; it has the [`OutPoint`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/transaction/struct.OutPoint.html) type.
261+
- `script_sig` is the script code required to spend an output; it has the [`ScriptBuf`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/script/struct.ScriptBuf.html) type.
268262
We are instantiating a new empty script with [`ScriptBuf::new()`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/script/struct.ScriptBuf.html#method.new).
269-
- `sequence` is the sequence number; it is a [`Sequence`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/transaction/struct.Sequence.html) type.
263+
- `sequence` is the sequence number; it has the [`Sequence`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/transaction/struct.Sequence.html) type.
270264
We are using the [`ENABLE_RBF_NO_LOCKTIME`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/transaction/struct.Sequence.html#associatedconstant.ENABLE_RBF_NO_LOCKTIME) constant.
271-
- `witness` is the witness stack; it is a [`Witness`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/witness/struct.Witness.html) type.
265+
- `witness` is the witness stack; has the [`Witness`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/witness/struct.Witness.html) type.
272266
We are using the [`default`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/witness/struct.Witness.html#impl-Default) method to create an empty witness that will be filled in later after signing.
273267
This is possible because `Witness` implements the [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) trait.
274268

275269
In `let spend = TxOut {...}` we are instantiating the spend output.
276270
Inside the [`TxOut`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/transaction/struct.TxOut.html) struct we are setting the following fields:
277271

278-
- `value` is the amount we are spending; it is a [`u64`](https://doc.rust-lang.org/std/primitive.u64.html) type.
272+
- `value` is the amount we are assigning to be spendable by given `script_pubkey`; it has the [`Amount`](https://docs.rs/bitcoin/0.32.0/bitcoin/struct.Amount.html) type.
279273
We are using the `const SPEND_AMOUNT` that we defined earlier.
280274
- `script_pubkey` is the script code required to spend a P2TR output; it is a [`ScriptBuf`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/script/struct.ScriptBuf.html) type.
281275
We are using the [`script_pubkey`](https://docs.rs/bitcoin/0.32.0/bitcoin/address/struct.Address.html#method.script_pubkey) method to generate the script pubkey from the receivers address.
@@ -289,7 +283,7 @@ which generates P2TR-type of script pubkey.
289283
In `let unsigned_tx = Transaction {...}` we are instantiating the transaction we want to sign and broadcast using the [`Transaction`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/transaction/struct.Transaction.html) struct.
290284
We set the following fields:
291285

292-
- `version` is the transaction version; it is a [`i32`](https://doc.rust-lang.org/std/primitive.u32.html) type.
286+
- `version` is the transaction version; it has the [`transaction::Version`](https://docs.rs/bitcoin/0.32.2/bitcoin/blockdata/transaction/struct.Version.html) type.
293287
We are using version `2` which means that [BIP68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki) applies.
294288
- `lock_time` is the transaction lock time;
295289
it is a [`LockTime`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/locktime/absolute/enum.LockTime.html) enum.
@@ -312,13 +306,14 @@ This is a type that efficiently calculates [signature hash message](https://deve
312306
We are using the `new` method to instantiate the struct with the `unsigned_tx` that we defined earlier.
313307
`new` takes any `Borrow<Transaction>` as an argument.
314308
[`Borrow<T>`](https://doc.rust-lang.org/std/borrow/trait.Borrow.html) is a trait that allows us to pass either a reference to a `T` or a `T` itself.
315-
Hence, you can pass a `Transaction` or a `&Transaction` to `new`.
309+
Hence, you can pass a `Transaction`, a `&Transaction` or a smart pointer to `new`.
316310

317-
`sighash_cache` is instantiated as mutable because we require a mutable reference when creating the sighash to sign using [`taproot_signature_hash`](https://docs.rs/bitcoin/0.32.0/bitcoin/sighash/struct.SighashCache.html#method.taproot_signature_hash) to it.
311+
`sighash_cache` is bound as mutable because we are updating it with computed values during signing.
312+
This is reflected by [`taproot_signature_hash`](https://docs.rs/bitcoin/0.32.0/bitcoin/sighash/struct.SighashCache.html#method.taproot_signature_hash) taking a mutable reference.
318313
This computes the [BIP341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki) sighash for any flag type.
319314
It takes the following arguments:
320315

321-
- `input_index` is the index of the input we are signing; it is a [`usize`](https://doc.rust-lang.org/std/primitive.usize.html) type.
316+
- `input_index` is the index of the input we are signing; it has the [`usize`](https://doc.rust-lang.org/std/primitive.usize.html) type.
322317
We are using `0` since we only have one input.
323318
- `&prevouts` is a reference to the [`Prevouts`](https://docs.rs/bitcoin/0.32.0/bitcoin/sighash/enum.Prevouts.html) enum that we defined earlier.
324319
This is used to reference the outputs of previous transactions and also used to calculate our transaction value.
@@ -330,19 +325,19 @@ It takes the following arguments:
330325
We are using the [`All`](https://docs.rs/bitcoin/0.32.0/bitcoin/sighash/enum.TapSighashType.html#variant.All) variant,
331326
which indicates that the sighash will include all the inputs and outputs.
332327

333-
Taproot signatures are generated by tweaking the private (and public) key(s).
334-
`let tweaked: TweakedKeypair = keypair.tap_tweak(&secp, None);` accomplishes this.
328+
Since Taproot outputs contain the tweaked key and `keypair` represents untweaked (internal) key we have to tweak the key before signing using
329+
`let tweaked: TweakedKeypair = keypair.tap_tweak(&secp, None);`.
335330

336331
We create the message `msg` by converting the `sighash` to a [`Message`](https://docs.rs/secp256k1/0.29.0/secp256k1/struct.Message.html) type.
337332
This is a the message that we will sign.
338-
The [Message::from](https://docs.rs/secp256k1/0.29.0/secp256k1/struct.Message.html#impl-From%3C%26%27_%20bitcoin%3A%3Ahashes%3A%3Asha256d%3A%3AHash%3E) method takes anything that implements the promises to be a thirty two byte hash i.e., 32 bytes that came from a cryptographically secure hashing algorithm.
333+
The [Message::from](https://docs.rs/secp256k1/0.29.0/secp256k1/struct.Message.html#impl-From%3C%26%27_%20bitcoin%3A%3Ahashes%3A%3Asha256d%3A%3AHash%3E) method is available for types that are intended and safe for signing.
339334

340335
We compute the signature `sig` by using the [`sign_schnorr`](https://docs.rs/secp256k1/0.29.0/secp256k1/struct.Secp256k1.html#method.sign_schnorr) method.
341336
It takes a reference to a [`Message`](https://docs.rs/secp256k1/0.29.0/secp256k1/struct.Message.html) and a reference to a [`Keypair`](https://docs.rs/secp256k1/0.29.0/secp256k1/struct.Keypair.html) as arguments,
342337
and returns a [`Signature`](https://docs.rs/secp256k1/0.29.0/secp256k1/ecdsa/struct.Signature.html) type.
343338

344-
In the next step, we update the witness stack for the input we just signed by first converting the `sighash_cache` into a [`Transaction`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/transaction/struct.Transaction.html)
345-
by using the [`into_transaction`](https://docs.rs/bitcoin/0.32.0/bitcoin/sighash/struct.SighashCache.html#method.into_transaction) method.
339+
In the next step, we update the witness stack for the input we just signed by first releasing the [`Transaction`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/transaction/struct.Transaction.html)
340+
from `sighash_cache` by using the [`into_transaction`](https://docs.rs/bitcoin/0.32.0/bitcoin/sighash/struct.SighashCache.html#method.into_transaction) method.
346341
We access the witness field of the first input with `tx.input[0].witness`.
347342
It is a [`Witness`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/witness/struct.Witness.html) type.
348343
We use the [`push`](https://docs.rs/bitcoin/0.32.0/bitcoin/blockdata/witness/struct.Witness.html#method.push) method

0 commit comments

Comments
 (0)