12
12
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
13
13
//
14
14
15
- //! Example: Signing a 2-of-3 multisignature
15
+ //! Example: Signing a 2-of-3 multisignature.
16
16
17
17
use bitcoin;
18
18
use miniscript;
19
19
20
20
use bitcoin:: blockdata:: witness:: Witness ;
21
- use bitcoin:: secp256k1; // secp256k1 re-exported from rust-bitcoin
21
+ use bitcoin:: secp256k1;
22
22
use miniscript:: DescriptorTrait ;
23
23
use std:: collections:: HashMap ;
24
24
use std:: str:: FromStr ;
25
25
26
26
fn main ( ) {
27
- // Avoid repeatedly typing a pretty-common descriptor type
28
- type BitcoinDescriptor = miniscript:: Descriptor < bitcoin:: PublicKey > ;
27
+ let mut tx = spending_transaction ( ) ;
28
+ let pks = list_of_three_arbitrary_public_keys ( ) ;
29
+ let sig = random_signature_from_the_blockchain ( ) ;
29
30
30
- // Transaction which spends some output
31
- let mut tx = bitcoin:: Transaction {
31
+ // Descriptor for the output being spent.
32
+ let s = format ! ( "wsh(multi(2,{},{},{}))" , pks[ 0 ] , pks[ 1 ] , pks[ 2 ] , ) ;
33
+ let descriptor = miniscript:: Descriptor :: < bitcoin:: PublicKey > :: from_str ( & s) . unwrap ( ) ;
34
+
35
+ // Check weight for witness satisfaction cost ahead of time.
36
+ // 4 (scriptSig length of 0) + 1 (witness stack size) + 106 (serialized witnessScript)
37
+ // + 73*2 (signature length + signatures + sighash bytes) + 1 (dummy byte) = 258
38
+ assert_eq ! ( descriptor. max_satisfaction_weight( ) . unwrap( ) , 258 ) ;
39
+
40
+ // Sometimes it is necessary to have additional information to get the
41
+ // `bitcoin::PublicKey` from the `MiniscriptKey` which can be supplied by
42
+ // the `to_pk_ctx` parameter. For example, when calculating the script
43
+ // pubkey of a descriptor with xpubs, the secp context and child information
44
+ // maybe required.
45
+
46
+ // Observe the script properties, just for fun.
47
+ assert_eq ! (
48
+ format!( "{:x}" , descriptor. script_pubkey( ) ) ,
49
+ "00200ed49b334a12c37f3df8a2974ad91ff95029215a2b53f78155be737907f06163"
50
+ ) ;
51
+
52
+ assert_eq ! (
53
+ format!(
54
+ "{:x}" ,
55
+ descriptor
56
+ . explicit_script( )
57
+ . expect( "wsh descriptors have unique inner script" )
58
+ ) ,
59
+ "52\
60
+ 21020202020202020202020202020202020202020202020202020202020202020202\
61
+ 21020102030405060708010203040506070801020304050607080000000000000000\
62
+ 21030102030405060708010203040506070801020304050607080000000000000000\
63
+ 53ae"
64
+ ) ;
65
+
66
+ // Attempt to satisfy at age 0, height 0.
67
+ let original_txin = tx. input [ 0 ] . clone ( ) ;
68
+
69
+ let mut sigs = HashMap :: < bitcoin:: PublicKey , miniscript:: bitcoin:: EcdsaSig > :: new ( ) ;
70
+
71
+ // Doesn't work with no signatures.
72
+ assert ! ( descriptor. satisfy( & mut tx. input[ 0 ] , & sigs) . is_err( ) ) ;
73
+ assert_eq ! ( tx. input[ 0 ] , original_txin) ;
74
+
75
+ // ...or one signature...
76
+ sigs. insert ( pks[ 1 ] , sig) ;
77
+ assert ! ( descriptor. satisfy( & mut tx. input[ 0 ] , & sigs) . is_err( ) ) ;
78
+ assert_eq ! ( tx. input[ 0 ] , original_txin) ;
79
+
80
+ // ...but two signatures is ok.
81
+ sigs. insert ( pks[ 2 ] , sig) ;
82
+ assert ! ( descriptor. satisfy( & mut tx. input[ 0 ] , & sigs) . is_ok( ) ) ;
83
+ assert_ne ! ( tx. input[ 0 ] , original_txin) ;
84
+ assert_eq ! ( tx. input[ 0 ] . witness. len( ) , 4 ) ; // 0, sig, sig, witness script
85
+
86
+ // ...and even if we give it a third signature, only two are used.
87
+ sigs. insert ( pks[ 0 ] , sig) ;
88
+ assert ! ( descriptor. satisfy( & mut tx. input[ 0 ] , & sigs) . is_ok( ) ) ;
89
+ assert_ne ! ( tx. input[ 0 ] , original_txin) ;
90
+ assert_eq ! ( tx. input[ 0 ] . witness. len( ) , 4 ) ; // 0, sig, sig, witness script
91
+ }
92
+
93
+ // Transaction which spends some output.
94
+ fn spending_transaction ( ) -> bitcoin:: Transaction {
95
+ bitcoin:: Transaction {
32
96
version : 2 ,
33
97
lock_time : 0 ,
34
98
input : vec ! [ bitcoin:: TxIn {
@@ -41,10 +105,12 @@ fn main() {
41
105
script_pubkey: bitcoin:: Script :: new( ) ,
42
106
value: 100_000_000 ,
43
107
} ] ,
44
- } ;
108
+ }
109
+ }
45
110
111
+ fn list_of_three_arbitrary_public_keys ( ) -> Vec < bitcoin:: PublicKey > {
46
112
#[ cfg_attr( feature="cargo-fmt" , rustfmt_skip) ]
47
- let public_keys = vec ! [
113
+ vec ! [
48
114
bitcoin:: PublicKey :: from_slice( & [ 2 ; 33 ] ) . expect( "key 1" ) ,
49
115
bitcoin:: PublicKey :: from_slice( & [
50
116
0x02 ,
@@ -60,10 +126,13 @@ fn main() {
60
126
0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 , 0x08 ,
61
127
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
62
128
] ) . expect( "key 3" ) ,
63
- ] ;
64
- let bitcoin_sig = bitcoin:: EcdsaSig {
65
- // copied at random off the blockchain; this is not actually a valid
66
- // signature for this transaction; Miniscript does not verify
129
+ ]
130
+ }
131
+
132
+ // Returns a signature copied at random off the blockchain; this is not actually
133
+ // a valid signature for this transaction; Miniscript does not verify the validity.
134
+ fn random_signature_from_the_blockchain ( ) -> bitcoin:: EcdsaSig {
135
+ bitcoin:: EcdsaSig {
67
136
sig : secp256k1:: ecdsa:: Signature :: from_str (
68
137
"3045\
69
138
0221\
@@ -73,70 +142,5 @@ fn main() {
73
142
)
74
143
. unwrap ( ) ,
75
144
hash_ty : bitcoin:: EcdsaSighashType :: All ,
76
- } ;
77
-
78
- let descriptor_str = format ! (
79
- "wsh(multi(2,{},{},{}))" ,
80
- public_keys[ 0 ] , public_keys[ 1 ] , public_keys[ 2 ] ,
81
- ) ;
82
-
83
- // Descriptor for the output being spent
84
- let my_descriptor =
85
- BitcoinDescriptor :: from_str ( & descriptor_str[ ..] ) . expect ( "parse descriptor string" ) ;
86
-
87
- // Check weight for witness satisfaction cost ahead of time.
88
- // 4(scriptSig length of 0) + 1(witness stack size) + 106(serialized witnessScript)
89
- // + 73*2(signature length + signatures + sighash bytes) + 1(dummy byte) = 258
90
- assert_eq ! ( my_descriptor. max_satisfaction_weight( ) . unwrap( ) , 258 ) ;
91
-
92
- // Sometimes it is necessary to have additional information to get the bitcoin::PublicKey
93
- // from the MiniscriptKey which can supplied by `to_pk_ctx` parameter. For example,
94
- // when calculating the script pubkey of a descriptor with xpubs, the secp context and
95
- // child information maybe required.
96
-
97
- // Observe the script properties, just for fun
98
- assert_eq ! (
99
- format!( "{:x}" , my_descriptor. script_pubkey( ) ) ,
100
- "00200ed49b334a12c37f3df8a2974ad91ff95029215a2b53f78155be737907f06163"
101
- ) ;
102
-
103
- assert_eq ! (
104
- format!(
105
- "{:x}" ,
106
- my_descriptor
107
- . explicit_script( )
108
- . expect( "wsh descriptors have unique inner script" )
109
- ) ,
110
- "52\
111
- 21020202020202020202020202020202020202020202020202020202020202020202\
112
- 21020102030405060708010203040506070801020304050607080000000000000000\
113
- 21030102030405060708010203040506070801020304050607080000000000000000\
114
- 53ae"
115
- ) ;
116
-
117
- // Attempt to satisfy at age 0, height 0
118
- let original_txin = tx. input [ 0 ] . clone ( ) ;
119
-
120
- let mut sigs = HashMap :: < bitcoin:: PublicKey , miniscript:: bitcoin:: EcdsaSig > :: new ( ) ;
121
-
122
- // Doesn't work with no signatures
123
- assert ! ( my_descriptor. satisfy( & mut tx. input[ 0 ] , & sigs) . is_err( ) ) ;
124
- assert_eq ! ( tx. input[ 0 ] , original_txin) ;
125
-
126
- // ...or one signature...
127
- sigs. insert ( public_keys[ 1 ] , bitcoin_sig) ;
128
- assert ! ( my_descriptor. satisfy( & mut tx. input[ 0 ] , & sigs) . is_err( ) ) ;
129
- assert_eq ! ( tx. input[ 0 ] , original_txin) ;
130
-
131
- // ...but two signatures is ok
132
- sigs. insert ( public_keys[ 2 ] , bitcoin_sig) ;
133
- assert ! ( my_descriptor. satisfy( & mut tx. input[ 0 ] , & sigs) . is_ok( ) ) ;
134
- assert_ne ! ( tx. input[ 0 ] , original_txin) ;
135
- assert_eq ! ( tx. input[ 0 ] . witness. len( ) , 4 ) ; // 0, sig, sig, witness script
136
-
137
- // ...and even if we give it a third signature, only two are used
138
- sigs. insert ( public_keys[ 0 ] , bitcoin_sig) ;
139
- assert ! ( my_descriptor. satisfy( & mut tx. input[ 0 ] , & sigs) . is_ok( ) ) ;
140
- assert_ne ! ( tx. input[ 0 ] , original_txin) ;
141
- assert_eq ! ( tx. input[ 0 ] . witness. len( ) , 4 ) ; // 0, sig, sig, witness script
145
+ }
142
146
}
0 commit comments