@@ -30,20 +30,41 @@ tlv_stream!(SignatureTlvStream, SignatureTlvStreamRef, SIGNATURE_TYPES, {
30
30
///
31
31
/// [BIP 340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
32
32
/// [BOLT 12]: https://github.com/rustyrussell/lightning-rfc/blob/guilt/offers/12-offer-encoding.md#signature-calculation
33
- #[ derive( Debug , PartialEq ) ]
34
- pub struct TaggedHash ( Message ) ;
33
+ #[ derive( Clone , Debug , PartialEq ) ]
34
+ pub struct TaggedHash {
35
+ tag : String ,
36
+ merkle_root : sha256:: Hash ,
37
+ digest : Message ,
38
+ }
35
39
36
40
impl TaggedHash {
37
41
/// Creates a tagged hash with the given parameters.
38
42
///
39
43
/// Panics if `tlv_stream` is not a well-formed TLV stream containing at least one TLV record.
40
44
pub ( super ) fn new ( tag : & str , tlv_stream : & [ u8 ] ) -> Self {
41
- Self ( message_digest ( tag, tlv_stream) )
45
+ let tag_hash = sha256:: Hash :: hash ( tag. as_bytes ( ) ) ;
46
+ let merkle_root = root_hash ( tlv_stream) ;
47
+ let digest = Message :: from_slice ( & tagged_hash ( tag_hash, merkle_root) ) . unwrap ( ) ;
48
+ Self {
49
+ tag : tag. to_owned ( ) ,
50
+ merkle_root,
51
+ digest,
52
+ }
42
53
}
43
54
44
55
/// Returns the digest to sign.
45
56
pub fn as_digest ( & self ) -> & Message {
46
- & self . 0
57
+ & self . digest
58
+ }
59
+
60
+ /// Returns the tag used in the tagged hash.
61
+ pub fn tag ( & self ) -> & str {
62
+ & self . tag
63
+ }
64
+
65
+ /// Returns the merkle root used in the tagged hash.
66
+ pub fn merkle_root ( & self ) -> sha256:: Hash {
67
+ self . merkle_root
47
68
}
48
69
}
49
70
@@ -91,20 +112,14 @@ where
91
112
/// Verifies the signature with a pubkey over the given message using a tagged hash as the message
92
113
/// digest.
93
114
pub ( super ) fn verify_signature (
94
- signature : & Signature , message : TaggedHash , pubkey : PublicKey ,
115
+ signature : & Signature , message : & TaggedHash , pubkey : PublicKey ,
95
116
) -> Result < ( ) , secp256k1:: Error > {
96
117
let digest = message. as_digest ( ) ;
97
118
let pubkey = pubkey. into ( ) ;
98
119
let secp_ctx = Secp256k1 :: verification_only ( ) ;
99
120
secp_ctx. verify_schnorr ( signature, digest, & pubkey)
100
121
}
101
122
102
- pub ( super ) fn message_digest ( tag : & str , bytes : & [ u8 ] ) -> Message {
103
- let tag = sha256:: Hash :: hash ( tag. as_bytes ( ) ) ;
104
- let merkle_root = root_hash ( bytes) ;
105
- Message :: from_slice ( & tagged_hash ( tag, merkle_root) ) . unwrap ( )
106
- }
107
-
108
123
/// Computes a merkle root hash for the given data, which must be a well-formed TLV stream
109
124
/// containing at least one TLV record.
110
125
fn root_hash ( data : & [ u8 ] ) -> sha256:: Hash {
@@ -258,12 +273,13 @@ mod tests {
258
273
use super :: { SIGNATURE_TYPES , TlvStream , WithoutSignatures } ;
259
274
260
275
use bitcoin:: hashes:: { Hash , sha256} ;
261
- use bitcoin:: secp256k1:: { KeyPair , Secp256k1 , SecretKey } ;
276
+ use bitcoin:: secp256k1:: { KeyPair , Message , Secp256k1 , SecretKey } ;
262
277
use bitcoin:: secp256k1:: schnorr:: Signature ;
263
278
use core:: convert:: Infallible ;
264
279
use crate :: offers:: offer:: { Amount , OfferBuilder } ;
265
280
use crate :: offers:: invoice_request:: InvoiceRequest ;
266
281
use crate :: offers:: parse:: Bech32Encode ;
282
+ use crate :: offers:: test_utils:: { payer_pubkey, recipient_pubkey} ;
267
283
use crate :: util:: ser:: Writeable ;
268
284
269
285
#[ test]
@@ -322,6 +338,25 @@ mod tests {
322
338
) ;
323
339
}
324
340
341
+ #[ test]
342
+ fn compute_tagged_hash ( ) {
343
+ let unsigned_invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
344
+ . amount_msats ( 1000 )
345
+ . build ( ) . unwrap ( )
346
+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
347
+ . payer_note ( "bar" . into ( ) )
348
+ . build ( ) . unwrap ( ) ;
349
+
350
+ // Simply test that we can grab the tag and merkle root exposed by the accessor
351
+ // functions, then use them to succesfully compute a tagged hash.
352
+ let tagged_hash = unsigned_invoice_request. as_ref ( ) ;
353
+ let expected_digest = unsigned_invoice_request. as_ref ( ) . as_digest ( ) ;
354
+ let tag = sha256:: Hash :: hash ( tagged_hash. tag ( ) . as_bytes ( ) ) ;
355
+ let actual_digest = Message :: from_slice ( & super :: tagged_hash ( tag, tagged_hash. merkle_root ( ) ) )
356
+ . unwrap ( ) ;
357
+ assert_eq ! ( * expected_digest, actual_digest) ;
358
+ }
359
+
325
360
#[ test]
326
361
fn skips_encoding_signature_tlv_records ( ) {
327
362
let secp_ctx = Secp256k1 :: new ( ) ;
0 commit comments