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
@@ -76,49 +76,58 @@ pub enum Bip322Signature {
7676 Full ( Transaction ) ,
7777}
7878
79+ /// TODO: Bip322 Signer structure
80+ pub struct Bip322Signer { }
81+
7982/// BIP322 validator structure
8083/// A standard for interoperable signed messages based on the Bitcoin Script format,
8184/// either for proving fund availability, or committing to a message as the intended
8285/// recipient of funds sent to the invoice address.
8386#[ derive( Debug , Clone , Eq , PartialEq ) ]
84- pub struct Bip322 < T : MiniscriptKey + ToPublicKey > {
87+ pub struct Bip322Validator < Pk : MiniscriptKey + ToPublicKey > {
8588 /// Message to be signed
86- message : Vec < u8 > ,
89+ message : String ,
8790
8891 /// 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 > ,
92+ signature : Bip322Signature ,
9393
9494 /// script_pubkey to define the challenge script inside to_spend transaction
9595 /// here we take in descriptors to derive the resulting script_pubkey
96- message_challenge : Descriptor < T > ,
96+ message_challenge : Descriptor < Pk > ,
97+
98+ /// Age
99+ age : u32 ,
100+
101+ /// Height
102+ height : u32 ,
97103}
98104
99- impl < T : MiniscriptKey + ToPublicKey > Bip322 < T > {
105+ impl < Pk : MiniscriptKey + ToPublicKey > Bip322Validator < Pk > {
100106 /// 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 ( ) ,
107+ pub fn new (
108+ msg : String ,
109+ sig : Bip322Signature ,
110+ addr : Descriptor < Pk > ,
111+ age : u32 ,
112+ height : u32 ,
113+ ) -> Self {
114+ Bip322Validator {
115+ message : msg,
104116 signature : sig,
105117 message_challenge : addr,
118+ age : age,
119+ height : height,
106120 }
107121 }
108122
109- /// Insert Signature inside BIP322 structure
110- pub fn insert_sig ( & mut self , sig : Bip322Signature ) {
111- self . signature = Some ( sig)
112- }
113-
114123 /// create the to_spend transaction
115124 pub fn to_spend ( & self ) -> Transaction {
116125 // create default input and output
117126 let mut vin = TxIn :: default ( ) ;
118127 let mut vout = TxOut :: default ( ) ;
119128
120129 // calculate the message tagged hash
121- let msg_hash = MessageHash :: hash ( & self . message [ .. ] ) . into_inner ( ) ;
130+ let msg_hash = MessageHash :: hash ( & self . message . as_bytes ( ) ) . into_inner ( ) ;
122131
123132 // mutate the input with appropriate script_sig and sequence
124133 vin. script_sig = Builder :: new ( )
@@ -143,12 +152,12 @@ impl<T: MiniscriptKey + ToPublicKey> Bip322<T> {
143152 /// Create to_sign transaction
144153 /// This will create a transaction structure with empty signature and witness field
145154 /// its up to the user of the library to fill the Tx with appropriate signature and witness
146- pub fn to_sign ( & self ) -> Transaction {
155+ pub fn empty_to_sign ( & self ) -> Transaction {
147156 // create the appropriate input
148157 let outpoint = OutPoint :: new ( self . to_spend ( ) . txid ( ) , 0 ) ;
149158 let mut input = TxIn :: default ( ) ;
150159 input. previous_output = outpoint;
151- input. sequence = 0 ;
160+ input. sequence = self . height ;
152161
153162 // create the output
154163 let output = TxOut {
@@ -160,8 +169,8 @@ impl<T: MiniscriptKey + ToPublicKey> Bip322<T> {
160169
161170 // return resulting transaction
162171 Transaction {
163- version : 0 ,
164- lock_time : 0 ,
172+ version : 2 ,
173+ lock_time : self . age ,
165174 input : vec ! [ input] ,
166175 output : vec ! [ output] ,
167176 }
@@ -171,46 +180,46 @@ impl<T: MiniscriptKey + ToPublicKey> Bip322<T> {
171180 /// This will require a BIP322Signature inside the structure
172181 pub fn validate ( & self ) -> Result < bool , BIP322Error > {
173182 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- }
183+ // A Full signature can be validated directly against the `to_sign` transaction
184+ Bip322Signature :: Full ( to_sign ) => self . tx_validation ( to_sign ) ,
185+
186+ // If Simple Signature is provided, the resulting `to_sign` Tx will be computed
187+ Bip322Signature :: Simple ( witness ) => {
188+ if ! self . message_challenge . script_pubkey ( ) . is_witness_program ( ) {
189+ return Err ( BIP322Error :: InternalError ( "Simple style signature is only applicable for Segwit type message_challenge" . to_string ( ) ) ) ;
190+ } else {
191+ // create empty to_sign transaction
192+ let mut to_sign = self . empty_to_sign ( ) ;
193+
194+ to_sign. input [ 0 ] . witness = witness . to_owned ( ) ;
195+
196+ self . tx_validation ( & to_sign )
197+ }
198+ }
199+
200+ // Legacy Signature can only be used to validate against P2PKH message_challenge
201+ Bip322Signature :: Legacy ( sig , pubkey ) => {
202+ if ! self . message_challenge . script_pubkey ( ) . is_p2pkh ( ) {
203+ return Err ( BIP322Error :: InternalError (
204+ "Legacy style signature is only applicable for P2PKH message_challenge"
205+ . to_string ( ) ,
206+ ) ) ;
207+ } else {
208+ let mut sig_ser = sig . serialize_der ( ) [ .. ] . to_vec ( ) ;
209+
210+ // By default SigHashType is ALL
211+ sig_ser . push ( SigHashType :: All as u8 ) ;
212+
213+ let script_sig = Builder :: new ( )
214+ . push_slice ( & sig_ser [ .. ] )
215+ . push_key ( & pubkey )
216+ . into_script ( ) ;
217+
218+ let mut to_sign = self . empty_to_sign ( ) ;
219+
220+ to_sign . input [ 0 ] . script_sig = script_sig ;
221+
222+ self . tx_validation ( & to_sign )
214223 }
215224 }
216225 }
@@ -248,6 +257,8 @@ impl<T: MiniscriptKey + ToPublicKey> Bip322<T> {
248257#[ cfg( test) ]
249258mod test {
250259 use super :: * ;
260+ use bitcoin:: hashes:: sha256t:: Tag ;
261+ use bitcoin:: hashes:: { sha256, HashEngine } ;
251262 use bitcoin:: secp256k1:: { Message , Secp256k1 } ;
252263 use bitcoin:: util:: bip143;
253264 use bitcoin:: PrivateKey ;
@@ -268,23 +279,69 @@ mod test {
268279 // Corresponding p2pkh script. used for sighash calculation
269280 let p2pkh_script = bitcoin:: Script :: new_p2pkh ( & pk. pubkey_hash ( ) ) ;
270281
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 ,
282+ let message = "Hello World" . to_string ( ) ;
283+ let age = 0 ;
284+ let height = 0 ;
285+
286+ // Create to_spend transaction
287+ let to_spend = {
288+ // create default input and output
289+ let mut vin = TxIn :: default ( ) ;
290+ let mut vout = TxOut :: default ( ) ;
291+
292+ // calculate the message tagged hash
293+ let msg_hash = MessageHash :: hash ( & message. as_bytes ( ) ) . into_inner ( ) ;
294+
295+ // mutate the input with appropriate script_sig and sequence
296+ vin. script_sig = Builder :: new ( )
297+ . push_int ( 0 )
298+ . push_slice ( & msg_hash[ ..] )
299+ . into_script ( ) ;
300+ vin. sequence = 0 ;
301+
302+ // mutate the value and script_pubkey as appropriate
303+ vout. value = 0 ;
304+ vout. script_pubkey = desc. script_pubkey ( ) ;
305+
306+ // create and return final transaction
307+ Transaction {
308+ version : 0 ,
309+ lock_time : 0 ,
310+ input : vec ! [ vin] ,
311+ output : vec ! [ vout] ,
312+ }
313+ } ;
314+
315+ // create an empty to_sign transaction
316+ let mut empty_to_sign = {
317+ // create the appropriate input
318+ let outpoint = OutPoint :: new ( to_spend. txid ( ) , 0 ) ;
319+ let mut input = TxIn :: default ( ) ;
320+ input. previous_output = outpoint;
321+ input. sequence = height;
322+
323+ // create the output
324+ let output = TxOut {
325+ value : 0 ,
326+ script_pubkey : Builder :: new ( )
327+ . push_opcode ( opcodes:: all:: OP_RETURN )
328+ . into_script ( ) ,
329+ } ;
330+
331+ // return resulting transaction
332+ Transaction {
333+ version : 2 ,
334+ lock_time : age,
335+ input : vec ! [ input] ,
336+ output : vec ! [ output] ,
337+ }
276338 } ;
277- let mut bip322_2 = bip322_1. clone ( ) ;
278- let mut bip322_3 = bip322_1. clone ( ) ;
279339
280340 // --------------------------------------------------------------
281341 // Check BIP322Signature::FUll
282342
283- // Generate to_sign transaction
284- let mut to_sign = bip322_1. to_sign ( ) ;
285-
286343 // Generate witness for above wpkh pubkey
287- let mut sighash_cache = bip143:: SigHashCache :: new ( & to_sign ) ;
344+ let mut sighash_cache = bip143:: SigHashCache :: new ( & empty_to_sign ) ;
288345 let message = sighash_cache. signature_hash ( 0 , & p2pkh_script, 0 , SigHashType :: All . into ( ) ) ;
289346 let message = Message :: from_slice ( & message[ ..] ) . unwrap ( ) ;
290347
@@ -294,11 +351,20 @@ mod test {
294351 sig_with_hash. push ( SigHashType :: All as u8 ) ;
295352
296353 let witness: Vec < Vec < u8 > > = vec ! [ sig_with_hash, pk. to_bytes( ) ] ;
297- to_sign . input [ 0 ] . witness = witness. clone ( ) ;
354+ empty_to_sign . input [ 0 ] . witness = witness. clone ( ) ;
298355
299- // Insert signature inside BIP322 structure
300- let bip322_signature = Bip322Signature :: Full ( to_sign) ;
301- bip322_1. insert_sig ( bip322_signature) ;
356+ let bip322_signature = Bip322Signature :: Full ( empty_to_sign) ;
357+
358+ // Create BIP322 Validator
359+ let bip322_1 = Bip322Validator {
360+ message : "Hello World" . to_string ( ) ,
361+ message_challenge : desc. clone ( ) ,
362+ signature : bip322_signature,
363+ age : 0 ,
364+ height : 0 ,
365+ } ;
366+ let mut bip322_2 = bip322_1. clone ( ) ;
367+ let mut bip322_3 = bip322_1. clone ( ) ;
302368
303369 // Check validation
304370 assert_eq ! ( bip322_1. validate( ) . unwrap( ) , true ) ;
@@ -307,7 +373,7 @@ mod test {
307373 // Check Bip322Signature::Simple
308374
309375 // Same structure can be validated with Simple type signature
310- bip322_2. insert_sig ( Bip322Signature :: Simple ( witness) ) ;
376+ bip322_2. signature = Bip322Signature :: Simple ( witness) ;
311377
312378 assert_eq ! ( bip322_2. validate( ) . unwrap( ) , true ) ;
313379
@@ -320,7 +386,7 @@ mod test {
320386 bip322_3. message_challenge = desc. clone ( ) ;
321387
322388 // Create empty to_sign
323- let to_sign = bip322_3. to_sign ( ) ;
389+ let to_sign = bip322_3. empty_to_sign ( ) ;
324390
325391 // Compute SigHash and Signature
326392 let message = to_sign. signature_hash ( 0 , & desc. script_pubkey ( ) , SigHashType :: All as u32 ) ;
@@ -329,9 +395,20 @@ mod test {
329395
330396 // Create Bip322Signature::Legacy
331397 let bip322_sig = Bip322Signature :: Legacy ( signature, pk) ;
332- bip322_3. insert_sig ( bip322_sig) ;
398+ bip322_3. signature = bip322_sig;
333399
334400 // Check validation
335401 assert_eq ! ( bip322_3. validate( ) . unwrap( ) , true ) ;
336402 }
403+
404+ #[ test]
405+ fn test_tagged_hash ( ) {
406+ let mut engine = sha256:: Hash :: engine ( ) ;
407+ let tag_hash = sha256:: Hash :: hash ( "BIP0322-signed-message" . as_bytes ( ) ) ;
408+ engine. input ( & tag_hash[ ..] ) ;
409+ engine. input ( & tag_hash[ ..] ) ;
410+
411+ assert_eq ! ( engine. midstate( ) . into_inner( ) , MIDSTATE ) ;
412+ assert_eq ! ( engine. midstate( ) , MessageTag :: engine( ) . midstate( ) ) ;
413+ }
337414}
0 commit comments