1
1
use super :: * ;
2
2
3
- /// Signs the BIP-322 simple from encoded values, i.e. address encoding, message string and
4
- /// WIF private key string. Returns a base64 encoded witness stack.
3
+ /// Signs the BIP-322 simple from spec-compliant string encodings.
5
4
pub fn sign_simple_encoded ( address : & str , message : & str , wif_private_key : & str ) -> Result < String > {
6
5
let address = Address :: from_str ( address)
7
6
. context ( error:: AddressParse { address } ) ?
@@ -20,8 +19,7 @@ pub fn sign_simple_encoded(address: &str, message: &str, wif_private_key: &str)
20
19
Ok ( general_purpose:: STANDARD . encode ( buffer) )
21
20
}
22
21
23
- /// Signs the BIP-322 full from encoded values, i.e. address encoding, message string and
24
- /// WIF private key string. Returns a base64 encoded transaction.
22
+ /// Signs the BIP-322 full from spec-compliant string encodings.
25
23
pub fn sign_full_encoded ( address : & str , message : & str , wif_private_key : & str ) -> Result < String > {
26
24
let address = Address :: from_str ( address)
27
25
. context ( error:: AddressParse { address } ) ?
@@ -54,32 +52,86 @@ pub fn sign_full(
54
52
message : & [ u8 ] ,
55
53
private_key : PrivateKey ,
56
54
) -> Result < Transaction > {
57
- if let bitcoin:: address:: Payload :: WitnessProgram ( witness_program) = address. payload ( ) {
58
- if witness_program. version ( ) . to_num ( ) != 1 {
55
+ let to_spend = create_to_spend ( address, message) ?;
56
+ let mut to_sign = create_to_sign ( & to_spend, None ) ?;
57
+
58
+ let witness =
59
+ if let bitcoin:: address:: Payload :: WitnessProgram ( witness_program) = address. payload ( ) {
60
+ let version = witness_program. version ( ) . to_num ( ) ;
61
+ let program_len = witness_program. program ( ) . len ( ) ;
62
+
63
+ match version {
64
+ 0 => {
65
+ if program_len != 20 {
66
+ return Err ( Error :: NotKeyPathSpend ) ;
67
+ }
68
+ create_message_signature_p2wpkh ( & to_spend, & to_sign, private_key)
69
+ }
70
+ 1 => {
71
+ if program_len != 32 {
72
+ return Err ( Error :: NotKeyPathSpend ) ;
73
+ }
74
+ create_message_signature_taproot ( & to_spend, & to_sign, private_key)
75
+ }
76
+ _ => {
77
+ return Err ( Error :: UnsupportedAddress {
78
+ address : address. to_string ( ) ,
79
+ } )
80
+ }
81
+ }
82
+ } else {
59
83
return Err ( Error :: UnsupportedAddress {
60
84
address : address. to_string ( ) ,
61
85
} ) ;
62
- }
63
-
64
- if witness_program. program ( ) . len ( ) != 32 {
65
- return Err ( Error :: NotKeyPathSpend ) ;
66
- }
67
- } else {
68
- return Err ( Error :: UnsupportedAddress {
69
- address : address. to_string ( ) ,
70
- } ) ;
71
- } ;
86
+ } ;
72
87
73
- let to_spend = create_to_spend ( address, message) ?;
74
- let mut to_sign = create_to_sign ( & to_spend, None ) ?;
75
-
76
- let witness = create_message_signature ( & to_spend, & to_sign, private_key) ;
77
88
to_sign. inputs [ 0 ] . final_script_witness = Some ( witness) ;
78
89
79
90
to_sign. extract_tx ( ) . context ( error:: TransactionExtract )
80
91
}
81
92
82
- fn create_message_signature (
93
+ fn create_message_signature_p2wpkh (
94
+ to_spend_tx : & Transaction ,
95
+ to_sign : & Psbt ,
96
+ private_key : PrivateKey ,
97
+ ) -> Witness {
98
+ let secp = Secp256k1 :: new ( ) ;
99
+ let sighash_type = EcdsaSighashType :: All ;
100
+ let mut sighash_cache = SighashCache :: new ( to_sign. unsigned_tx . clone ( ) ) ;
101
+
102
+ let sighash = sighash_cache
103
+ . p2wpkh_signature_hash (
104
+ 0 ,
105
+ & to_spend_tx. output [ 0 ] . script_pubkey ,
106
+ to_spend_tx. output [ 0 ] . value ,
107
+ sighash_type,
108
+ )
109
+ . expect ( "signature hash should compute" ) ;
110
+
111
+ let sig = secp. sign_ecdsa (
112
+ & secp256k1:: Message :: from_digest_slice ( sighash. as_ref ( ) )
113
+ . expect ( "should be cryptographically secure hash" ) ,
114
+ & private_key. inner ,
115
+ ) ;
116
+
117
+ let witness = sighash_cache
118
+ . witness_mut ( 0 )
119
+ . expect ( "getting mutable witness reference should work" ) ;
120
+
121
+ witness. push (
122
+ bitcoin:: ecdsa:: Signature {
123
+ sig,
124
+ hash_ty : sighash_type,
125
+ }
126
+ . to_vec ( ) ,
127
+ ) ;
128
+
129
+ witness. push ( private_key. public_key ( & secp) . to_bytes ( ) ) ;
130
+
131
+ witness. to_owned ( )
132
+ }
133
+
134
+ fn create_message_signature_taproot (
83
135
to_spend_tx : & Transaction ,
84
136
to_sign : & Psbt ,
85
137
private_key : PrivateKey ,
@@ -88,6 +140,7 @@ fn create_message_signature(
88
140
89
141
let secp = Secp256k1 :: new ( ) ;
90
142
let key_pair = Keypair :: from_secret_key ( & secp, & private_key. inner ) ;
143
+
91
144
let ( x_only_public_key, _parity) = XOnlyPublicKey :: from_keypair ( & key_pair) ;
92
145
to_sign. inputs [ 0 ] . tap_internal_key = Some ( x_only_public_key) ;
93
146
0 commit comments