X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Foffers%2Fmerkle.rs;h=7330541220f625240dee1db5e13539a73aaea824;hb=870a0f14bab32d21c7652773b5d9a37f8e59cd5e;hp=cf9a2eff4626168982648b99a9dabec1a824d11c;hpb=38dfbf99db1bdb40bcaa3bbd7388cd7ed8e734b7;p=rust-lightning diff --git a/lightning/src/offers/merkle.rs b/lightning/src/offers/merkle.rs index cf9a2eff..73305412 100644 --- a/lightning/src/offers/merkle.rs +++ b/lightning/src/offers/merkle.rs @@ -31,21 +31,40 @@ tlv_stream!(SignatureTlvStream, SignatureTlvStreamRef, SIGNATURE_TYPES, { /// [BIP 340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki /// [BOLT 12]: https://github.com/rustyrussell/lightning-rfc/blob/guilt/offers/12-offer-encoding.md#signature-calculation #[derive(Clone, Debug, PartialEq)] -pub struct TaggedHash(Message); +pub struct TaggedHash { + tag: &'static str, + merkle_root: sha256::Hash, + digest: Message, +} impl TaggedHash { /// Creates a tagged hash with the given parameters. /// /// Panics if `tlv_stream` is not a well-formed TLV stream containing at least one TLV record. - pub(super) fn new(tag: &str, tlv_stream: &[u8]) -> Self { - let tag = sha256::Hash::hash(tag.as_bytes()); + pub(super) fn new(tag: &'static str, tlv_stream: &[u8]) -> Self { + let tag_hash = sha256::Hash::hash(tag.as_bytes()); let merkle_root = root_hash(tlv_stream); - Self(Message::from_slice(&tagged_hash(tag, merkle_root)).unwrap()) + let digest = Message::from_slice(&tagged_hash(tag_hash, merkle_root)).unwrap(); + Self { + tag, + merkle_root, + digest, + } } /// Returns the digest to sign. pub fn as_digest(&self) -> &Message { - &self.0 + &self.digest + } + + /// Returns the tag used in the tagged hash. + pub fn tag(&self) -> &str { + &self.tag + } + + /// Returns the merkle root used in the tagged hash. + pub fn merkle_root(&self) -> sha256::Hash { + self.merkle_root } } @@ -254,12 +273,13 @@ mod tests { use super::{SIGNATURE_TYPES, TlvStream, WithoutSignatures}; use bitcoin::hashes::{Hash, sha256}; - use bitcoin::secp256k1::{KeyPair, Secp256k1, SecretKey}; + use bitcoin::secp256k1::{KeyPair, Message, Secp256k1, SecretKey}; use bitcoin::secp256k1::schnorr::Signature; use core::convert::Infallible; use crate::offers::offer::{Amount, OfferBuilder}; use crate::offers::invoice_request::InvoiceRequest; use crate::offers::parse::Bech32Encode; + use crate::offers::test_utils::{payer_pubkey, recipient_pubkey}; use crate::util::ser::Writeable; #[test] @@ -318,6 +338,25 @@ mod tests { ); } + #[test] + fn compute_tagged_hash() { + let unsigned_invoice_request = OfferBuilder::new("foo".into(), recipient_pubkey()) + .amount_msats(1000) + .build().unwrap() + .request_invoice(vec![1; 32], payer_pubkey()).unwrap() + .payer_note("bar".into()) + .build().unwrap(); + + // Simply test that we can grab the tag and merkle root exposed by the accessor + // functions, then use them to succesfully compute a tagged hash. + let tagged_hash = unsigned_invoice_request.as_ref(); + let expected_digest = unsigned_invoice_request.as_ref().as_digest(); + let tag = sha256::Hash::hash(tagged_hash.tag().as_bytes()); + let actual_digest = Message::from_slice(&super::tagged_hash(tag, tagged_hash.merkle_root())) + .unwrap(); + assert_eq!(*expected_digest, actual_digest); + } + #[test] fn skips_encoding_signature_tlv_records() { let secp_ctx = Secp256k1::new();