X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Foffers%2Foffer.rs;h=ab95d5b192f6936be0701aefb876089a62054906;hb=ddfeb3f642c7d3f0e4a627dcf552e2a1c2b1e04a;hp=f6aa354b9e4f3d6c9efd2aee4ac47a04c8741dc0;hpb=3dffe54258a374d15571d4ec72f5faa02477b770;p=rust-lightning diff --git a/lightning/src/offers/offer.rs b/lightning/src/offers/offer.rs index f6aa354b..ab95d5b1 100644 --- a/lightning/src/offers/offer.rs +++ b/lightning/src/offers/offer.rs @@ -13,6 +13,8 @@ //! published as a QR code to be scanned by a customer. The customer uses the offer to request an //! invoice from the merchant to be paid. //! +//! # Example +//! //! ``` //! extern crate bitcoin; //! extern crate core; @@ -65,6 +67,14 @@ //! # Ok(()) //! # } //! ``` +//! +//! # Note +//! +//! If constructing an [`Offer`] for use with a [`ChannelManager`], use +//! [`ChannelManager::create_offer_builder`] instead of [`OfferBuilder::new`]. +//! +//! [`ChannelManager`]: crate::ln::channelmanager::ChannelManager +//! [`ChannelManager::create_offer_builder`]: crate::ln::channelmanager::ChannelManager::create_offer_builder use bitcoin::blockdata::constants::ChainHash; use bitcoin::network::constants::Network; @@ -77,6 +87,7 @@ use core::time::Duration; use crate::sign::EntropySource; use crate::io; use crate::blinded_path::BlindedPath; +use crate::ln::channelmanager::PaymentId; use crate::ln::features::OfferFeatures; use crate::ln::inbound_payment::{ExpandedKey, IV_LEN, Nonce}; use crate::ln::msgs::MAX_VALUE_MSAT; @@ -131,6 +142,14 @@ impl<'a> OfferBuilder<'a, ExplicitMetadata, secp256k1::SignOnly> { /// while the offer is valid. /// /// Use a different pubkey per offer to avoid correlating offers. + /// + /// # Note + /// + /// If constructing an [`Offer`] for use with a [`ChannelManager`], use + /// [`ChannelManager::create_offer_builder`] instead of [`OfferBuilder::new`]. + /// + /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager + /// [`ChannelManager::create_offer_builder`]: crate::ln::channelmanager::ChannelManager::create_offer_builder pub fn new(description: String, signing_pubkey: PublicKey) -> Self { OfferBuilder { offer: OfferContents { @@ -169,7 +188,7 @@ impl<'a, T: secp256k1::Signing> OfferBuilder<'a, DerivedMetadata, T> { secp_ctx: &'a Secp256k1 ) -> Self where ES::Target: EntropySource { let nonce = Nonce::from_entropy_source(entropy_source); - let derivation_material = MetadataMaterial::new(nonce, expanded_key, IV_BYTES); + let derivation_material = MetadataMaterial::new(nonce, expanded_key, IV_BYTES, None); let metadata = Metadata::DerivedSigningPubkey(derivation_material); OfferBuilder { offer: OfferContents { @@ -190,9 +209,18 @@ impl<'a, M: MetadataStrategy, T: secp256k1::Signing> OfferBuilder<'a, M, T> { /// See [`Offer::chains`] on how this relates to the payment currency. /// /// Successive calls to this method will add another chain hash. - pub fn chain(mut self, network: Network) -> Self { + pub fn chain(self, network: Network) -> Self { + self.chain_hash(ChainHash::using_genesis_block(network)) + } + + /// Adds the [`ChainHash`] to [`Offer::chains`]. If not called, the chain hash of + /// [`Network::Bitcoin`] is assumed to be the only one supported. + /// + /// See [`Offer::chains`] on how this relates to the payment currency. + /// + /// Successive calls to this method will add another chain hash. + pub(crate) fn chain_hash(mut self, chain: ChainHash) -> Self { let chains = self.offer.chains.get_or_insert_with(Vec::new); - let chain = ChainHash::using_genesis_block(network); if !chains.contains(&chain) { chains.push(chain); } @@ -283,7 +311,7 @@ impl<'a, M: MetadataStrategy, T: secp256k1::Signing> OfferBuilder<'a, M, T> { let mut tlv_stream = self.offer.as_tlv_stream(); debug_assert_eq!(tlv_stream.metadata, None); tlv_stream.metadata = None; - if metadata.derives_keys() { + if metadata.derives_recipient_keys() { tlv_stream.node_id = None; } @@ -365,7 +393,7 @@ macro_rules! offer_accessors { ($self: ident, $contents: expr) => { /// The chains that may be used when paying a requested invoice (e.g., bitcoin mainnet). /// Payments must be denominated in units of the minimal lightning-payable unit (e.g., msats) /// for the selected chain. - pub fn chains(&$self) -> Vec<$crate::bitcoin::blockdata::constants::ChainHash> { + pub fn chains(&$self) -> Vec { $contents.chains() } @@ -417,7 +445,7 @@ macro_rules! offer_accessors { ($self: ident, $contents: expr) => { } /// The public key used by the recipient to sign invoices. - pub fn signing_pubkey(&$self) -> $crate::bitcoin::secp256k1::PublicKey { + pub fn signing_pubkey(&$self) -> bitcoin::secp256k1::PublicKey { $contents.signing_pubkey() } } } @@ -454,10 +482,12 @@ impl Offer { /// Similar to [`Offer::request_invoice`] except it: /// - derives the [`InvoiceRequest::payer_id`] such that a different key can be used for each - /// request, and - /// - sets the [`InvoiceRequest::payer_metadata`] when [`InvoiceRequestBuilder::build`] is - /// called such that it can be used by [`Bolt12Invoice::verify`] to determine if the invoice - /// was requested using a base [`ExpandedKey`] from which the payer id was derived. + /// request, + /// - sets [`InvoiceRequest::payer_metadata`] when [`InvoiceRequestBuilder::build`] is called + /// such that it can be used by [`Bolt12Invoice::verify`] to determine if the invoice was + /// requested using a base [`ExpandedKey`] from which the payer id was derived, and + /// - includes the [`PaymentId`] encrypted in [`InvoiceRequest::payer_metadata`] so that it can + /// be used when sending the payment for the requested invoice. /// /// Useful to protect the sender's privacy. /// @@ -468,7 +498,8 @@ impl Offer { /// [`Bolt12Invoice::verify`]: crate::offers::invoice::Bolt12Invoice::verify /// [`ExpandedKey`]: crate::ln::inbound_payment::ExpandedKey pub fn request_invoice_deriving_payer_id<'a, 'b, ES: Deref, T: secp256k1::Signing>( - &'a self, expanded_key: &ExpandedKey, entropy_source: ES, secp_ctx: &'b Secp256k1 + &'a self, expanded_key: &ExpandedKey, entropy_source: ES, secp_ctx: &'b Secp256k1, + payment_id: PaymentId ) -> Result, Bolt12SemanticError> where ES::Target: EntropySource, @@ -477,7 +508,9 @@ impl Offer { return Err(Bolt12SemanticError::UnknownRequiredFeatures); } - Ok(InvoiceRequestBuilder::deriving_payer_id(self, expanded_key, entropy_source, secp_ctx)) + Ok(InvoiceRequestBuilder::deriving_payer_id( + self, expanded_key, entropy_source, secp_ctx, payment_id + )) } /// Similar to [`Offer::request_invoice_deriving_payer_id`] except uses `payer_id` for the @@ -489,7 +522,8 @@ impl Offer { /// /// [`InvoiceRequest::payer_id`]: crate::offers::invoice_request::InvoiceRequest::payer_id pub fn request_invoice_deriving_metadata( - &self, payer_id: PublicKey, expanded_key: &ExpandedKey, entropy_source: ES + &self, payer_id: PublicKey, expanded_key: &ExpandedKey, entropy_source: ES, + payment_id: PaymentId ) -> Result, Bolt12SemanticError> where ES::Target: EntropySource, @@ -498,7 +532,9 @@ impl Offer { return Err(Bolt12SemanticError::UnknownRequiredFeatures); } - Ok(InvoiceRequestBuilder::deriving_metadata(self, payer_id, expanded_key, entropy_source)) + Ok(InvoiceRequestBuilder::deriving_metadata( + self, payer_id, expanded_key, entropy_source, payment_id + )) } /// Creates an [`InvoiceRequestBuilder`] for the offer with the given `metadata` and `payer_id`, @@ -661,11 +697,13 @@ impl OfferContents { let tlv_stream = TlvStream::new(bytes).range(OFFER_TYPES).filter(|record| { match record.r#type { OFFER_METADATA_TYPE => false, - OFFER_NODE_ID_TYPE => !self.metadata.as_ref().unwrap().derives_keys(), + OFFER_NODE_ID_TYPE => { + !self.metadata.as_ref().unwrap().derives_recipient_keys() + }, _ => true, } }); - signer::verify_metadata( + signer::verify_recipient_metadata( metadata, key, IV_BYTES, self.signing_pubkey(), tlv_stream, secp_ctx ) },