Qualify the BOLT 12 unsigned invoice type
[rust-lightning] / lightning / src / offers / invoice_request.rs
index a7cdbfc0f155157cfa7b7f8e1976953ee750d080..f5cb439b58a006d67b5895fb61a932610ba528f0 100644 (file)
 //!
 //! An [`InvoiceRequest`] can be built from a parsed [`Offer`] as an "offer to be paid". It is
 //! typically constructed by a customer and sent to the merchant who had published the corresponding
-//! offer. The recipient of the request responds with an [`Invoice`].
+//! offer. The recipient of the request responds with a [`Bolt12Invoice`].
 //!
 //! For an "offer for money" (e.g., refund, ATM withdrawal), where an offer doesn't exist as a
 //! precursor, see [`Refund`].
 //!
-//! [`Invoice`]: crate::offers::invoice::Invoice
+//! [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
 //! [`Refund`]: crate::offers::refund::Refund
 //!
 //! ```
@@ -58,19 +58,19 @@ use bitcoin::secp256k1::{KeyPair, Message, PublicKey, Secp256k1, self};
 use bitcoin::secp256k1::schnorr::Signature;
 use core::convert::{Infallible, TryFrom};
 use core::ops::Deref;
-use crate::chain::keysinterface::EntropySource;
+use crate::sign::EntropySource;
 use crate::io;
+use crate::blinded_path::BlindedPath;
 use crate::ln::PaymentHash;
 use crate::ln::features::InvoiceRequestFeatures;
 use crate::ln::inbound_payment::{ExpandedKey, IV_LEN, Nonce};
 use crate::ln::msgs::DecodeError;
-use crate::offers::invoice::{BlindedPayInfo, InvoiceBuilder};
-use crate::offers::merkle::{SignError, SignatureTlvStream, SignatureTlvStreamRef, TlvStream, self};
-use crate::offers::offer::{OFFER_TYPES, Offer, OfferContents, OfferTlvStream, OfferTlvStreamRef};
+use crate::offers::invoice::{BlindedPayInfo, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder};
+use crate::offers::merkle::{SignError, SignatureTlvStream, SignatureTlvStreamRef, self};
+use crate::offers::offer::{Offer, OfferContents, OfferTlvStream, OfferTlvStreamRef};
 use crate::offers::parse::{ParseError, ParsedMessage, SemanticError};
-use crate::offers::payer::{PAYER_METADATA_TYPE, PayerContents, PayerTlvStream, PayerTlvStreamRef};
-use crate::offers::signer::{Metadata, MetadataMaterial, self};
-use crate::onion_message::BlindedPath;
+use crate::offers::payer::{PayerContents, PayerTlvStream, PayerTlvStreamRef};
+use crate::offers::signer::{Metadata, MetadataMaterial};
 use crate::util::ser::{HighZeroBytesDroppedBigSize, SeekReadable, WithoutLength, Writeable, Writer};
 use crate::util::string::PrintableString;
 
@@ -78,12 +78,14 @@ use crate::prelude::*;
 
 const SIGNATURE_TAG: &'static str = concat!("lightning", "invoice_request", "signature");
 
-const IV_BYTES: &[u8; IV_LEN] = b"LDK Invreq ~~~~~";
+pub(super) const IV_BYTES: &[u8; IV_LEN] = b"LDK Invreq ~~~~~";
 
 /// Builds an [`InvoiceRequest`] from an [`Offer`] for the "offer to be paid" flow.
 ///
 /// See [module-level documentation] for usage.
 ///
+/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
+///
 /// [module-level documentation]: self
 pub struct InvoiceRequestBuilder<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signing> {
        offer: &'a Offer,
@@ -94,12 +96,18 @@ pub struct InvoiceRequestBuilder<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signi
 }
 
 /// Indicates how [`InvoiceRequest::payer_id`] will be set.
+///
+/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
 pub trait PayerIdStrategy {}
 
 /// [`InvoiceRequest::payer_id`] will be explicitly set.
+///
+/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
 pub struct ExplicitPayerId {}
 
 /// [`InvoiceRequest::payer_id`] will be derived.
+///
+/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
 pub struct DerivedPayerId {}
 
 impl PayerIdStrategy for ExplicitPayerId {}
@@ -239,7 +247,7 @@ impl<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signing> InvoiceRequestBuilder<'a
        fn build_without_checks(mut self) ->
                (UnsignedInvoiceRequest<'a>, Option<KeyPair>, Option<&'b Secp256k1<T>>)
        {
-               // Create the metadata for stateless verification of aInvoice.
+               // Create the metadata for stateless verification of a Bolt12Invoice.
                let mut keys = None;
                let secp_ctx = self.secp_ctx.clone();
                if self.invoice_request.payer.0.has_derivation_material() {
@@ -340,6 +348,8 @@ pub struct UnsignedInvoiceRequest<'a> {
 
 impl<'a> UnsignedInvoiceRequest<'a> {
        /// Signs the invoice request using the given function.
+       ///
+       /// This is not exported to bindings users as functions are not yet mapped.
        pub fn sign<F, E>(self, sign: F) -> Result<InvoiceRequest, SignError<E>>
        where
                F: FnOnce(&Message) -> Result<Signature, E>
@@ -371,12 +381,12 @@ impl<'a> UnsignedInvoiceRequest<'a> {
        }
 }
 
-/// An `InvoiceRequest` is a request for an [`Invoice`] formulated from an [`Offer`].
+/// An `InvoiceRequest` is a request for a [`Bolt12Invoice`] formulated from an [`Offer`].
 ///
 /// An offer may provide choices such as quantity, amount, chain, features, etc. An invoice request
 /// specifies these such that its recipient can send an invoice for payment.
 ///
-/// [`Invoice`]: crate::offers::invoice::Invoice
+/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
 /// [`Offer`]: crate::offers::offer::Offer
 #[derive(Clone, Debug)]
 #[cfg_attr(test, derive(PartialEq))]
@@ -386,9 +396,9 @@ pub struct InvoiceRequest {
        signature: Signature,
 }
 
-/// The contents of an [`InvoiceRequest`], which may be shared with an [`Invoice`].
+/// The contents of an [`InvoiceRequest`], which may be shared with an [`Bolt12Invoice`].
 ///
-/// [`Invoice`]: crate::offers::invoice::Invoice
+/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
 #[derive(Clone, Debug)]
 #[cfg_attr(test, derive(PartialEq))]
 pub(super) struct InvoiceRequestContents {
@@ -465,11 +475,13 @@ impl InvoiceRequest {
        /// See [`InvoiceRequest::respond_with_no_std`] for further details where the aforementioned
        /// creation time is used for the `created_at` parameter.
        ///
+       /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
+       ///
        /// [`Duration`]: core::time::Duration
        #[cfg(feature = "std")]
        pub fn respond_with(
-               &self, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, payment_hash: PaymentHash
-       ) -> Result<InvoiceBuilder, SemanticError> {
+               &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash
+       ) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, SemanticError> {
                let created_at = std::time::SystemTime::now()
                        .duration_since(std::time::SystemTime::UNIX_EPOCH)
                        .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
@@ -480,8 +492,8 @@ impl InvoiceRequest {
        /// Creates an [`InvoiceBuilder`] for the request with the given required fields.
        ///
        /// Unless [`InvoiceBuilder::relative_expiry`] is set, the invoice will expire two hours after
-       /// `created_at`, which is used to set [`Invoice::created_at`]. Useful for `no-std` builds where
-       /// [`std::time::SystemTime`] is not available.
+       /// `created_at`, which is used to set [`Bolt12Invoice::created_at`]. Useful for `no-std` builds
+       /// where [`std::time::SystemTime`] is not available.
        ///
        /// The caller is expected to remember the preimage of `payment_hash` in order to claim a payment
        /// for the invoice.
@@ -493,11 +505,13 @@ impl InvoiceRequest {
        ///
        /// Errors if the request contains unknown required features.
        ///
-       /// [`Invoice::created_at`]: crate::offers::invoice::Invoice::created_at
+       /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
+       ///
+       /// [`Bolt12Invoice::created_at`]: crate::offers::invoice::Bolt12Invoice::created_at
        pub fn respond_with_no_std(
-               &self, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, payment_hash: PaymentHash,
+               &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
                created_at: core::time::Duration
-       ) -> Result<InvoiceBuilder, SemanticError> {
+       ) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, SemanticError> {
                if self.features().requires_unknown_bits() {
                        return Err(SemanticError::UnknownRequiredFeatures);
                }
@@ -505,11 +519,64 @@ impl InvoiceRequest {
                InvoiceBuilder::for_offer(self, payment_paths, created_at, payment_hash)
        }
 
-       /// Verifies that the request was for an offer created using the given key.
+       /// Creates an [`InvoiceBuilder`] for the request using the given required fields and that uses
+       /// derived signing keys from the originating [`Offer`] to sign the [`Bolt12Invoice`]. Must use
+       /// the same [`ExpandedKey`] as the one used to create the offer.
+       ///
+       /// See [`InvoiceRequest::respond_with`] for further details.
+       ///
+       /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
+       ///
+       /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
+       #[cfg(feature = "std")]
+       pub fn verify_and_respond_using_derived_keys<T: secp256k1::Signing>(
+               &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
+               expanded_key: &ExpandedKey, secp_ctx: &Secp256k1<T>
+       ) -> Result<InvoiceBuilder<DerivedSigningPubkey>, SemanticError> {
+               let created_at = std::time::SystemTime::now()
+                       .duration_since(std::time::SystemTime::UNIX_EPOCH)
+                       .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
+
+               self.verify_and_respond_using_derived_keys_no_std(
+                       payment_paths, payment_hash, created_at, expanded_key, secp_ctx
+               )
+       }
+
+       /// Creates an [`InvoiceBuilder`] for the request using the given required fields and that uses
+       /// derived signing keys from the originating [`Offer`] to sign the [`Bolt12Invoice`]. Must use
+       /// the same [`ExpandedKey`] as the one used to create the offer.
+       ///
+       /// See [`InvoiceRequest::respond_with_no_std`] for further details.
+       ///
+       /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
+       ///
+       /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
+       pub fn verify_and_respond_using_derived_keys_no_std<T: secp256k1::Signing>(
+               &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
+               created_at: core::time::Duration, expanded_key: &ExpandedKey, secp_ctx: &Secp256k1<T>
+       ) -> Result<InvoiceBuilder<DerivedSigningPubkey>, SemanticError> {
+               if self.features().requires_unknown_bits() {
+                       return Err(SemanticError::UnknownRequiredFeatures);
+               }
+
+               let keys = match self.verify(expanded_key, secp_ctx) {
+                       Err(()) => return Err(SemanticError::InvalidMetadata),
+                       Ok(None) => return Err(SemanticError::InvalidMetadata),
+                       Ok(Some(keys)) => keys,
+               };
+
+               InvoiceBuilder::for_offer_using_keys(self, payment_paths, created_at, payment_hash, keys)
+       }
+
+       /// Verifies that the request was for an offer created using the given key. Returns the derived
+       /// keys need to sign an [`Bolt12Invoice`] for the request if they could be extracted from the
+       /// metadata.
+       ///
+       /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
        pub fn verify<T: secp256k1::Signing>(
                &self, key: &ExpandedKey, secp_ctx: &Secp256k1<T>
-       ) -> bool {
-               self.contents.inner.offer.verify(TlvStream::new(&self.bytes), key, secp_ctx)
+       ) -> Result<Option<KeyPair>, ()> {
+               self.contents.inner.offer.verify(&self.bytes, key, secp_ctx)
        }
 
        #[cfg(test)]
@@ -528,24 +595,16 @@ impl InvoiceRequestContents {
                self.inner.metadata()
        }
 
+       pub(super) fn derives_keys(&self) -> bool {
+               self.inner.payer.0.derives_keys()
+       }
+
        pub(super) fn chain(&self) -> ChainHash {
                self.inner.chain()
        }
 
-       /// Verifies that the payer metadata was produced from the invoice request in the TLV stream.
-       pub(super) fn verify<T: secp256k1::Signing>(
-               &self, tlv_stream: TlvStream<'_>, key: &ExpandedKey, secp_ctx: &Secp256k1<T>
-       ) -> bool {
-               let offer_records = tlv_stream.clone().range(OFFER_TYPES);
-               let invreq_records = tlv_stream.range(INVOICE_REQUEST_TYPES).filter(|record| {
-                       match record.r#type {
-                               PAYER_METADATA_TYPE => false, // Should be outside range
-                               INVOICE_REQUEST_PAYER_ID_TYPE => !self.inner.payer.0.derives_keys(),
-                               _ => true,
-                       }
-               });
-               let tlv_stream = offer_records.chain(invreq_records);
-               signer::verify_metadata(self.metadata(), key, IV_BYTES, self.payer_id, tlv_stream, secp_ctx)
+       pub(super) fn payer_id(&self) -> PublicKey {
+               self.payer_id
        }
 
        pub(super) fn as_tlv_stream(&self) -> PartialInvoiceRequestTlvStreamRef {
@@ -602,12 +661,12 @@ impl Writeable for InvoiceRequestContents {
 }
 
 /// Valid type range for invoice_request TLV records.
-const INVOICE_REQUEST_TYPES: core::ops::Range<u64> = 80..160;
+pub(super) const INVOICE_REQUEST_TYPES: core::ops::Range<u64> = 80..160;
 
 /// TLV record type for [`InvoiceRequest::payer_id`] and [`Refund::payer_id`].
 ///
 /// [`Refund::payer_id`]: crate::offers::refund::Refund::payer_id
-const INVOICE_REQUEST_PAYER_ID_TYPE: u64 = 88;
+pub(super) const INVOICE_REQUEST_PAYER_ID_TYPE: u64 = 88;
 
 tlv_stream!(InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef, INVOICE_REQUEST_TYPES, {
        (80, chain: ChainHash),
@@ -726,11 +785,11 @@ mod tests {
        use core::num::NonZeroU64;
        #[cfg(feature = "std")]
        use core::time::Duration;
-       use crate::chain::keysinterface::KeyMaterial;
+       use crate::sign::KeyMaterial;
        use crate::ln::features::InvoiceRequestFeatures;
        use crate::ln::inbound_payment::ExpandedKey;
        use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
-       use crate::offers::invoice::{Invoice, SIGNATURE_TAG as INVOICE_SIGNATURE_TAG};
+       use crate::offers::invoice::{Bolt12Invoice, SIGNATURE_TAG as INVOICE_SIGNATURE_TAG};
        use crate::offers::merkle::{SignError, SignatureTlvStreamRef, self};
        use crate::offers::offer::{Amount, OfferBuilder, OfferTlvStreamRef, Quantity};
        use crate::offers::parse::{ParseError, SemanticError};
@@ -871,7 +930,7 @@ mod tests {
                let mut encoded_invoice = bytes;
                signature_tlv_stream.write(&mut encoded_invoice).unwrap();
 
-               let invoice = Invoice::try_from(encoded_invoice).unwrap();
+               let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
                assert!(!invoice.verify(&expanded_key, &secp_ctx));
 
                // Fails verification with altered metadata
@@ -895,7 +954,7 @@ mod tests {
                let mut encoded_invoice = bytes;
                signature_tlv_stream.write(&mut encoded_invoice).unwrap();
 
-               let invoice = Invoice::try_from(encoded_invoice).unwrap();
+               let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
                assert!(!invoice.verify(&expanded_key, &secp_ctx));
        }
 
@@ -941,7 +1000,7 @@ mod tests {
                let mut encoded_invoice = bytes;
                signature_tlv_stream.write(&mut encoded_invoice).unwrap();
 
-               let invoice = Invoice::try_from(encoded_invoice).unwrap();
+               let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
                assert!(!invoice.verify(&expanded_key, &secp_ctx));
 
                // Fails verification with altered payer id
@@ -965,7 +1024,7 @@ mod tests {
                let mut encoded_invoice = bytes;
                signature_tlv_stream.write(&mut encoded_invoice).unwrap();
 
-               let invoice = Invoice::try_from(encoded_invoice).unwrap();
+               let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
                assert!(!invoice.verify(&expanded_key, &secp_ctx));
        }