Skip to content

Commit caafced

Browse files
committed
expose more granular data in TaggedHash struct
Expose tag and merkle root fields in the TaggedHash struct.
1 parent 38dfbf9 commit caafced

File tree

1 file changed

+44
-5
lines changed

1 file changed

+44
-5
lines changed

lightning/src/offers/merkle.rs

+44-5
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,40 @@ tlv_stream!(SignatureTlvStream, SignatureTlvStreamRef, SIGNATURE_TYPES, {
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
3333
#[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+
}
3539

3640
impl 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-
let tag = sha256::Hash::hash(tag.as_bytes());
45+
let tag_hash = sha256::Hash::hash(tag.as_bytes());
4246
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+
}
4453
}
4554

4655
/// Returns the digest to sign.
4756
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
4968
}
5069
}
5170

@@ -254,12 +273,13 @@ mod tests {
254273
use super::{SIGNATURE_TYPES, TlvStream, WithoutSignatures};
255274

256275
use bitcoin::hashes::{Hash, sha256};
257-
use bitcoin::secp256k1::{KeyPair, Secp256k1, SecretKey};
276+
use bitcoin::secp256k1::{KeyPair, Message, Secp256k1, SecretKey};
258277
use bitcoin::secp256k1::schnorr::Signature;
259278
use core::convert::Infallible;
260279
use crate::offers::offer::{Amount, OfferBuilder};
261280
use crate::offers::invoice_request::InvoiceRequest;
262281
use crate::offers::parse::Bech32Encode;
282+
use crate::offers::test_utils::{payer_pubkey, recipient_pubkey};
263283
use crate::util::ser::Writeable;
264284

265285
#[test]
@@ -318,6 +338,25 @@ mod tests {
318338
);
319339
}
320340

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+
321360
#[test]
322361
fn skips_encoding_signature_tlv_records() {
323362
let secp_ctx = Secp256k1::new();

0 commit comments

Comments
 (0)