X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;ds=sidebyside;f=lightning%2Fsrc%2Foffers%2Finvoice.rs;h=06215e2d48615ce9784c6e95f534a8eeb7739be9;hb=cc1b505b305c5339496d9aaca28c73b083ba602f;hp=05960642efd111e2f748a805ab2df628e1d24682;hpb=7f641da655810ef78cd61b796b79cbc4707d28bf;p=rust-lightning diff --git a/lightning/src/offers/invoice.rs b/lightning/src/offers/invoice.rs index 05960642..06215e2d 100644 --- a/lightning/src/offers/invoice.rs +++ b/lightning/src/offers/invoice.rs @@ -110,6 +110,7 @@ use core::time::Duration; use crate::io; use crate::blinded_path::BlindedPath; use crate::ln::PaymentHash; +use crate::ln::channelmanager::PaymentId; use crate::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures}; use crate::ln::inbound_payment::ExpandedKey; use crate::ln::msgs::DecodeError; @@ -397,6 +398,11 @@ impl UnsignedBolt12Invoice { Self { bytes, contents, tagged_hash } } + /// Returns the [`TaggedHash`] of the invoice to sign. + pub fn tagged_hash(&self) -> &TaggedHash { + &self.tagged_hash + } + /// Signs the [`TaggedHash`] of the invoice using the given function. /// /// Note: The hash computation may have included unknown, odd TLV records. @@ -690,10 +696,11 @@ impl Bolt12Invoice { merkle::message_digest(SIGNATURE_TAG, &self.bytes).as_ref().clone() } - /// Verifies that the invoice was for a request or refund created using the given key. + /// Verifies that the invoice was for a request or refund created using the given key. Returns + /// the associated [`PaymentId`] to use when sending the payment. pub fn verify( &self, key: &ExpandedKey, secp_ctx: &Secp256k1 - ) -> bool { + ) -> Result { self.contents.verify(TlvStream::new(&self.bytes), key, secp_ctx) } @@ -942,7 +949,7 @@ impl InvoiceContents { fn verify( &self, tlv_stream: TlvStream<'_>, key: &ExpandedKey, secp_ctx: &Secp256k1 - ) -> bool { + ) -> Result { let offer_records = tlv_stream.clone().range(OFFER_TYPES); let invreq_records = tlv_stream.range(INVOICE_REQUEST_TYPES).filter(|record| { match record.r#type { @@ -962,10 +969,7 @@ impl InvoiceContents { }, }; - match signer::verify_metadata(metadata, key, iv_bytes, payer_id, tlv_stream, secp_ctx) { - Ok(_) => true, - Err(()) => false, - } + signer::verify_payer_metadata(metadata, key, iv_bytes, payer_id, tlv_stream, secp_ctx) } fn derives_keys(&self) -> bool { @@ -1184,8 +1188,9 @@ impl TryFrom> for Bolt12Invoice { None => return Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSignature)), Some(signature) => signature, }; + let message = TaggedHash::new(SIGNATURE_TAG, &bytes); let pubkey = contents.fields().signing_pubkey; - merkle::verify_signature(&signature, SIGNATURE_TAG, &bytes, pubkey)?; + merkle::verify_signature(&signature, message, pubkey)?; Ok(Bolt12Invoice { bytes, contents, signature }) } @@ -1288,7 +1293,7 @@ mod tests { use crate::ln::inbound_payment::ExpandedKey; use crate::ln::msgs::DecodeError; use crate::offers::invoice_request::InvoiceRequestTlvStreamRef; - use crate::offers::merkle::{SignError, SignatureTlvStreamRef, self}; + use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, self}; use crate::offers::offer::{Amount, OfferBuilder, OfferTlvStreamRef, Quantity}; use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError}; use crate::offers::payer::PayerTlvStreamRef; @@ -1400,11 +1405,9 @@ mod tests { assert_eq!(invoice.fallbacks(), vec![]); assert_eq!(invoice.invoice_features(), &Bolt12InvoiceFeatures::empty()); assert_eq!(invoice.signing_pubkey(), recipient_pubkey()); - assert!( - merkle::verify_signature( - &invoice.signature, SIGNATURE_TAG, &invoice.bytes, recipient_pubkey() - ).is_ok() - ); + + let message = TaggedHash::new(SIGNATURE_TAG, &invoice.bytes); + 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(); @@ -1499,11 +1502,9 @@ mod tests { assert_eq!(invoice.fallbacks(), vec![]); assert_eq!(invoice.invoice_features(), &Bolt12InvoiceFeatures::empty()); assert_eq!(invoice.signing_pubkey(), recipient_pubkey()); - assert!( - merkle::verify_signature( - &invoice.signature, SIGNATURE_TAG, &invoice.bytes, recipient_pubkey() - ).is_ok() - ); + + let message = TaggedHash::new(SIGNATURE_TAG, &invoice.bytes); + assert!(merkle::verify_signature(&invoice.signature, message, recipient_pubkey()).is_ok()); assert_eq!( invoice.as_tlv_stream(), @@ -1640,36 +1641,31 @@ mod tests { .build().unwrap() .sign(payer_sign).unwrap(); - if let Err(e) = invoice_request - .verify_and_respond_using_derived_keys_no_std( - payment_paths(), payment_hash(), now(), &expanded_key, &secp_ctx - ) - .unwrap() + if let Err(e) = invoice_request.clone() + .verify(&expanded_key, &secp_ctx).unwrap() + .respond_using_derived_keys_no_std(payment_paths(), payment_hash(), now()).unwrap() .build_and_sign(&secp_ctx) { panic!("error building invoice: {:?}", e); } let expanded_key = ExpandedKey::new(&KeyMaterial([41; 32])); - match invoice_request.verify_and_respond_using_derived_keys_no_std( - payment_paths(), payment_hash(), now(), &expanded_key, &secp_ctx - ) { - Ok(_) => panic!("expected error"), - Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidMetadata), - } + assert!(invoice_request.verify(&expanded_key, &secp_ctx).is_err()); let desc = "foo".to_string(); let offer = OfferBuilder ::deriving_signing_pubkey(desc, node_id, &expanded_key, &entropy, &secp_ctx) .amount_msats(1000) + // Omit the path so that node_id is used for the signing pubkey instead of deriving .build().unwrap(); let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap() .build().unwrap() .sign(payer_sign).unwrap(); - match invoice_request.verify_and_respond_using_derived_keys_no_std( - payment_paths(), payment_hash(), now(), &expanded_key, &secp_ctx - ) { + match invoice_request + .verify(&expanded_key, &secp_ctx).unwrap() + .respond_using_derived_keys_no_std(payment_paths(), payment_hash(), now()) + { Ok(_) => panic!("expected error"), Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidMetadata), }