refactor to remove message_digest
authorOrbital <orbitalturtle@protonmail.com>
Fri, 3 Nov 2023 00:50:20 +0000 (19:50 -0500)
committerOrbital <orbitalturtle@protonmail.com>
Tue, 7 Nov 2023 03:29:50 +0000 (21:29 -0600)
We change the Bolt12Invoice struct to carry a tagged hash. Because
message_digest is then only used in one place, we can inline it in
the TaggedHash constructor.

lightning/src/offers/invoice.rs
lightning/src/offers/invoice_request.rs
lightning/src/offers/merkle.rs

index c6fd5d056491560b5b3f630564fe97af93bea372..5bd5a95d8e627a3e69964db540fbffa554bbddf4 100644 (file)
@@ -439,6 +439,7 @@ impl UnsignedBolt12Invoice {
                        bytes: self.bytes,
                        contents: self.contents,
                        signature,
+                       tagged_hash: self.tagged_hash,
                })
        }
 }
@@ -463,6 +464,7 @@ pub struct Bolt12Invoice {
        bytes: Vec<u8>,
        contents: InvoiceContents,
        signature: Signature,
+       tagged_hash: TaggedHash,
 }
 
 /// The contents of an [`Bolt12Invoice`] for responding to either an [`Offer`] or a [`Refund`].
@@ -707,7 +709,7 @@ impl Bolt12Invoice {
 
        /// Hash that was used for signing the invoice.
        pub fn signable_hash(&self) -> [u8; 32] {
-               merkle::message_digest(SIGNATURE_TAG, &self.bytes).as_ref().clone()
+               self.tagged_hash.as_digest().as_ref().clone()
        }
 
        /// Verifies that the invoice was for a request or refund created using the given key. Returns
@@ -1212,11 +1214,11 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Bolt12Invoice {
                        None => return Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSignature)),
                        Some(signature) => signature,
                };
-               let message = TaggedHash::new(SIGNATURE_TAG, &bytes);
+               let tagged_hash = TaggedHash::new(SIGNATURE_TAG, &bytes);
                let pubkey = contents.fields().signing_pubkey;
-               merkle::verify_signature(&signature, message, pubkey)?;
+               merkle::verify_signature(&signature, &tagged_hash, pubkey)?;
 
-               Ok(Bolt12Invoice { bytes, contents, signature })
+               Ok(Bolt12Invoice { bytes, contents, signature, tagged_hash })
        }
 }
 
@@ -1431,7 +1433,7 @@ mod tests {
                assert_eq!(invoice.signing_pubkey(), recipient_pubkey());
 
                let message = TaggedHash::new(SIGNATURE_TAG, &invoice.bytes);
-               assert!(merkle::verify_signature(&invoice.signature, message, recipient_pubkey()).is_ok());
+               assert!(merkle::verify_signature(&invoice.signature, &message, recipient_pubkey()).is_ok());
 
                let digest = Message::from_slice(&invoice.signable_hash()).unwrap();
                let pubkey = recipient_pubkey().into();
@@ -1528,7 +1530,7 @@ mod tests {
                assert_eq!(invoice.signing_pubkey(), recipient_pubkey());
 
                let message = TaggedHash::new(SIGNATURE_TAG, &invoice.bytes);
-               assert!(merkle::verify_signature(&invoice.signature, message, recipient_pubkey()).is_ok());
+               assert!(merkle::verify_signature(&invoice.signature, &message, recipient_pubkey()).is_ok());
 
                assert_eq!(
                        invoice.as_tlv_stream(),
index bd6d58371a9f316cccf6b362cc4825f27171f177..9ddd741a1d5428745e2bd1d840fa14eb4a1eee08 100644 (file)
@@ -876,7 +876,7 @@ impl TryFrom<Vec<u8>> for InvoiceRequest {
                        Some(signature) => signature,
                };
                let message = TaggedHash::new(SIGNATURE_TAG, &bytes);
-               merkle::verify_signature(&signature, message, contents.payer_id)?;
+               merkle::verify_signature(&signature, &message, contents.payer_id)?;
 
                Ok(InvoiceRequest { bytes, contents, signature })
        }
@@ -1013,7 +1013,7 @@ mod tests {
                assert_eq!(invoice_request.payer_note(), None);
 
                let message = TaggedHash::new(SIGNATURE_TAG, &invoice_request.bytes);
-               assert!(merkle::verify_signature(&invoice_request.signature, message, payer_pubkey()).is_ok());
+               assert!(merkle::verify_signature(&invoice_request.signature, &message, payer_pubkey()).is_ok());
 
                assert_eq!(
                        invoice_request.as_tlv_stream(),
index 7390b58fef8ef780a68f58aa50438dcbe1979d71..cf9a2eff4626168982648b99a9dabec1a824d11c 100644 (file)
@@ -30,7 +30,7 @@ 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(Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct TaggedHash(Message);
 
 impl TaggedHash {
@@ -38,7 +38,9 @@ impl TaggedHash {
        ///
        /// 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 {
-               Self(message_digest(tag, tlv_stream))
+               let tag = sha256::Hash::hash(tag.as_bytes());
+               let merkle_root = root_hash(tlv_stream);
+               Self(Message::from_slice(&tagged_hash(tag, merkle_root)).unwrap())
        }
 
        /// Returns the digest to sign.
@@ -91,7 +93,7 @@ where
 /// Verifies the signature with a pubkey over the given message using a tagged hash as the message
 /// digest.
 pub(super) fn verify_signature(
-       signature: &Signature, message: TaggedHash, pubkey: PublicKey,
+       signature: &Signature, message: &TaggedHash, pubkey: PublicKey,
 ) -> Result<(), secp256k1::Error> {
        let digest = message.as_digest();
        let pubkey = pubkey.into();
@@ -99,12 +101,6 @@ pub(super) fn verify_signature(
        secp_ctx.verify_schnorr(signature, digest, &pubkey)
 }
 
-pub(super) fn message_digest(tag: &str, bytes: &[u8]) -> Message {
-       let tag = sha256::Hash::hash(tag.as_bytes());
-       let merkle_root = root_hash(bytes);
-       Message::from_slice(&tagged_hash(tag, merkle_root)).unwrap()
-}
-
 /// Computes a merkle root hash for the given data, which must be a well-formed TLV stream
 /// containing at least one TLV record.
 fn root_hash(data: &[u8]) -> sha256::Hash {