Skip to content

Commit 74b35eb

Browse files
committed
expose more granular data in TaggedHash struct
1 parent d2242f6 commit 74b35eb

File tree

3 files changed

+48
-11
lines changed

3 files changed

+48
-11
lines changed

lightning/src/offers/invoice.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ use crate::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures, InvoiceRequ
115115
use crate::ln::inbound_payment::ExpandedKey;
116116
use crate::ln::msgs::DecodeError;
117117
use crate::offers::invoice_request::{INVOICE_REQUEST_PAYER_ID_TYPE, INVOICE_REQUEST_TYPES, IV_BYTES as INVOICE_REQUEST_IV_BYTES, InvoiceRequest, InvoiceRequestContents, InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef};
118-
use crate::offers::merkle::{SignError, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, TlvStream, WithoutSignatures, self};
118+
use crate::offers::merkle::{root_hash, SignError, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, TlvStream, WithoutSignatures, self};
119119
use crate::offers::offer::{Amount, OFFER_TYPES, OfferTlvStream, OfferTlvStreamRef, Quantity};
120120
use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
121121
use crate::offers::payer::{PAYER_METADATA_TYPE, PayerTlvStream, PayerTlvStreamRef};
@@ -707,7 +707,8 @@ impl Bolt12Invoice {
707707

708708
/// Hash that was used for signing the invoice.
709709
pub fn signable_hash(&self) -> [u8; 32] {
710-
merkle::message_digest(SIGNATURE_TAG, &self.bytes).as_ref().clone()
710+
let merkle_root_hash = root_hash(&self.bytes);
711+
merkle::message_digest(SIGNATURE_TAG, merkle_root_hash).as_ref().clone()
711712
}
712713

713714
/// Verifies that the invoice was for a request or refund created using the given key. Returns

lightning/src/offers/invoice_request.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -930,8 +930,9 @@ mod tests {
930930
use super::{InvoiceRequest, InvoiceRequestTlvStreamRef, SIGNATURE_TAG, UnsignedInvoiceRequest};
931931

932932
use bitcoin::blockdata::constants::ChainHash;
933+
use bitcoin::hashes::{sha256, Hash};
933934
use bitcoin::network::constants::Network;
934-
use bitcoin::secp256k1::{KeyPair, Secp256k1, SecretKey, self};
935+
use bitcoin::secp256k1::{KeyPair, Message, Secp256k1, SecretKey, self};
935936
use core::convert::{Infallible, TryFrom};
936937
use core::num::NonZeroU64;
937938
#[cfg(feature = "std")]
@@ -942,7 +943,7 @@ mod tests {
942943
use crate::ln::inbound_payment::ExpandedKey;
943944
use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
944945
use crate::offers::invoice::{Bolt12Invoice, SIGNATURE_TAG as INVOICE_SIGNATURE_TAG};
945-
use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, self};
946+
use crate::offers::merkle::{tagged_hash, SignError, SignatureTlvStreamRef, TaggedHash, self};
946947
use crate::offers::offer::{Amount, OfferBuilder, OfferTlvStreamRef, Quantity};
947948
use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError};
948949
use crate::offers::payer::PayerTlvStreamRef;
@@ -1545,6 +1546,23 @@ mod tests {
15451546
assert_eq!(tlv_stream.payer_note, Some(&String::from("baz")));
15461547
}
15471548

1549+
#[test]
1550+
fn compute_tagged_hash() {
1551+
let unsigned_invoice_request = OfferBuilder::new("foo".into(), recipient_pubkey())
1552+
.amount_msats(1000)
1553+
.build().unwrap()
1554+
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
1555+
.payer_note("bar".into())
1556+
.build().unwrap();
1557+
1558+
// Simply test that we can grab the tag and merkle root exposed by the accessor
1559+
// functions, then use them tosuccesfully compute a tagged hash.
1560+
let taggedhash = unsigned_invoice_request.as_ref();
1561+
let tag = sha256::Hash::hash(taggedhash.tag().as_bytes());
1562+
let _ = Message::from_slice(&tagged_hash(tag, taggedhash.merkle_root()))
1563+
.unwrap();
1564+
}
1565+
15481566
#[test]
15491567
fn fails_signing_invoice_request() {
15501568
match OfferBuilder::new("foo".into(), recipient_pubkey())

lightning/src/offers/merkle.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,38 @@ 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(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-
Self(message_digest(tag, tlv_stream))
45+
let merkle_root = root_hash(tlv_stream);
46+
Self {
47+
tag: tag.to_owned(),
48+
merkle_root,
49+
digest: message_digest(tag, merkle_root),
50+
}
4251
}
4352

4453
/// Returns the digest to sign.
4554
pub fn as_digest(&self) -> &Message {
46-
&self.0
55+
&self.digest
56+
}
57+
58+
/// Returns the tag used in the tagged hash.
59+
pub fn tag(&self) -> &str {
60+
&self.tag
61+
}
62+
63+
/// Returns the merkle root used in the tagged hash.
64+
pub fn merkle_root(&self) -> sha256::Hash {
65+
self.merkle_root
4766
}
4867
}
4968

@@ -99,15 +118,14 @@ pub(super) fn verify_signature(
99118
secp_ctx.verify_schnorr(signature, digest, &pubkey)
100119
}
101120

102-
pub(super) fn message_digest(tag: &str, bytes: &[u8]) -> Message {
121+
pub(super) fn message_digest(tag: &str, merkle_root: sha256::Hash) -> Message {
103122
let tag = sha256::Hash::hash(tag.as_bytes());
104-
let merkle_root = root_hash(bytes);
105123
Message::from_slice(&tagged_hash(tag, merkle_root)).unwrap()
106124
}
107125

108126
/// Computes a merkle root hash for the given data, which must be a well-formed TLV stream
109127
/// containing at least one TLV record.
110-
fn root_hash(data: &[u8]) -> sha256::Hash {
128+
pub(crate) fn root_hash(data: &[u8]) -> sha256::Hash {
111129
let nonce_tag = tagged_hash_engine(sha256::Hash::from_engine({
112130
let first_tlv_record = TlvStream::new(&data[..]).next().unwrap();
113131
let mut engine = sha256::Hash::engine();
@@ -144,7 +162,7 @@ fn root_hash(data: &[u8]) -> sha256::Hash {
144162
*leaves.first().unwrap()
145163
}
146164

147-
fn tagged_hash<T: AsRef<[u8]>>(tag: sha256::Hash, msg: T) -> sha256::Hash {
165+
pub(crate) fn tagged_hash<T: AsRef<[u8]>>(tag: sha256::Hash, msg: T) -> sha256::Hash {
148166
let engine = tagged_hash_engine(tag);
149167
tagged_hash_from_engine(engine, msg)
150168
}

0 commit comments

Comments
 (0)