X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Foffers%2Finvoice_request.rs;h=5e3ed40ac08db2b2a8a662c357bb4eb475fb45fc;hb=540534b7166094e9d7dafedfc8ba0704c6617638;hp=02fcd578f949f133e8585ff7bc1b38bc0636f984;hpb=c7b877efdde29ddfce072dc5ba5eef33f344935c;p=rust-lightning diff --git a/lightning/src/offers/invoice_request.rs b/lightning/src/offers/invoice_request.rs index 02fcd578..5e3ed40a 100644 --- a/lightning/src/offers/invoice_request.rs +++ b/lightning/src/offers/invoice_request.rs @@ -25,8 +25,8 @@ //! //! use bitcoin::network::constants::Network; //! use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey}; -//! use core::convert::Infallible; //! use lightning::ln::features::OfferFeatures; +//! use lightning::offers::invoice_request::UnsignedInvoiceRequest; //! use lightning::offers::offer::Offer; //! use lightning::util::ser::Writeable; //! @@ -36,16 +36,19 @@ //! let pubkey = PublicKey::from(keys); //! let mut buffer = Vec::new(); //! +//! # use lightning::offers::invoice_request::{ExplicitPayerId, InvoiceRequestBuilder}; +//! # >::from( //! "lno1qcp4256ypq" //! .parse::()? //! .request_invoice(vec![42; 64], pubkey)? +//! # ) //! .chain(Network::Testnet)? //! .amount_msats(1000)? //! .quantity(5)? //! .payer_note("foo".to_string()) //! .build()? -//! .sign::<_, Infallible>( -//! |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys)) +//! .sign(|message: &UnsignedInvoiceRequest| +//! Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys)) //! ) //! .expect("failed verifying signature") //! .write(&mut buffer) @@ -58,7 +61,6 @@ use bitcoin::blockdata::constants::ChainHash; use bitcoin::network::constants::Network; use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, self}; use bitcoin::secp256k1::schnorr::Signature; -use core::convert::{AsRef, Infallible, TryFrom}; use core::ops::Deref; use crate::sign::EntropySource; use crate::io; @@ -68,8 +70,8 @@ use crate::ln::channelmanager::PaymentId; use crate::ln::features::InvoiceRequestFeatures; use crate::ln::inbound_payment::{ExpandedKey, IV_LEN, Nonce}; use crate::ln::msgs::DecodeError; -use crate::offers::invoice::{BlindedPayInfo, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder}; -use crate::offers::merkle::{SignError, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, self}; +use crate::offers::invoice::BlindedPayInfo; +use crate::offers::merkle::{SignError, SignFn, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, self}; use crate::offers::offer::{Offer, OfferContents, OfferTlvStream, OfferTlvStreamRef}; use crate::offers::parse::{Bolt12ParseError, ParsedMessage, Bolt12SemanticError}; use crate::offers::payer::{PayerContents, PayerTlvStream, PayerTlvStreamRef}; @@ -77,6 +79,16 @@ use crate::offers::signer::{Metadata, MetadataMaterial}; use crate::util::ser::{HighZeroBytesDroppedBigSize, SeekReadable, WithoutLength, Writeable, Writer}; use crate::util::string::PrintableString; +#[cfg(not(c_bindings))] +use { + crate::offers::invoice::{DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder}, +}; +#[cfg(c_bindings)] +use { + crate::offers::invoice::{InvoiceWithDerivedSigningPubkeyBuilder, InvoiceWithExplicitSigningPubkeyBuilder}, +}; + +#[allow(unused_imports)] use crate::prelude::*; /// Tag for the hash function used when signing an [`InvoiceRequest`]'s merkle root. @@ -99,6 +111,34 @@ pub struct InvoiceRequestBuilder<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signi secp_ctx: Option<&'b Secp256k1>, } +/// Builds an [`InvoiceRequest`] from an [`Offer`] for the "offer to be paid" flow. +/// +/// See [module-level documentation] for usage. +/// +/// [module-level documentation]: self +#[cfg(c_bindings)] +pub struct InvoiceRequestWithExplicitPayerIdBuilder<'a, 'b> { + offer: &'a Offer, + invoice_request: InvoiceRequestContentsWithoutPayerId, + payer_id: Option, + payer_id_strategy: core::marker::PhantomData, + secp_ctx: Option<&'b Secp256k1>, +} + +/// Builds an [`InvoiceRequest`] from an [`Offer`] for the "offer to be paid" flow. +/// +/// See [module-level documentation] for usage. +/// +/// [module-level documentation]: self +#[cfg(c_bindings)] +pub struct InvoiceRequestWithDerivedPayerIdBuilder<'a, 'b> { + offer: &'a Offer, + invoice_request: InvoiceRequestContentsWithoutPayerId, + payer_id: Option, + payer_id_strategy: core::marker::PhantomData, + secp_ctx: Option<&'b Secp256k1>, +} + /// 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. @@ -118,6 +158,7 @@ impl PayerIdStrategy for ExplicitPayerId {} impl PayerIdStrategy for DerivedPayerId {} macro_rules! invoice_request_explicit_payer_id_builder_methods { ($self: ident, $self_type: ty) => { + #[cfg_attr(c_bindings, allow(dead_code))] pub(super) fn new(offer: &'a Offer, metadata: Vec, payer_id: PublicKey) -> Self { Self { offer, @@ -128,6 +169,7 @@ macro_rules! invoice_request_explicit_payer_id_builder_methods { ($self: ident, } } + #[cfg_attr(c_bindings, allow(dead_code))] pub(super) fn deriving_metadata( offer: &'a Offer, payer_id: PublicKey, expanded_key: &ExpandedKey, entropy_source: ES, payment_id: PaymentId, @@ -154,10 +196,13 @@ macro_rules! invoice_request_explicit_payer_id_builder_methods { ($self: ident, } } } -macro_rules! invoice_request_derived_payer_id_builder_methods { ($self: ident, $self_type: ty) => { +macro_rules! invoice_request_derived_payer_id_builder_methods { ( + $self: ident, $self_type: ty, $secp_context: ty +) => { + #[cfg_attr(c_bindings, allow(dead_code))] pub(super) fn deriving_payer_id( offer: &'a Offer, expanded_key: &ExpandedKey, entropy_source: ES, - secp_ctx: &'b Secp256k1, payment_id: PaymentId + secp_ctx: &'b Secp256k1<$secp_context>, payment_id: PaymentId ) -> Self where ES::Target: EntropySource { let nonce = Nonce::from_entropy_source(entropy_source); let payment_id = Some(payment_id); @@ -175,13 +220,15 @@ macro_rules! invoice_request_derived_payer_id_builder_methods { ($self: ident, $ /// Builds a signed [`InvoiceRequest`] after checking for valid semantics. pub fn build_and_sign($self: $self_type) -> Result { let (unsigned_invoice_request, keys, secp_ctx) = $self.build_with_checks()?; + #[cfg(c_bindings)] + let mut unsigned_invoice_request = unsigned_invoice_request; debug_assert!(keys.is_some()); let secp_ctx = secp_ctx.unwrap(); let keys = keys.unwrap(); let invoice_request = unsigned_invoice_request - .sign::<_, Infallible>( - |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys)) + .sign(|message: &UnsignedInvoiceRequest| + Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys)) ) .unwrap(); Ok(invoice_request) @@ -189,8 +236,9 @@ macro_rules! invoice_request_derived_payer_id_builder_methods { ($self: ident, $ } } macro_rules! invoice_request_builder_methods { ( - $self: ident, $self_type: ty, $return_type: ty, $return_value: expr + $self: ident, $self_type: ty, $return_type: ty, $return_value: expr, $secp_context: ty $(, $self_mut: tt)? ) => { + #[cfg_attr(c_bindings, allow(dead_code))] fn create_contents(offer: &Offer, metadata: Metadata) -> InvoiceRequestContentsWithoutPayerId { let offer = offer.contents.clone(); InvoiceRequestContentsWithoutPayerId { @@ -213,7 +261,7 @@ macro_rules! invoice_request_builder_methods { ( /// offer. /// /// Successive calls to this method will override the previous setting. - pub(crate) fn chain_hash(mut $self: $self_type, chain: ChainHash) -> Result<$return_type, Bolt12SemanticError> { + pub(crate) fn chain_hash($($self_mut)* $self: $self_type, chain: ChainHash) -> Result<$return_type, Bolt12SemanticError> { if !$self.offer.supports_chain(chain) { return Err(Bolt12SemanticError::UnsupportedChain); } @@ -228,7 +276,7 @@ macro_rules! invoice_request_builder_methods { ( /// Successive calls to this method will override the previous setting. /// /// [`quantity`]: Self::quantity - pub fn amount_msats(mut $self: $self_type, amount_msats: u64) -> Result<$return_type, Bolt12SemanticError> { + pub fn amount_msats($($self_mut)* $self: $self_type, amount_msats: u64) -> Result<$return_type, Bolt12SemanticError> { $self.invoice_request.offer.check_amount_msats_for_quantity( Some(amount_msats), $self.invoice_request.quantity )?; @@ -240,7 +288,7 @@ macro_rules! invoice_request_builder_methods { ( /// does not conform to [`Offer::is_valid_quantity`]. /// /// Successive calls to this method will override the previous setting. - pub fn quantity(mut $self: $self_type, quantity: u64) -> Result<$return_type, Bolt12SemanticError> { + pub fn quantity($($self_mut)* $self: $self_type, quantity: u64) -> Result<$return_type, Bolt12SemanticError> { $self.invoice_request.offer.check_quantity(Some(quantity))?; $self.invoice_request.quantity = Some(quantity); Ok($return_value) @@ -249,13 +297,13 @@ macro_rules! invoice_request_builder_methods { ( /// Sets the [`InvoiceRequest::payer_note`]. /// /// Successive calls to this method will override the previous setting. - pub fn payer_note(mut $self: $self_type, payer_note: String) -> $return_type { + pub fn payer_note($($self_mut)* $self: $self_type, payer_note: String) -> $return_type { $self.invoice_request.payer_note = Some(payer_note); $return_value } - fn build_with_checks(mut $self: $self_type) -> Result< - (UnsignedInvoiceRequest, Option, Option<&'b Secp256k1>), + fn build_with_checks($($self_mut)* $self: $self_type) -> Result< + (UnsignedInvoiceRequest, Option, Option<&'b Secp256k1<$secp_context>>), Bolt12SemanticError > { #[cfg(feature = "std")] { @@ -285,8 +333,8 @@ macro_rules! invoice_request_builder_methods { ( Ok($self.build_without_checks()) } - fn build_without_checks(mut $self: $self_type) -> - (UnsignedInvoiceRequest, Option, Option<&'b Secp256k1>) + fn build_without_checks($($self_mut)* $self: $self_type) -> + (UnsignedInvoiceRequest, Option, Option<&'b Secp256k1<$secp_context>>) { // Create the metadata for stateless verification of a Bolt12Invoice. let mut keys = None; @@ -317,7 +365,10 @@ macro_rules! invoice_request_builder_methods { ( let payer_id = $self.payer_id.unwrap(); let invoice_request = InvoiceRequestContents { + #[cfg(not(c_bindings))] inner: $self.invoice_request, + #[cfg(c_bindings)] + inner: $self.invoice_request.clone(), payer_id, }; let unsigned_invoice_request = UnsignedInvoiceRequest::new($self.offer, invoice_request); @@ -328,29 +379,34 @@ macro_rules! invoice_request_builder_methods { ( #[cfg(test)] macro_rules! invoice_request_builder_test_methods { ( - $self: ident, $self_type: ty, $return_type: ty, $return_value: expr + $self: ident, $self_type: ty, $return_type: ty, $return_value: expr $(, $self_mut: tt)? ) => { - fn chain_unchecked(mut $self: $self_type, network: Network) -> $return_type { + #[cfg_attr(c_bindings, allow(dead_code))] + fn chain_unchecked($($self_mut)* $self: $self_type, network: Network) -> $return_type { let chain = ChainHash::using_genesis_block(network); $self.invoice_request.chain = Some(chain); $return_value } - fn amount_msats_unchecked(mut $self: $self_type, amount_msats: u64) -> $return_type { + #[cfg_attr(c_bindings, allow(dead_code))] + fn amount_msats_unchecked($($self_mut)* $self: $self_type, amount_msats: u64) -> $return_type { $self.invoice_request.amount_msats = Some(amount_msats); $return_value } - fn features_unchecked(mut $self: $self_type, features: InvoiceRequestFeatures) -> $return_type { + #[cfg_attr(c_bindings, allow(dead_code))] + fn features_unchecked($($self_mut)* $self: $self_type, features: InvoiceRequestFeatures) -> $return_type { $self.invoice_request.features = features; $return_value } - fn quantity_unchecked(mut $self: $self_type, quantity: u64) -> $return_type { + #[cfg_attr(c_bindings, allow(dead_code))] + fn quantity_unchecked($($self_mut)* $self: $self_type, quantity: u64) -> $return_type { $self.invoice_request.quantity = Some(quantity); $return_value } + #[cfg_attr(c_bindings, allow(dead_code))] pub(super) fn build_unchecked($self: $self_type) -> UnsignedInvoiceRequest { $self.build_without_checks().0 } @@ -361,14 +417,68 @@ impl<'a, 'b, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, ExplicitPayerI } impl<'a, 'b, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, DerivedPayerId, T> { - invoice_request_derived_payer_id_builder_methods!(self, Self); + invoice_request_derived_payer_id_builder_methods!(self, Self, T); } impl<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, P, T> { - invoice_request_builder_methods!(self, Self, Self, self); + invoice_request_builder_methods!(self, Self, Self, self, T, mut); #[cfg(test)] - invoice_request_builder_test_methods!(self, Self, Self, self); + invoice_request_builder_test_methods!(self, Self, Self, self, mut); +} + +#[cfg(all(c_bindings, not(test)))] +impl<'a, 'b> InvoiceRequestWithExplicitPayerIdBuilder<'a, 'b> { + invoice_request_explicit_payer_id_builder_methods!(self, &mut Self); + invoice_request_builder_methods!(self, &mut Self, (), (), secp256k1::All); +} + +#[cfg(all(c_bindings, test))] +impl<'a, 'b> InvoiceRequestWithExplicitPayerIdBuilder<'a, 'b> { + invoice_request_explicit_payer_id_builder_methods!(self, &mut Self); + invoice_request_builder_methods!(self, &mut Self, &mut Self, self, secp256k1::All); + invoice_request_builder_test_methods!(self, &mut Self, &mut Self, self); +} + +#[cfg(all(c_bindings, not(test)))] +impl<'a, 'b> InvoiceRequestWithDerivedPayerIdBuilder<'a, 'b> { + invoice_request_derived_payer_id_builder_methods!(self, &mut Self, secp256k1::All); + invoice_request_builder_methods!(self, &mut Self, (), (), secp256k1::All); +} + +#[cfg(all(c_bindings, test))] +impl<'a, 'b> InvoiceRequestWithDerivedPayerIdBuilder<'a, 'b> { + invoice_request_derived_payer_id_builder_methods!(self, &mut Self, secp256k1::All); + invoice_request_builder_methods!(self, &mut Self, &mut Self, self, secp256k1::All); + invoice_request_builder_test_methods!(self, &mut Self, &mut Self, self); +} + +#[cfg(c_bindings)] +impl<'a, 'b> From> +for InvoiceRequestBuilder<'a, 'b, ExplicitPayerId, secp256k1::All> { + fn from(builder: InvoiceRequestWithExplicitPayerIdBuilder<'a, 'b>) -> Self { + let InvoiceRequestWithExplicitPayerIdBuilder { + offer, invoice_request, payer_id, payer_id_strategy, secp_ctx, + } = builder; + + Self { + offer, invoice_request, payer_id, payer_id_strategy, secp_ctx, + } + } +} + +#[cfg(c_bindings)] +impl<'a, 'b> From> +for InvoiceRequestBuilder<'a, 'b, DerivedPayerId, secp256k1::All> { + fn from(builder: InvoiceRequestWithDerivedPayerIdBuilder<'a, 'b>) -> Self { + let InvoiceRequestWithDerivedPayerIdBuilder { + offer, invoice_request, payer_id, payer_id_strategy, secp_ctx, + } = builder; + + Self { + offer, invoice_request, payer_id, payer_id_strategy, secp_ctx, + } + } } /// A semantically valid [`InvoiceRequest`] that hasn't been signed. @@ -383,6 +493,30 @@ pub struct UnsignedInvoiceRequest { tagged_hash: TaggedHash, } +/// A function for signing an [`UnsignedInvoiceRequest`]. +pub trait SignInvoiceRequestFn { + /// Signs a [`TaggedHash`] computed over the merkle root of `message`'s TLV stream. + fn sign_invoice_request(&self, message: &UnsignedInvoiceRequest) -> Result; +} + +impl SignInvoiceRequestFn for F +where + F: Fn(&UnsignedInvoiceRequest) -> Result, +{ + fn sign_invoice_request(&self, message: &UnsignedInvoiceRequest) -> Result { + self(message) + } +} + +impl SignFn for F +where + F: SignInvoiceRequestFn, +{ + fn sign(&self, message: &UnsignedInvoiceRequest) -> Result { + self.sign_invoice_request(message) + } +} + impl UnsignedInvoiceRequest { fn new(offer: &Offer, contents: InvoiceRequestContents) -> Self { // Use the offer bytes instead of the offer TLV stream as the offer may have contained @@ -406,16 +540,15 @@ impl UnsignedInvoiceRequest { } } -macro_rules! unsigned_invoice_request_sign_method { ($self: ident, $self_type: ty) => { +macro_rules! unsigned_invoice_request_sign_method { ( + $self: ident, $self_type: ty $(, $self_mut: tt)? +) => { /// Signs the [`TaggedHash`] of the invoice request using the given function. /// /// Note: The hash computation may have included unknown, odd TLV records. - /// - /// This is not exported to bindings users as functions are not yet mapped. - pub fn sign(mut $self: $self_type, sign: F) -> Result> - where - F: FnOnce(&Self) -> Result - { + pub fn sign( + $($self_mut)* $self: $self_type, sign: F + ) -> Result { let pubkey = $self.contents.payer_id; let signature = merkle::sign_message(sign, &$self, pubkey)?; @@ -426,15 +559,27 @@ macro_rules! unsigned_invoice_request_sign_method { ($self: ident, $self_type: t signature_tlv_stream.write(&mut $self.bytes).unwrap(); Ok(InvoiceRequest { + #[cfg(not(c_bindings))] bytes: $self.bytes, + #[cfg(c_bindings)] + bytes: $self.bytes.clone(), + #[cfg(not(c_bindings))] contents: $self.contents, + #[cfg(c_bindings)] + contents: $self.contents.clone(), signature, }) } } } +#[cfg(not(c_bindings))] +impl UnsignedInvoiceRequest { + unsigned_invoice_request_sign_method!(self, Self, mut); +} + +#[cfg(c_bindings)] impl UnsignedInvoiceRequest { - unsigned_invoice_request_sign_method!(self, Self); + unsigned_invoice_request_sign_method!(self, &mut Self); } impl AsRef for UnsignedInvoiceRequest { @@ -547,35 +692,25 @@ impl UnsignedInvoiceRequest { invoice_request_accessors!(self, self.contents); } -impl InvoiceRequest { - offer_accessors!(self, self.contents.inner.offer); - invoice_request_accessors!(self, self.contents); - - /// Signature of the invoice request using [`payer_id`]. - /// - /// [`payer_id`]: Self::payer_id - pub fn signature(&self) -> Signature { - self.signature - } - +macro_rules! invoice_request_respond_with_explicit_signing_pubkey_methods { ( + $self: ident, $contents: expr, $builder: ty +) => { /// Creates an [`InvoiceBuilder`] for the request with the given required fields and using the /// [`Duration`] since [`std::time::SystemTime::UNIX_EPOCH`] as the creation time. /// /// 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<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash - ) -> Result, Bolt12SemanticError> { + &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash + ) -> Result<$builder, Bolt12SemanticError> { let created_at = std::time::SystemTime::now() .duration_since(std::time::SystemTime::UNIX_EPOCH) .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH"); - self.respond_with_no_std(payment_paths, payment_hash, created_at) + $contents.respond_with_no_std(payment_paths, payment_hash, created_at) } /// Creates an [`InvoiceBuilder`] for the request with the given required fields. @@ -599,36 +734,72 @@ impl InvoiceRequest { /// If the originating [`Offer`] was created using [`OfferBuilder::deriving_signing_pubkey`], /// then use [`InvoiceRequest::verify`] and [`VerifiedInvoiceRequest`] methods instead. /// - /// 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 /// [`OfferBuilder::deriving_signing_pubkey`]: crate::offers::offer::OfferBuilder::deriving_signing_pubkey pub fn respond_with_no_std( - &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash, created_at: core::time::Duration - ) -> Result, Bolt12SemanticError> { - if self.invoice_request_features().requires_unknown_bits() { + ) -> Result<$builder, Bolt12SemanticError> { + if $contents.invoice_request_features().requires_unknown_bits() { return Err(Bolt12SemanticError::UnknownRequiredFeatures); } - InvoiceBuilder::for_offer(self, payment_paths, created_at, payment_hash) + <$builder>::for_offer(&$contents, payment_paths, created_at, payment_hash) } +} } +macro_rules! invoice_request_verify_method { ($self: ident, $self_type: ty) => { /// Verifies that the request was for an offer created using the given key. Returns the verified /// request which contains the derived keys needed to sign a [`Bolt12Invoice`] for the request /// if they could be extracted from the metadata. /// /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice - pub fn verify( - self, key: &ExpandedKey, secp_ctx: &Secp256k1 + pub fn verify< + #[cfg(not(c_bindings))] + T: secp256k1::Signing + >( + $self: $self_type, key: &ExpandedKey, + #[cfg(not(c_bindings))] + secp_ctx: &Secp256k1, + #[cfg(c_bindings)] + secp_ctx: &Secp256k1, ) -> Result { - let keys = self.contents.inner.offer.verify(&self.bytes, key, secp_ctx)?; + let keys = $self.contents.inner.offer.verify(&$self.bytes, key, secp_ctx)?; Ok(VerifiedInvoiceRequest { - inner: self, + #[cfg(not(c_bindings))] + inner: $self, + #[cfg(c_bindings)] + inner: $self.clone(), keys, }) } +} } + +#[cfg(not(c_bindings))] +impl InvoiceRequest { + offer_accessors!(self, self.contents.inner.offer); + invoice_request_accessors!(self, self.contents); + invoice_request_respond_with_explicit_signing_pubkey_methods!(self, self, InvoiceBuilder); + invoice_request_verify_method!(self, Self); +} + +#[cfg(c_bindings)] +impl InvoiceRequest { + offer_accessors!(self, self.contents.inner.offer); + invoice_request_accessors!(self, self.contents); + invoice_request_respond_with_explicit_signing_pubkey_methods!(self, self, InvoiceWithExplicitSigningPubkeyBuilder); + invoice_request_verify_method!(self, &Self); +} + +impl InvoiceRequest { + /// Signature of the invoice request using [`payer_id`]. + /// + /// [`payer_id`]: Self::payer_id + pub fn signature(&self) -> Signature { + self.signature + } + pub(crate) fn as_tlv_stream(&self) -> FullInvoiceRequestTlvStreamRef { let (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream) = self.contents.as_tlv_stream(); @@ -639,55 +810,25 @@ impl InvoiceRequest { } } -impl VerifiedInvoiceRequest { - offer_accessors!(self, self.inner.contents.inner.offer); - invoice_request_accessors!(self, self.inner.contents); - - /// Creates an [`InvoiceBuilder`] for the request with the given required fields and using the - /// [`Duration`] since [`std::time::SystemTime::UNIX_EPOCH`] as the creation time. - /// - /// 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. - /// - /// [`Duration`]: core::time::Duration - #[cfg(feature = "std")] - pub fn respond_with( - &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash - ) -> Result, Bolt12SemanticError> { - self.inner.respond_with(payment_paths, payment_hash) - } - - /// Creates an [`InvoiceBuilder`] for the request with the given required fields. - /// - /// 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. - pub fn respond_with_no_std( - &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash, - created_at: core::time::Duration - ) -> Result, Bolt12SemanticError> { - self.inner.respond_with_no_std(payment_paths, payment_hash, created_at) - } - +macro_rules! invoice_request_respond_with_derived_signing_pubkey_methods { ( + $self: ident, $contents: expr, $builder: ty +) => { /// 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 respond_using_derived_keys( - &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash - ) -> Result, Bolt12SemanticError> { + &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash + ) -> Result<$builder, Bolt12SemanticError> { let created_at = std::time::SystemTime::now() .duration_since(std::time::SystemTime::UNIX_EPOCH) .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH"); - self.respond_using_derived_keys_no_std(payment_paths, payment_hash, created_at) + $self.respond_using_derived_keys_no_std(payment_paths, payment_hash, created_at) } /// Creates an [`InvoiceBuilder`] for the request using the given required fields and that uses @@ -696,26 +837,37 @@ impl VerifiedInvoiceRequest { /// /// 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 respond_using_derived_keys_no_std( - &self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash, created_at: core::time::Duration - ) -> Result, Bolt12SemanticError> { - if self.inner.invoice_request_features().requires_unknown_bits() { + ) -> Result<$builder, Bolt12SemanticError> { + if $self.inner.invoice_request_features().requires_unknown_bits() { return Err(Bolt12SemanticError::UnknownRequiredFeatures); } - let keys = match self.keys { + let keys = match $self.keys { None => return Err(Bolt12SemanticError::InvalidMetadata), Some(keys) => keys, }; - InvoiceBuilder::for_offer_using_keys( - &self.inner, payment_paths, created_at, payment_hash, keys + <$builder>::for_offer_using_keys( + &$self.inner, payment_paths, created_at, payment_hash, keys ) } +} } + +impl VerifiedInvoiceRequest { + offer_accessors!(self, self.inner.contents.inner.offer); + invoice_request_accessors!(self, self.inner.contents); + #[cfg(not(c_bindings))] + invoice_request_respond_with_explicit_signing_pubkey_methods!(self, self.inner, InvoiceBuilder); + #[cfg(c_bindings)] + invoice_request_respond_with_explicit_signing_pubkey_methods!(self, self.inner, InvoiceWithExplicitSigningPubkeyBuilder); + #[cfg(not(c_bindings))] + invoice_request_respond_with_derived_signing_pubkey_methods!(self, self.inner, InvoiceBuilder); + #[cfg(c_bindings)] + invoice_request_respond_with_derived_signing_pubkey_methods!(self, self.inner, InvoiceWithDerivedSigningPubkeyBuilder); } impl InvoiceRequestContents { @@ -951,7 +1103,6 @@ mod tests { use bitcoin::blockdata::constants::ChainHash; use bitcoin::network::constants::Network; use bitcoin::secp256k1::{KeyPair, Secp256k1, SecretKey, self}; - use core::convert::{Infallible, TryFrom}; use core::num::NonZeroU64; #[cfg(feature = "std")] use core::time::Duration; @@ -984,6 +1135,8 @@ mod tests { .build().unwrap() .request_invoice(vec![1; 32], payer_pubkey()).unwrap() .build().unwrap(); + #[cfg(c_bindings)] + let mut unsigned_invoice_request = unsigned_invoice_request; let mut buffer = Vec::new(); unsigned_invoice_request.write(&mut buffer).unwrap(); @@ -1579,10 +1732,10 @@ mod tests { .build().unwrap() .request_invoice(vec![1; 32], payer_pubkey()).unwrap() .build().unwrap() - .sign(|_| Err(())) + .sign(fail_sign) { Ok(_) => panic!("expected error"), - Err(e) => assert_eq!(e, SignError::Signing(())), + Err(e) => assert_eq!(e, SignError::Signing), } match OfferBuilder::new("foo".into(), recipient_pubkey()) @@ -1993,8 +2146,8 @@ mod tests { .build().unwrap() .request_invoice(vec![1; 32], keys.public_key()).unwrap() .build().unwrap() - .sign::<_, Infallible>( - |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys)) + .sign(|message: &UnsignedInvoiceRequest| + Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys)) ) .unwrap();