@@ -31,21 +31,40 @@ tlv_stream!(SignatureTlvStream, SignatureTlvStreamRef, SIGNATURE_TYPES, {
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
33
#[ derive( Clone , Debug , PartialEq ) ]
34
- pub struct TaggedHash ( Message ) ;
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
- let tag = sha256:: Hash :: hash ( tag. as_bytes ( ) ) ;
45
+ let tag_hash = sha256:: Hash :: hash ( tag. as_bytes ( ) ) ;
42
46
let merkle_root = root_hash ( tlv_stream) ;
43
- Self ( Message :: from_slice ( & tagged_hash ( tag, merkle_root) ) . unwrap ( ) )
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
+ }
44
53
}
45
54
46
55
/// Returns the digest to sign.
47
56
pub fn as_digest ( & self ) -> & Message {
48
- & 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
49
68
}
50
69
}
51
70
@@ -254,12 +273,13 @@ mod tests {
254
273
use super :: { SIGNATURE_TYPES , TlvStream , WithoutSignatures } ;
255
274
256
275
use bitcoin:: hashes:: { Hash , sha256} ;
257
- use bitcoin:: secp256k1:: { KeyPair , Secp256k1 , SecretKey } ;
276
+ use bitcoin:: secp256k1:: { KeyPair , Message , Secp256k1 , SecretKey } ;
258
277
use bitcoin:: secp256k1:: schnorr:: Signature ;
259
278
use core:: convert:: Infallible ;
260
279
use crate :: offers:: offer:: { Amount , OfferBuilder } ;
261
280
use crate :: offers:: invoice_request:: InvoiceRequest ;
262
281
use crate :: offers:: parse:: Bech32Encode ;
282
+ use crate :: offers:: test_utils:: { payer_pubkey, recipient_pubkey} ;
263
283
use crate :: util:: ser:: Writeable ;
264
284
265
285
#[ test]
@@ -318,6 +338,25 @@ mod tests {
318
338
) ;
319
339
}
320
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
+
321
360
#[ test]
322
361
fn skips_encoding_signature_tlv_records ( ) {
323
362
let secp_ctx = Secp256k1 :: new ( ) ;
0 commit comments