@@ -30,20 +30,41 @@ tlv_stream!(SignatureTlvStream, SignatureTlvStreamRef, SIGNATURE_TYPES, {
3030///
3131/// [BIP 340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
3232/// [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+ }
3539
3640impl TaggedHash {
3741 /// Creates a tagged hash with the given parameters.
3842 ///
3943 /// Panics if `tlv_stream` is not a well-formed TLV stream containing at least one TLV record.
4044 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+ }
4253 }
4354
4455 /// Returns the digest to sign.
4556 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
4768 }
4869}
4970
@@ -91,20 +112,14 @@ where
91112/// Verifies the signature with a pubkey over the given message using a tagged hash as the message
92113/// digest.
93114pub ( super ) fn verify_signature (
94- signature : & Signature , message : TaggedHash , pubkey : PublicKey ,
115+ signature : & Signature , message : & TaggedHash , pubkey : PublicKey ,
95116) -> Result < ( ) , secp256k1:: Error > {
96117 let digest = message. as_digest ( ) ;
97118 let pubkey = pubkey. into ( ) ;
98119 let secp_ctx = Secp256k1 :: verification_only ( ) ;
99120 secp_ctx. verify_schnorr ( signature, digest, & pubkey)
100121}
101122
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-
108123/// Computes a merkle root hash for the given data, which must be a well-formed TLV stream
109124/// containing at least one TLV record.
110125fn root_hash ( data : & [ u8 ] ) -> sha256:: Hash {
@@ -258,12 +273,13 @@ mod tests {
258273 use super :: { SIGNATURE_TYPES , TlvStream , WithoutSignatures } ;
259274
260275 use bitcoin:: hashes:: { Hash , sha256} ;
261- use bitcoin:: secp256k1:: { KeyPair , Secp256k1 , SecretKey } ;
276+ use bitcoin:: secp256k1:: { KeyPair , Message , Secp256k1 , SecretKey } ;
262277 use bitcoin:: secp256k1:: schnorr:: Signature ;
263278 use core:: convert:: Infallible ;
264279 use crate :: offers:: offer:: { Amount , OfferBuilder } ;
265280 use crate :: offers:: invoice_request:: InvoiceRequest ;
266281 use crate :: offers:: parse:: Bech32Encode ;
282+ use crate :: offers:: test_utils:: { payer_pubkey, recipient_pubkey} ;
267283 use crate :: util:: ser:: Writeable ;
268284
269285 #[ test]
@@ -322,6 +338,25 @@ mod tests {
322338 ) ;
323339 }
324340
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+
325360 #[ test]
326361 fn skips_encoding_signature_tlv_records ( ) {
327362 let secp_ctx = Secp256k1 :: new ( ) ;
0 commit comments