11// BIP322 Generic Signature Algorithm
2- // Written in 2019 by
2+ // Written in 2021 by
33// Rajarshi Maitra <[email protected] >] 44//
55// To the extent possible under law, the author(s) have dedicated all
1919//! `https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki`
2020//!
2121
22- use crate :: { Descriptor , DescriptorTrait , MiniscriptKey , ToPublicKey } ;
22+ use super :: { Descriptor , DescriptorTrait , MiniscriptKey , ToPublicKey } ;
2323use bitcoin:: blockdata:: { opcodes, script:: Builder } ;
2424use bitcoin:: hashes:: {
2525 borrow_slice_impl, hex_fmt_impl, index_impl, serde_impl, sha256t_hash_newtype, Hash ,
2626} ;
2727use bitcoin:: secp256k1:: { Secp256k1 , Signature } ;
2828use bitcoin:: { OutPoint , PublicKey , SigHashType , Transaction , TxIn , TxOut } ;
2929
30- use crate :: interpreter:: { Error as InterpreterError , Interpreter } ;
30+ use super :: interpreter:: { Error as InterpreterError , Interpreter } ;
3131use std:: convert:: From ;
3232
33- // BIP322 message tag = sha256("BIP0322-signed-message")
34- static MIDSTATE : [ u8 ; 32 ] = [
35- 116 , 101 , 132 , 161 , 135 , 47 , 161 , 0 , 65 , 85 , 78 , 255 , 160 , 56 , 214 , 18 , 73 , 66 , 221 , 121 , 180 ,
36- 229 , 138 , 76 , 218 , 24 , 78 , 19 , 219 , 230 , 44 , 73 ,
33+ // BIP322 message tagged hash midstate
34+ const MIDSTATE : [ u8 ; 32 ] = [
35+ 137 , 110 , 101 , 166 , 158 , 24 , 33 , 51 , 154 , 160 , 217 , 89 , 167 , 185 , 222 , 252 , 115 , 60 , 186 , 140 ,
36+ 151 , 47 , 2 , 20 , 94 , 72 , 184 , 111 , 248 , 59 , 249 , 156 ,
3737] ;
3838
3939// BIP322 Tagged Hash
@@ -42,7 +42,7 @@ sha256t_hash_newtype!(
4242 MessageTag ,
4343 MIDSTATE ,
4444 64 ,
45- doc = "test hash" ,
45+ doc = "BIP322 message tagged hash" ,
4646 true
4747) ;
4848
@@ -81,44 +81,50 @@ pub enum Bip322Signature {
8181/// either for proving fund availability, or committing to a message as the intended
8282/// recipient of funds sent to the invoice address.
8383#[ derive( Debug , Clone , Eq , PartialEq ) ]
84- pub struct Bip322 < T : MiniscriptKey + ToPublicKey > {
84+ pub struct Bip322Validator < Pk : MiniscriptKey + ToPublicKey > {
8585 /// Message to be signed
86- message : Vec < u8 > ,
86+ message : String ,
8787
8888 /// Signature to verify the message
89- /// Optional value is used here because a validator structure can be
90- /// created without a BIP322Signature. Such structure can only produce
91- /// to_spend (or empty to_sign) transaction, but cannot validate them.
92- signature : Option < Bip322Signature > ,
89+ signature : Bip322Signature ,
9390
9491 /// script_pubkey to define the challenge script inside to_spend transaction
9592 /// here we take in descriptors to derive the resulting script_pubkey
96- message_challenge : Descriptor < T > ,
93+ message_challenge : Descriptor < Pk > ,
94+
95+ /// Age
96+ age : u32 ,
97+
98+ /// Height
99+ height : u32 ,
97100}
98101
99- impl < T : MiniscriptKey + ToPublicKey > Bip322 < T > {
102+ impl < Pk : MiniscriptKey + ToPublicKey > Bip322Validator < Pk > {
100103 /// Create a new BIP322 validator
101- pub fn new ( msg : & [ u8 ] , sig : Option < Bip322Signature > , addr : Descriptor < T > ) -> Self {
102- Bip322 {
103- message : msg. to_vec ( ) ,
104+ pub fn new (
105+ msg : String ,
106+ sig : Bip322Signature ,
107+ addr : Descriptor < Pk > ,
108+ age : u32 ,
109+ height : u32 ,
110+ ) -> Self {
111+ Bip322Validator {
112+ message : msg,
104113 signature : sig,
105114 message_challenge : addr,
115+ age : age,
116+ height : height,
106117 }
107118 }
108119
109- /// Insert Signature inside BIP322 structure
110- pub fn insert_sig ( & mut self , sig : Bip322Signature ) {
111- self . signature = Some ( sig)
112- }
113-
114120 /// create the to_spend transaction
115121 pub fn to_spend ( & self ) -> Transaction {
116122 // create default input and output
117123 let mut vin = TxIn :: default ( ) ;
118124 let mut vout = TxOut :: default ( ) ;
119125
120126 // calculate the message tagged hash
121- let msg_hash = MessageHash :: hash ( & self . message [ .. ] ) . into_inner ( ) ;
127+ let msg_hash = MessageHash :: hash ( & self . message . as_bytes ( ) ) . into_inner ( ) ;
122128
123129 // mutate the input with appropriate script_sig and sequence
124130 vin. script_sig = Builder :: new ( )
@@ -143,12 +149,12 @@ impl<T: MiniscriptKey + ToPublicKey> Bip322<T> {
143149 /// Create to_sign transaction
144150 /// This will create a transaction structure with empty signature and witness field
145151 /// its up to the user of the library to fill the Tx with appropriate signature and witness
146- pub fn to_sign ( & self ) -> Transaction {
152+ pub fn empty_to_sign ( & self ) -> Transaction {
147153 // create the appropriate input
148154 let outpoint = OutPoint :: new ( self . to_spend ( ) . txid ( ) , 0 ) ;
149155 let mut input = TxIn :: default ( ) ;
150156 input. previous_output = outpoint;
151- input. sequence = 0 ;
157+ input. sequence = self . height ;
152158
153159 // create the output
154160 let output = TxOut {
@@ -160,8 +166,8 @@ impl<T: MiniscriptKey + ToPublicKey> Bip322<T> {
160166
161167 // return resulting transaction
162168 Transaction {
163- version : 0 ,
164- lock_time : 0 ,
169+ version : 2 ,
170+ lock_time : self . age ,
165171 input : vec ! [ input] ,
166172 output : vec ! [ output] ,
167173 }
@@ -171,46 +177,46 @@ impl<T: MiniscriptKey + ToPublicKey> Bip322<T> {
171177 /// This will require a BIP322Signature inside the structure
172178 pub fn validate ( & self ) -> Result < bool , BIP322Error > {
173179 match & self . signature {
174- None => Err ( BIP322Error :: InternalError (
175- "Signature required for validation" . to_string ( ) ,
176- ) ) ,
177- Some ( sig ) => {
178- match sig {
179- // A Full signature can be validated directly against the `to_sign` transaction
180- Bip322Signature :: Full ( to_sign ) => self . tx_validation ( to_sign ) ,
181-
182- // If Simple Signature is provided, the resulting ` to_sign` Tx will be computed
183- Bip322Signature :: Simple ( witness ) => {
184- // create empty to_sign transaction
185- let mut to_sign = self . to_sign ( ) ;
186-
187- to_sign . input [ 0 ] . witness = witness . to_owned ( ) ;
188-
189- self . tx_validation ( & to_sign )
190- }
191-
192- // Legacy Signature can only be used to validate against P2PKH message_challenge
193- Bip322Signature :: Legacy ( sig , pubkey ) => {
194- if ! self . message_challenge . script_pubkey ( ) . is_p2pkh ( ) {
195- return Err ( BIP322Error :: InternalError ( "Legacy style signature is only applicable for P2PKH message_challenge" . to_string ( ) ) ) ;
196- } else {
197- let mut sig_ser = sig . serialize_der ( ) [ .. ] . to_vec ( ) ;
198-
199- // By default SigHashType is ALL
200- sig_ser . push ( SigHashType :: All as u8 ) ;
201-
202- let script_sig = Builder :: new ( )
203- . push_slice ( & sig_ser [ .. ] )
204- . push_key ( & pubkey )
205- . into_script ( ) ;
206-
207- let mut to_sign = self . to_sign ( ) ;
208-
209- to_sign. input [ 0 ] . script_sig = script_sig ;
210-
211- self . tx_validation ( & to_sign )
212- }
213- }
180+ // A Full signature can be validated directly against the `to_sign` transaction
181+ Bip322Signature :: Full ( to_sign ) => self . tx_validation ( to_sign ) ,
182+
183+ // If Simple Signature is provided, the resulting `to_sign` Tx will be computed
184+ Bip322Signature :: Simple ( witness ) => {
185+ if ! self . message_challenge . script_pubkey ( ) . is_witness_program ( ) {
186+ return Err ( BIP322Error :: InternalError ( "Simple style signature is only applicable for Segwit type message_challenge" . to_string ( ) ) ) ;
187+ } else {
188+ // create empty to_sign transaction
189+ let mut to_sign = self . empty_to_sign ( ) ;
190+
191+ to_sign. input [ 0 ] . witness = witness . to_owned ( ) ;
192+
193+ self . tx_validation ( & to_sign )
194+ }
195+ }
196+
197+ // Legacy Signature can only be used to validate against P2PKH message_challenge
198+ Bip322Signature :: Legacy ( sig , pubkey ) => {
199+ if ! self . message_challenge . script_pubkey ( ) . is_p2pkh ( ) {
200+ return Err ( BIP322Error :: InternalError (
201+ "Legacy style signature is only applicable for P2PKH message_challenge"
202+ . to_string ( ) ,
203+ ) ) ;
204+ } else {
205+ let mut sig_ser = sig . serialize_der ( ) [ .. ] . to_vec ( ) ;
206+
207+ // By default SigHashType is ALL
208+ sig_ser . push ( SigHashType :: All as u8 ) ;
209+
210+ let script_sig = Builder :: new ( )
211+ . push_slice ( & sig_ser [ .. ] )
212+ . push_key ( & pubkey )
213+ . into_script ( ) ;
214+
215+ let mut to_sign = self . empty_to_sign ( ) ;
216+
217+ to_sign . input [ 0 ] . script_sig = script_sig ;
218+
219+ self . tx_validation ( & to_sign )
214220 }
215221 }
216222 }
@@ -248,6 +254,8 @@ impl<T: MiniscriptKey + ToPublicKey> Bip322<T> {
248254#[ cfg( test) ]
249255mod test {
250256 use super :: * ;
257+ use bitcoin:: hashes:: sha256t:: Tag ;
258+ use bitcoin:: hashes:: { sha256, HashEngine } ;
251259 use bitcoin:: secp256k1:: { Message , Secp256k1 } ;
252260 use bitcoin:: util:: bip143;
253261 use bitcoin:: PrivateKey ;
@@ -268,23 +276,69 @@ mod test {
268276 // Corresponding p2pkh script. used for sighash calculation
269277 let p2pkh_script = bitcoin:: Script :: new_p2pkh ( & pk. pubkey_hash ( ) ) ;
270278
271- // Create BIP322 structures with empty signature
272- let mut bip322_1 = Bip322 {
273- message : b"Hello World" . to_vec ( ) ,
274- message_challenge : desc. clone ( ) ,
275- signature : None ,
279+ let message = "Hello World" . to_string ( ) ;
280+ let age = 0 ;
281+ let height = 0 ;
282+
283+ // Create to_spend transaction
284+ let to_spend = {
285+ // create default input and output
286+ let mut vin = TxIn :: default ( ) ;
287+ let mut vout = TxOut :: default ( ) ;
288+
289+ // calculate the message tagged hash
290+ let msg_hash = MessageHash :: hash ( & message. as_bytes ( ) ) . into_inner ( ) ;
291+
292+ // mutate the input with appropriate script_sig and sequence
293+ vin. script_sig = Builder :: new ( )
294+ . push_int ( 0 )
295+ . push_slice ( & msg_hash[ ..] )
296+ . into_script ( ) ;
297+ vin. sequence = 0 ;
298+
299+ // mutate the value and script_pubkey as appropriate
300+ vout. value = 0 ;
301+ vout. script_pubkey = desc. script_pubkey ( ) ;
302+
303+ // create and return final transaction
304+ Transaction {
305+ version : 0 ,
306+ lock_time : 0 ,
307+ input : vec ! [ vin] ,
308+ output : vec ! [ vout] ,
309+ }
310+ } ;
311+
312+ // create an empty to_sign transaction
313+ let mut empty_to_sign = {
314+ // create the appropriate input
315+ let outpoint = OutPoint :: new ( to_spend. txid ( ) , 0 ) ;
316+ let mut input = TxIn :: default ( ) ;
317+ input. previous_output = outpoint;
318+ input. sequence = height;
319+
320+ // create the output
321+ let output = TxOut {
322+ value : 0 ,
323+ script_pubkey : Builder :: new ( )
324+ . push_opcode ( opcodes:: all:: OP_RETURN )
325+ . into_script ( ) ,
326+ } ;
327+
328+ // return resulting transaction
329+ Transaction {
330+ version : 2 ,
331+ lock_time : age,
332+ input : vec ! [ input] ,
333+ output : vec ! [ output] ,
334+ }
276335 } ;
277- let mut bip322_2 = bip322_1. clone ( ) ;
278- let mut bip322_3 = bip322_1. clone ( ) ;
279336
280337 // --------------------------------------------------------------
281338 // Check BIP322Signature::FUll
282339
283- // Generate to_sign transaction
284- let mut to_sign = bip322_1. to_sign ( ) ;
285-
286340 // Generate witness for above wpkh pubkey
287- let mut sighash_cache = bip143:: SigHashCache :: new ( & to_sign ) ;
341+ let mut sighash_cache = bip143:: SigHashCache :: new ( & empty_to_sign ) ;
288342 let message = sighash_cache. signature_hash ( 0 , & p2pkh_script, 0 , SigHashType :: All . into ( ) ) ;
289343 let message = Message :: from_slice ( & message[ ..] ) . unwrap ( ) ;
290344
@@ -294,11 +348,20 @@ mod test {
294348 sig_with_hash. push ( SigHashType :: All as u8 ) ;
295349
296350 let witness: Vec < Vec < u8 > > = vec ! [ sig_with_hash, pk. to_bytes( ) ] ;
297- to_sign . input [ 0 ] . witness = witness. clone ( ) ;
351+ empty_to_sign . input [ 0 ] . witness = witness. clone ( ) ;
298352
299- // Insert signature inside BIP322 structure
300- let bip322_signature = Bip322Signature :: Full ( to_sign) ;
301- bip322_1. insert_sig ( bip322_signature) ;
353+ let bip322_signature = Bip322Signature :: Full ( empty_to_sign) ;
354+
355+ // Create BIP322 Validator
356+ let bip322_1 = Bip322Validator {
357+ message : "Hello World" . to_string ( ) ,
358+ message_challenge : desc. clone ( ) ,
359+ signature : bip322_signature,
360+ age : 0 ,
361+ height : 0 ,
362+ } ;
363+ let mut bip322_2 = bip322_1. clone ( ) ;
364+ let mut bip322_3 = bip322_1. clone ( ) ;
302365
303366 // Check validation
304367 assert_eq ! ( bip322_1. validate( ) . unwrap( ) , true ) ;
@@ -307,7 +370,7 @@ mod test {
307370 // Check Bip322Signature::Simple
308371
309372 // Same structure can be validated with Simple type signature
310- bip322_2. insert_sig ( Bip322Signature :: Simple ( witness) ) ;
373+ bip322_2. signature = Bip322Signature :: Simple ( witness) ;
311374
312375 assert_eq ! ( bip322_2. validate( ) . unwrap( ) , true ) ;
313376
@@ -320,7 +383,7 @@ mod test {
320383 bip322_3. message_challenge = desc. clone ( ) ;
321384
322385 // Create empty to_sign
323- let to_sign = bip322_3. to_sign ( ) ;
386+ let to_sign = bip322_3. empty_to_sign ( ) ;
324387
325388 // Compute SigHash and Signature
326389 let message = to_sign. signature_hash ( 0 , & desc. script_pubkey ( ) , SigHashType :: All as u32 ) ;
@@ -329,9 +392,20 @@ mod test {
329392
330393 // Create Bip322Signature::Legacy
331394 let bip322_sig = Bip322Signature :: Legacy ( signature, pk) ;
332- bip322_3. insert_sig ( bip322_sig) ;
395+ bip322_3. signature = bip322_sig;
333396
334397 // Check validation
335398 assert_eq ! ( bip322_3. validate( ) . unwrap( ) , true ) ;
336399 }
400+
401+ #[ test]
402+ fn test_tagged_hash ( ) {
403+ let mut engine = sha256:: Hash :: engine ( ) ;
404+ let tag_hash = sha256:: Hash :: hash ( "BIP0322-signed-message" . as_bytes ( ) ) ;
405+ engine. input ( & tag_hash[ ..] ) ;
406+ engine. input ( & tag_hash[ ..] ) ;
407+
408+ assert_eq ! ( engine. midstate( ) . into_inner( ) , MIDSTATE ) ;
409+ assert_eq ! ( engine. midstate( ) , MessageTag :: engine( ) . midstate( ) ) ;
410+ }
337411}
0 commit comments