]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Disallow user-provided payer_signing_pubkey
authorJeffrey Czyz <jkczyz@gmail.com>
Tue, 20 Aug 2024 20:52:17 +0000 (15:52 -0500)
committerJeffrey Czyz <jkczyz@gmail.com>
Mon, 11 Nov 2024 22:18:11 +0000 (16:18 -0600)
When creating an InvoiceRequests, users may choose to either use a
transient signing pubkey generated by LDK or provide a static one.
Disallow the latter as it allows users to reuse the same pubkey, which
results in poor sender privacy.

fuzz/src/offer_deser.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/outbound_payment.rs
lightning/src/offers/invoice.rs
lightning/src/offers/invoice_request.rs
lightning/src/offers/merkle.rs
lightning/src/offers/offer.rs

index 84b69d3fcd31f5dc82bbf1bdf60faa4036283f25..f903e48851dd2e301003fad2376877b983d0839b 100644 (file)
@@ -8,11 +8,15 @@
 // licenses.
 
 use crate::utils::test_logger;
-use bitcoin::secp256k1::{Keypair, PublicKey, Secp256k1, SecretKey};
+use bitcoin::secp256k1::Secp256k1;
 use core::convert::TryFrom;
-use lightning::offers::invoice_request::UnsignedInvoiceRequest;
+use lightning::ln::channelmanager::PaymentId;
+use lightning::ln::inbound_payment::ExpandedKey;
+use lightning::offers::invoice_request::InvoiceRequest;
+use lightning::offers::nonce::Nonce;
 use lightning::offers::offer::{Amount, Offer, Quantity};
 use lightning::offers::parse::Bolt12SemanticError;
+use lightning::sign::{EntropySource, KeyMaterial};
 use lightning::util::ser::Writeable;
 
 #[inline]
@@ -22,27 +26,30 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
                offer.write(&mut bytes).unwrap();
                assert_eq!(data, bytes);
 
-               let secp_ctx = Secp256k1::new();
-               let keys = Keypair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
-               let pubkey = PublicKey::from(keys);
                let mut buffer = Vec::new();
 
-               if let Ok(invoice_request) = build_response(&offer, pubkey) {
-                       invoice_request
-                               .sign(|message: &UnsignedInvoiceRequest| {
-                                       Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
-                               })
-                               .unwrap()
-                               .write(&mut buffer)
-                               .unwrap();
+               if let Ok(invoice_request) = build_request(&offer) {
+                       invoice_request.write(&mut buffer).unwrap();
                }
        }
 }
 
-fn build_response(
-       offer: &Offer, pubkey: PublicKey,
-) -> Result<UnsignedInvoiceRequest, Bolt12SemanticError> {
-       let mut builder = offer.request_invoice(vec![42; 64], pubkey)?;
+struct FixedEntropy;
+
+impl EntropySource for FixedEntropy {
+       fn get_secure_random_bytes(&self) -> [u8; 32] {
+               [42; 32]
+       }
+}
+
+fn build_request(offer: &Offer) -> Result<InvoiceRequest, Bolt12SemanticError> {
+       let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+       let entropy = FixedEntropy {};
+       let nonce = Nonce::from_entropy_source(&entropy);
+       let secp_ctx = Secp256k1::new();
+       let payment_id = PaymentId([1; 32]);
+
+       let mut builder = offer.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id)?;
 
        builder = match offer.amount() {
                None => builder.amount_msats(1000).unwrap(),
@@ -56,7 +63,7 @@ fn build_response(
                Quantity::One => builder,
        };
 
-       builder.build()
+       builder.build_and_sign()
 }
 
 pub fn offer_deser_test<Out: test_logger::Output>(data: &[u8], out: Out) {
index 4ca95db11b51a1933be20af3d7aac57c9c8c800c..e639e2830e930762b54ceb470fe2a5031f704899 100644 (file)
@@ -9612,7 +9612,7 @@ where
 
                let nonce = Nonce::from_entropy_source(entropy);
                let builder: InvoiceRequestBuilder<DerivedPayerSigningPubkey, secp256k1::All> = offer
-                       .request_invoice_deriving_signing_pubkey(expanded_key, nonce, secp_ctx, payment_id)?
+                       .request_invoice(expanded_key, nonce, secp_ctx, payment_id)?
                        .into();
                let builder = builder.chain_hash(self.chain_hash)?;
 
index c3fde629a831ee23ce2115b2d02682a0a1c38771..70cf6738275953dff0511e06a49da7c719bb89cb 100644 (file)
@@ -2655,6 +2655,8 @@ mod tests {
                let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
                let secp_ctx = Secp256k1::new();
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let nonce = Nonce([0; 16]);
 
                let pending_events = Mutex::new(VecDeque::new());
                let outbound_payments = OutboundPayments::new(new_hash_map());
@@ -2672,9 +2674,8 @@ mod tests {
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), created_at).unwrap()
                        .build().unwrap()
                        .sign(recipient_sign).unwrap();
@@ -2711,15 +2712,16 @@ mod tests {
 
                let pending_events = Mutex::new(VecDeque::new());
                let outbound_payments = OutboundPayments::new(new_hash_map());
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let nonce = Nonce([0; 16]);
                let payment_id = PaymentId([0; 32]);
                let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
 
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .sign(recipient_sign).unwrap();
@@ -2772,15 +2774,16 @@ mod tests {
 
                let pending_events = Mutex::new(VecDeque::new());
                let outbound_payments = OutboundPayments::new(new_hash_map());
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let nonce = Nonce([0; 16]);
                let payment_id = PaymentId([0; 32]);
                let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
 
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .sign(recipient_sign).unwrap();
@@ -2865,7 +2868,7 @@ mod tests {
                OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice_deriving_signing_pubkey(&expanded_key, nonce, &secp_ctx, payment_id)
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id)
                        .unwrap()
                        .build_and_sign()
                        .unwrap()
index b1d7660f2240764b207e06dd9913957fbbb0013b..59100f4cf49318775d94f4f681d4d4426242277c 100644 (file)
@@ -1607,6 +1607,7 @@ mod tests {
        use crate::blinded_path::message::BlindedMessagePath;
        use crate::sign::KeyMaterial;
        use crate::types::features::{Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures};
+       use crate::ln::channelmanager::PaymentId;
        use crate::ln::inbound_payment::ExpandedKey;
        use crate::ln::msgs::DecodeError;
        use crate::offers::invoice_request::{ExperimentalInvoiceRequestTlvStreamRef, InvoiceRequestTlvStreamRef};
@@ -1648,15 +1649,21 @@ mod tests {
 
        #[test]
        fn builds_invoice_for_offer_with_defaults() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+               let encrypted_payment_id = expanded_key.crypt_for_offer(payment_id.0, nonce);
+
                let payment_paths = payment_paths();
                let payment_hash = payment_hash();
                let now = now();
                let unsigned_invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths.clone(), payment_hash, now).unwrap()
                        .build().unwrap();
 
@@ -1664,7 +1671,7 @@ mod tests {
                unsigned_invoice.write(&mut buffer).unwrap();
 
                assert_eq!(unsigned_invoice.bytes, buffer.as_slice());
-               assert_eq!(unsigned_invoice.payer_metadata(), &[1; 32]);
+               assert_eq!(unsigned_invoice.payer_metadata(), &encrypted_payment_id);
                assert_eq!(unsigned_invoice.offer_chains(), Some(vec![ChainHash::using_genesis_block(Network::Bitcoin)]));
                assert_eq!(unsigned_invoice.metadata(), None);
                assert_eq!(unsigned_invoice.amount(), Some(Amount::Bitcoin { amount_msats: 1000 }));
@@ -1679,7 +1686,6 @@ mod tests {
                assert_eq!(unsigned_invoice.amount_msats(), 1000);
                assert_eq!(unsigned_invoice.invoice_request_features(), &InvoiceRequestFeatures::empty());
                assert_eq!(unsigned_invoice.quantity(), None);
-               assert_eq!(unsigned_invoice.payer_signing_pubkey(), payer_pubkey());
                assert_eq!(unsigned_invoice.payer_note(), None);
                assert_eq!(unsigned_invoice.payment_paths(), payment_paths.as_slice());
                assert_eq!(unsigned_invoice.created_at(), now);
@@ -1706,7 +1712,7 @@ mod tests {
                invoice.write(&mut buffer).unwrap();
 
                assert_eq!(invoice.bytes, buffer.as_slice());
-               assert_eq!(invoice.payer_metadata(), &[1; 32]);
+               assert_eq!(invoice.payer_metadata(), &encrypted_payment_id);
                assert_eq!(invoice.offer_chains(), Some(vec![ChainHash::using_genesis_block(Network::Bitcoin)]));
                assert_eq!(invoice.metadata(), None);
                assert_eq!(invoice.amount(), Some(Amount::Bitcoin { amount_msats: 1000 }));
@@ -1721,7 +1727,10 @@ mod tests {
                assert_eq!(invoice.amount_msats(), 1000);
                assert_eq!(invoice.invoice_request_features(), &InvoiceRequestFeatures::empty());
                assert_eq!(invoice.quantity(), None);
-               assert_eq!(invoice.payer_signing_pubkey(), payer_pubkey());
+               assert_eq!(
+                       invoice.verify_using_payer_data(payment_id, nonce, &expanded_key, &secp_ctx),
+                       Ok(payment_id),
+               );
                assert_eq!(invoice.payer_note(), None);
                assert_eq!(invoice.payment_paths(), payment_paths.as_slice());
                assert_eq!(invoice.created_at(), now);
@@ -1744,7 +1753,7 @@ mod tests {
                assert_eq!(
                        invoice.as_tlv_stream(),
                        (
-                               PayerTlvStreamRef { metadata: Some(&vec![1; 32]) },
+                               PayerTlvStreamRef { metadata: Some(&encrypted_payment_id.to_vec()) },
                                OfferTlvStreamRef {
                                        chains: None,
                                        metadata: None,
@@ -1763,7 +1772,7 @@ mod tests {
                                        amount: None,
                                        features: None,
                                        quantity: None,
-                                       payer_id: Some(&payer_pubkey()),
+                                       payer_id: Some(&invoice.payer_signing_pubkey()),
                                        payer_note: None,
                                        paths: None,
                                },
@@ -1902,6 +1911,12 @@ mod tests {
        #[cfg(feature = "std")]
        #[test]
        fn builds_invoice_from_offer_with_expiration() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let future_expiry = Duration::from_secs(u64::max_value());
                let past_expiry = Duration::from_secs(0);
 
@@ -1909,9 +1924,8 @@ mod tests {
                        .amount_msats(1000)
                        .absolute_expiry(future_expiry)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with(payment_paths(), payment_hash())
                        .unwrap()
                        .build()
@@ -1923,9 +1937,8 @@ mod tests {
                        .amount_msats(1000)
                        .absolute_expiry(past_expiry)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build_unchecked()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_unchecked_and_sign()
                        .respond_with(payment_paths(), payment_hash())
                        .unwrap()
                        .build()
@@ -1970,6 +1983,7 @@ mod tests {
                let entropy = FixedEntropy {};
                let nonce = Nonce::from_entropy_source(&entropy);
                let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
 
                let blinded_path = BlindedMessagePath::from_raw(
                        pubkey(40), pubkey(41),
@@ -1981,14 +1995,14 @@ mod tests {
 
                #[cfg(c_bindings)]
                use crate::offers::offer::OfferWithDerivedMetadataBuilder as OfferBuilder;
-               let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
+               let invoice_request = OfferBuilder
+                       ::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
                        .amount_msats(1000)
                        .path(blinded_path)
                        .experimental_foo(42)
-                       .build().unwrap();
-               let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
                        .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
 
                if let Err(e) = invoice_request.clone()
                        .verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).unwrap()
@@ -2003,14 +2017,14 @@ mod tests {
                        invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).is_err()
                );
 
-               let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
+               let invoice_request = OfferBuilder
+                       ::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
                        .amount_msats(1000)
                        // Omit the path so that node_id is used for the signing pubkey instead of deriving it
                        .experimental_foo(42)
-                       .build().unwrap();
-               let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
                        .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
 
                match invoice_request
                        .verify_using_metadata(&expanded_key, &secp_ctx).unwrap()
@@ -2074,15 +2088,20 @@ mod tests {
 
        #[test]
        fn builds_invoice_with_relative_expiry() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let now = now();
                let one_hour = Duration::from_secs(3600);
 
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now).unwrap()
                        .relative_expiry(one_hour.as_secs() as u32)
                        .build().unwrap()
@@ -2096,9 +2115,8 @@ mod tests {
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now - one_hour).unwrap()
                        .relative_expiry(one_hour.as_secs() as u32 - 1)
                        .build().unwrap()
@@ -2112,13 +2130,18 @@ mod tests {
 
        #[test]
        fn builds_invoice_with_amount_from_request() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(1001).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .sign(recipient_sign).unwrap();
@@ -2129,14 +2152,19 @@ mod tests {
 
        #[test]
        fn builds_invoice_with_quantity_from_request() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Unbounded)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .quantity(2).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .sign(recipient_sign).unwrap();
@@ -2148,10 +2176,9 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Unbounded)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .quantity(u64::max_value()).unwrap()
-                       .build_unchecked()
-                       .sign(payer_sign).unwrap()
+                       .build_unchecked_and_sign()
                        .respond_with_no_std(payment_paths(), payment_hash(), now())
                {
                        Ok(_) => panic!("expected error"),
@@ -2161,6 +2188,12 @@ mod tests {
 
        #[test]
        fn builds_invoice_with_fallback_address() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let script = ScriptBuf::new();
                let pubkey = bitcoin::key::PublicKey::new(recipient_pubkey());
                let x_only_pubkey = XOnlyPublicKey::from_keypair(&recipient_keys()).0;
@@ -2169,9 +2202,8 @@ mod tests {
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .fallback_v0_p2wsh(&script.wscript_hash())
                        .fallback_v0_p2wpkh(&pubkey.wpubkey_hash().unwrap())
@@ -2208,15 +2240,20 @@ mod tests {
 
        #[test]
        fn builds_invoice_with_allow_mpp() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let mut features = Bolt12InvoiceFeatures::empty();
                features.set_basic_mpp_optional();
 
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .allow_mpp()
                        .build().unwrap()
@@ -2228,12 +2265,17 @@ mod tests {
 
        #[test]
        fn fails_signing_invoice() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                match OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .sign(fail_sign)
@@ -2245,9 +2287,8 @@ mod tests {
                match OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .sign(payer_sign)
@@ -2259,12 +2300,17 @@ mod tests {
 
        #[test]
        fn parses_invoice_with_payment_paths() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .sign(recipient_sign).unwrap();
@@ -2314,12 +2360,17 @@ mod tests {
 
        #[test]
        fn parses_invoice_with_created_at() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .sign(recipient_sign).unwrap();
@@ -2344,12 +2395,17 @@ mod tests {
 
        #[test]
        fn parses_invoice_with_relative_expiry() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .relative_expiry(3600)
                        .build().unwrap()
@@ -2366,12 +2422,17 @@ mod tests {
 
        #[test]
        fn parses_invoice_with_payment_hash() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .sign(recipient_sign).unwrap();
@@ -2396,12 +2457,17 @@ mod tests {
 
        #[test]
        fn parses_invoice_with_amount() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .sign(recipient_sign).unwrap();
@@ -2424,12 +2490,17 @@ mod tests {
 
        #[test]
        fn parses_invoice_with_allow_mpp() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .allow_mpp()
                        .build().unwrap()
@@ -2450,18 +2521,22 @@ mod tests {
 
        #[test]
        fn parses_invoice_with_fallback_address() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let script = ScriptBuf::new();
                let pubkey = bitcoin::key::PublicKey::new(recipient_pubkey());
                let x_only_pubkey = XOnlyPublicKey::from_keypair(&recipient_keys()).0;
                let tweaked_pubkey = TweakedPublicKey::dangerous_assume_tweaked(x_only_pubkey);
 
-               let offer = OfferBuilder::new(recipient_pubkey())
+               let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
-                       .build().unwrap();
-               let invoice_request = offer
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
                        .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
                #[cfg(not(c_bindings))]
                let invoice_builder = invoice_request
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap();
@@ -2510,12 +2585,17 @@ mod tests {
 
        #[test]
        fn parses_invoice_with_node_id() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .sign(recipient_sign).unwrap();
@@ -2551,6 +2631,12 @@ mod tests {
 
        #[test]
        fn parses_invoice_with_node_id_from_blinded_path() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let paths = vec![
                        BlindedMessagePath::from_raw(
                                pubkey(40), pubkey(41),
@@ -2580,9 +2666,8 @@ mod tests {
                        .path(paths[0].clone())
                        .path(paths[1].clone())
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std_using_signing_pubkey(
                                payment_paths(), payment_hash(), now(), pubkey(46)
                        ).unwrap()
@@ -2602,9 +2687,8 @@ mod tests {
                        .path(paths[0].clone())
                        .path(paths[1].clone())
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std_using_signing_pubkey(
                                payment_paths(), payment_hash(), now(), recipient_pubkey()
                        ).unwrap()
@@ -2624,13 +2708,18 @@ mod tests {
 
        #[test]
        fn fails_parsing_invoice_without_signature() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let mut buffer = Vec::new();
                OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .contents
@@ -2644,12 +2733,17 @@ mod tests {
 
        #[test]
        fn fails_parsing_invoice_with_invalid_signature() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let mut invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .sign(recipient_sign).unwrap();
@@ -2669,6 +2763,11 @@ mod tests {
 
        #[test]
        fn parses_invoice_with_unknown_tlv_records() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let payment_id = PaymentId([1; 32]);
+
                const UNKNOWN_ODD_TYPE: u64 = INVOICE_TYPES.end - 1;
                assert!(UNKNOWN_ODD_TYPE % 2 == 1);
 
@@ -2677,9 +2776,8 @@ mod tests {
                let mut unsigned_invoice = OfferBuilder::new(keys.public_key())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap();
 
@@ -2715,9 +2813,8 @@ mod tests {
                let mut unsigned_invoice = OfferBuilder::new(keys.public_key())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap();
 
@@ -2750,14 +2847,18 @@ mod tests {
 
        #[test]
        fn parses_invoice_with_experimental_tlv_records() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let payment_id = PaymentId([1; 32]);
+
                let secp_ctx = Secp256k1::new();
                let keys = Keypair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let invoice = OfferBuilder::new(keys.public_key())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .experimental_baz(42)
                        .build().unwrap()
@@ -2777,9 +2878,8 @@ mod tests {
                let mut unsigned_invoice = OfferBuilder::new(keys.public_key())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap();
 
@@ -2817,9 +2917,8 @@ mod tests {
                let mut unsigned_invoice = OfferBuilder::new(keys.public_key())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap();
 
@@ -2854,9 +2953,8 @@ mod tests {
                let invoice = OfferBuilder::new(keys.public_key())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .sign(|message: &UnsignedBolt12Invoice|
@@ -2879,12 +2977,17 @@ mod tests {
 
        #[test]
        fn fails_parsing_invoice_with_out_of_range_tlv_records() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .sign(recipient_sign).unwrap();
@@ -2903,12 +3006,17 @@ mod tests {
 
        #[test]
        fn fails_parsing_invoice_with_message_paths() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
                        .build().unwrap()
                        .sign(recipient_sign).unwrap();
index d1ab6d067d90d88ef84156763fbe8ff878998b29..d667565679b585f70beeecc788092715dd9a0882 100644 (file)
 //!
 //! use bitcoin::network::Network;
 //! use bitcoin::secp256k1::{Keypair, PublicKey, Secp256k1, SecretKey};
+//! use lightning::ln::channelmanager::PaymentId;
+//! use lightning::ln::inbound_payment::ExpandedKey;
 //! use lightning::types::features::OfferFeatures;
 //! use lightning::offers::invoice_request::UnsignedInvoiceRequest;
+//! # use lightning::offers::nonce::Nonce;
 //! use lightning::offers::offer::Offer;
+//! # use lightning::sign::EntropySource;
+//! use lightning::sign::KeyMaterial;
 //! use lightning::util::ser::Writeable;
 //!
+//! # struct FixedEntropy;
+//! # impl EntropySource for FixedEntropy {
+//! #     fn get_secure_random_bytes(&self) -> [u8; 32] {
+//! #         [42; 32]
+//! #     }
+//! # }
 //! # fn parse() -> Result<(), lightning::offers::parse::Bolt12ParseError> {
+//! let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+//! # let entropy = FixedEntropy {};
+//! # let nonce = Nonce::from_entropy_source(&entropy);
 //! let secp_ctx = Secp256k1::new();
-//! let keys = Keypair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32])?);
-//! let pubkey = PublicKey::from(keys);
+//! let payment_id = PaymentId([1; 32]);
 //! let mut buffer = Vec::new();
 //!
-//! # use lightning::offers::invoice_request::{ExplicitPayerSigningPubkey, InvoiceRequestBuilder};
-//! # <InvoiceRequestBuilder<ExplicitPayerSigningPubkey, _>>::from(
+//! # use lightning::offers::invoice_request::{DerivedPayerSigningPubkey, InvoiceRequestBuilder};
+//! # <InvoiceRequestBuilder<DerivedPayerSigningPubkey, _>>::from(
 //! "lno1qcp4256ypq"
 //!     .parse::<Offer>()?
-//!     .request_invoice(vec![42; 64], pubkey)?
+//!     .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id)?
 //! # )
 //!     .chain(Network::Testnet)?
 //!     .amount_msats(1000)?
 //!     .quantity(5)?
 //!     .payer_note("foo".to_string())
-//!     .build()?
-//!     .sign(|message: &UnsignedInvoiceRequest|
-//!         Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
-//!     )
-//!     .expect("failed verifying signature")
+//!     .build_and_sign()?
 //!     .write(&mut buffer)
 //!     .unwrap();
 //! # Ok(())
@@ -110,20 +119,6 @@ pub struct InvoiceRequestBuilder<'a, 'b, P: PayerSigningPubkeyStrategy, T: secp2
        secp_ctx: Option<&'b Secp256k1<T>>,
 }
 
-/// 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 InvoiceRequestWithExplicitPayerSigningPubkeyBuilder<'a, 'b> {
-       offer: &'a Offer,
-       invoice_request: InvoiceRequestContentsWithoutPayerSigningPubkey,
-       payer_signing_pubkey: Option<PublicKey>,
-       payer_signing_pubkey_strategy: core::marker::PhantomData<ExplicitPayerSigningPubkey>,
-       secp_ctx: Option<&'b Secp256k1<secp256k1::All>>,
-}
-
 /// Builds an [`InvoiceRequest`] from an [`Offer`] for the "offer to be paid" flow.
 ///
 /// See [module-level documentation] for usage.
@@ -143,57 +138,13 @@ pub struct InvoiceRequestWithDerivedPayerSigningPubkeyBuilder<'a, 'b> {
 /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
 pub trait PayerSigningPubkeyStrategy {}
 
-/// [`InvoiceRequest::payer_signing_pubkey`] will be explicitly set.
-///
-/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
-pub struct ExplicitPayerSigningPubkey {}
-
 /// [`InvoiceRequest::payer_signing_pubkey`] will be derived.
 ///
 /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
 pub struct DerivedPayerSigningPubkey {}
 
-impl PayerSigningPubkeyStrategy for ExplicitPayerSigningPubkey {}
 impl PayerSigningPubkeyStrategy for DerivedPayerSigningPubkey {}
 
-macro_rules! invoice_request_explicit_payer_signing_pubkey_builder_methods { ($self: ident, $self_type: ty) => {
-       #[cfg_attr(c_bindings, allow(dead_code))]
-       pub(super) fn new(offer: &'a Offer, metadata: Vec<u8>, signing_pubkey: PublicKey) -> Self {
-               Self {
-                       offer,
-                       invoice_request: Self::create_contents(offer, Metadata::Bytes(metadata)),
-                       payer_signing_pubkey: Some(signing_pubkey),
-                       payer_signing_pubkey_strategy: core::marker::PhantomData,
-                       secp_ctx: None,
-               }
-       }
-
-       #[cfg_attr(c_bindings, allow(dead_code))]
-       pub(super) fn deriving_metadata(
-               offer: &'a Offer, signing_pubkey: PublicKey, expanded_key: &ExpandedKey, nonce: Nonce,
-               payment_id: PaymentId,
-       ) -> Self {
-               let payment_id = Some(payment_id);
-               let derivation_material = MetadataMaterial::new(nonce, expanded_key, payment_id);
-               let metadata = Metadata::Derived(derivation_material);
-               Self {
-                       offer,
-                       invoice_request: Self::create_contents(offer, metadata),
-                       payer_signing_pubkey: Some(signing_pubkey),
-                       payer_signing_pubkey_strategy: core::marker::PhantomData,
-                       secp_ctx: None,
-               }
-       }
-
-       /// Builds an unsigned [`InvoiceRequest`] after checking for valid semantics. It can be signed
-       /// by [`UnsignedInvoiceRequest::sign`].
-       pub fn build($self: $self_type) -> Result<UnsignedInvoiceRequest, Bolt12SemanticError> {
-               let (unsigned_invoice_request, keys, _) = $self.build_with_checks()?;
-               debug_assert!(keys.is_none());
-               Ok(unsigned_invoice_request)
-       }
-} }
-
 macro_rules! invoice_request_derived_payer_signing_pubkey_builder_methods { (
        $self: ident, $self_type: ty, $secp_context: ty
 ) => {
@@ -381,6 +332,12 @@ macro_rules! invoice_request_builder_methods { (
 macro_rules! invoice_request_builder_test_methods { (
        $self: ident, $self_type: ty, $return_type: ty, $return_value: expr $(, $self_mut: tt)?
 ) => {
+       #[cfg_attr(c_bindings, allow(dead_code))]
+       pub(super) fn payer_metadata($($self_mut)* $self: $self_type, metadata: Metadata) -> $return_type {
+               $self.invoice_request.payer = PayerContents(metadata);
+               $return_value
+       }
+
        #[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);
@@ -406,6 +363,12 @@ macro_rules! invoice_request_builder_test_methods { (
                $return_value
        }
 
+       #[cfg_attr(c_bindings, allow(dead_code))]
+       pub(super) fn payer_signing_pubkey($($self_mut)* $self: $self_type, signing_pubkey: PublicKey) -> $return_type {
+               $self.payer_signing_pubkey = Some(signing_pubkey);
+               $return_value
+       }
+
        #[cfg_attr(c_bindings, allow(dead_code))]
        pub(super) fn experimental_bar($($self_mut)* $self: $self_type, experimental_bar: u64) -> $return_type {
                $self.invoice_request.experimental_bar = Some(experimental_bar);
@@ -416,11 +379,23 @@ macro_rules! invoice_request_builder_test_methods { (
        pub(super) fn build_unchecked($self: $self_type) -> UnsignedInvoiceRequest {
                $self.build_without_checks().0
        }
-} }
 
-impl<'a, 'b, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, ExplicitPayerSigningPubkey, T> {
-       invoice_request_explicit_payer_signing_pubkey_builder_methods!(self, Self);
-}
+       #[cfg_attr(c_bindings, allow(dead_code))]
+       pub(super) fn build_unchecked_and_sign($self: $self_type) -> InvoiceRequest {
+               let (unsigned_invoice_request, keys, secp_ctx) = $self.build_without_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();
+               unsigned_invoice_request
+                       .sign(|message: &UnsignedInvoiceRequest|
+                               Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
+                       )
+                       .unwrap()
+       }
+} }
 
 impl<'a, 'b, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, DerivedPayerSigningPubkey, T> {
        invoice_request_derived_payer_signing_pubkey_builder_methods!(self, Self, T);
@@ -433,19 +408,6 @@ impl<'a, 'b, P: PayerSigningPubkeyStrategy, T: secp256k1::Signing> InvoiceReques
        invoice_request_builder_test_methods!(self, Self, Self, self, mut);
 }
 
-#[cfg(all(c_bindings, not(test)))]
-impl<'a, 'b> InvoiceRequestWithExplicitPayerSigningPubkeyBuilder<'a, 'b> {
-       invoice_request_explicit_payer_signing_pubkey_builder_methods!(self, &mut Self);
-       invoice_request_builder_methods!(self, &mut Self, (), (), secp256k1::All);
-}
-
-#[cfg(all(c_bindings, test))]
-impl<'a, 'b> InvoiceRequestWithExplicitPayerSigningPubkeyBuilder<'a, 'b> {
-       invoice_request_explicit_payer_signing_pubkey_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> InvoiceRequestWithDerivedPayerSigningPubkeyBuilder<'a, 'b> {
        invoice_request_derived_payer_signing_pubkey_builder_methods!(self, &mut Self, secp256k1::All);
@@ -459,20 +421,6 @@ impl<'a, 'b> InvoiceRequestWithDerivedPayerSigningPubkeyBuilder<'a, 'b> {
        invoice_request_builder_test_methods!(self, &mut Self, &mut Self, self);
 }
 
-#[cfg(c_bindings)]
-impl<'a, 'b> From<InvoiceRequestWithExplicitPayerSigningPubkeyBuilder<'a, 'b>>
-for InvoiceRequestBuilder<'a, 'b, ExplicitPayerSigningPubkey, secp256k1::All> {
-       fn from(builder: InvoiceRequestWithExplicitPayerSigningPubkeyBuilder<'a, 'b>) -> Self {
-               let InvoiceRequestWithExplicitPayerSigningPubkeyBuilder {
-                       offer, invoice_request, payer_signing_pubkey, payer_signing_pubkey_strategy, secp_ctx,
-               } = builder;
-
-               Self {
-                       offer, invoice_request, payer_signing_pubkey, payer_signing_pubkey_strategy, secp_ctx,
-               }
-       }
-}
-
 #[cfg(c_bindings)]
 impl<'a, 'b> From<InvoiceRequestWithDerivedPayerSigningPubkeyBuilder<'a, 'b>>
 for InvoiceRequestBuilder<'a, 'b, DerivedPayerSigningPubkey, secp256k1::All> {
@@ -1375,7 +1323,7 @@ mod tests {
        use crate::ln::inbound_payment::ExpandedKey;
        use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
        use crate::offers::invoice::{Bolt12Invoice, SIGNATURE_TAG as INVOICE_SIGNATURE_TAG};
-       use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, TlvStream, self};
+       use crate::offers::merkle::{SignatureTlvStreamRef, TaggedHash, TlvStream, self};
        use crate::offers::nonce::Nonce;
        use crate::offers::offer::{Amount, ExperimentalOfferTlvStreamRef, OfferTlvStreamRef, Quantity};
        #[cfg(not(c_bindings))]
@@ -1394,51 +1342,24 @@ mod tests {
 
        #[test]
        fn builds_invoice_request_with_defaults() {
-               let unsigned_invoice_request = OfferBuilder::new(recipient_pubkey())
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+               let encrypted_payment_id = expanded_key.crypt_for_offer(payment_id.0, nonce);
+
+               let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .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();
-
-               assert_eq!(unsigned_invoice_request.bytes, buffer.as_slice());
-               assert_eq!(unsigned_invoice_request.payer_metadata(), &[1; 32]);
-               assert_eq!(unsigned_invoice_request.chains(), vec![ChainHash::using_genesis_block(Network::Bitcoin)]);
-               assert_eq!(unsigned_invoice_request.metadata(), None);
-               assert_eq!(unsigned_invoice_request.amount(), Some(Amount::Bitcoin { amount_msats: 1000 }));
-               assert_eq!(unsigned_invoice_request.description(), Some(PrintableString("")));
-               assert_eq!(unsigned_invoice_request.offer_features(), &OfferFeatures::empty());
-               assert_eq!(unsigned_invoice_request.absolute_expiry(), None);
-               assert_eq!(unsigned_invoice_request.paths(), &[]);
-               assert_eq!(unsigned_invoice_request.issuer(), None);
-               assert_eq!(unsigned_invoice_request.supported_quantity(), Quantity::One);
-               assert_eq!(unsigned_invoice_request.issuer_signing_pubkey(), Some(recipient_pubkey()));
-               assert_eq!(unsigned_invoice_request.chain(), ChainHash::using_genesis_block(Network::Bitcoin));
-               assert_eq!(unsigned_invoice_request.amount_msats(), None);
-               assert_eq!(unsigned_invoice_request.invoice_request_features(), &InvoiceRequestFeatures::empty());
-               assert_eq!(unsigned_invoice_request.quantity(), None);
-               assert_eq!(unsigned_invoice_request.payer_signing_pubkey(), payer_pubkey());
-               assert_eq!(unsigned_invoice_request.payer_note(), None);
-
-               match UnsignedInvoiceRequest::try_from(buffer) {
-                       Err(e) => panic!("error parsing unsigned invoice request: {:?}", e),
-                       Ok(parsed) => {
-                               assert_eq!(parsed.bytes, unsigned_invoice_request.bytes);
-                               assert_eq!(parsed.tagged_hash, unsigned_invoice_request.tagged_hash);
-                       },
-               }
-
-               let invoice_request = unsigned_invoice_request.sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
 
                assert_eq!(invoice_request.bytes, buffer.as_slice());
-               assert_eq!(invoice_request.payer_metadata(), &[1; 32]);
+               assert_eq!(invoice_request.payer_metadata(), &encrypted_payment_id);
                assert_eq!(invoice_request.chains(), vec![ChainHash::using_genesis_block(Network::Bitcoin)]);
                assert_eq!(invoice_request.metadata(), None);
                assert_eq!(invoice_request.amount(), Some(Amount::Bitcoin { amount_msats: 1000 }));
@@ -1453,16 +1374,19 @@ mod tests {
                assert_eq!(invoice_request.amount_msats(), None);
                assert_eq!(invoice_request.invoice_request_features(), &InvoiceRequestFeatures::empty());
                assert_eq!(invoice_request.quantity(), None);
-               assert_eq!(invoice_request.payer_signing_pubkey(), payer_pubkey());
                assert_eq!(invoice_request.payer_note(), None);
 
                let message = TaggedHash::from_valid_tlv_stream_bytes(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, invoice_request.payer_signing_pubkey(),
+                       ).is_ok()
+               );
 
                assert_eq!(
                        invoice_request.as_tlv_stream(),
                        (
-                               PayerTlvStreamRef { metadata: Some(&vec![1; 32]) },
+                               PayerTlvStreamRef { metadata: Some(&encrypted_payment_id.to_vec()) },
                                OfferTlvStreamRef {
                                        chains: None,
                                        metadata: None,
@@ -1481,7 +1405,7 @@ mod tests {
                                        amount: None,
                                        features: None,
                                        quantity: None,
-                                       payer_id: Some(&payer_pubkey()),
+                                       payer_id: Some(&invoice_request.payer_signing_pubkey()),
                                        payer_note: None,
                                        paths: None,
                                },
@@ -1503,6 +1427,12 @@ mod tests {
        #[cfg(feature = "std")]
        #[test]
        fn builds_invoice_request_from_offer_with_expiration() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let future_expiry = Duration::from_secs(u64::max_value());
                let past_expiry = Duration::from_secs(0);
 
@@ -1510,8 +1440,8 @@ mod tests {
                        .amount_msats(1000)
                        .absolute_expiry(future_expiry)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign()
                {
                        panic!("error building invoice_request: {:?}", e);
                }
@@ -1520,109 +1450,14 @@ mod tests {
                        .amount_msats(1000)
                        .absolute_expiry(past_expiry)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign()
                {
                        Ok(_) => panic!("expected error"),
                        Err(e) => assert_eq!(e, Bolt12SemanticError::AlreadyExpired),
                }
        }
 
-       #[test]
-       fn builds_invoice_request_with_derived_metadata() {
-               let signing_pubkey = payer_pubkey();
-               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
-               let entropy = FixedEntropy {};
-               let nonce = Nonce::from_entropy_source(&entropy);
-               let secp_ctx = Secp256k1::new();
-               let payment_id = PaymentId([1; 32]);
-
-               let offer = OfferBuilder::new(recipient_pubkey())
-                       .amount_msats(1000)
-                       .experimental_foo(42)
-                       .build().unwrap();
-               let invoice_request = offer
-                       .request_invoice_deriving_metadata(signing_pubkey, &expanded_key, nonce, payment_id)
-                       .unwrap()
-                       .experimental_bar(42)
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
-               assert_eq!(invoice_request.payer_signing_pubkey(), payer_pubkey());
-
-               let invoice = invoice_request.respond_with_no_std(payment_paths(), payment_hash(), now())
-                       .unwrap()
-                       .experimental_baz(42)
-                       .build().unwrap()
-                       .sign(recipient_sign).unwrap();
-               match invoice.verify_using_metadata(&expanded_key, &secp_ctx) {
-                       Ok(payment_id) => assert_eq!(payment_id, PaymentId([1; 32])),
-                       Err(()) => panic!("verification failed"),
-               }
-               assert!(
-                       invoice.verify_using_payer_data(payment_id, nonce, &expanded_key, &secp_ctx).is_err()
-               );
-
-               // Fails verification with altered fields
-               let (
-                       payer_tlv_stream, offer_tlv_stream, mut invoice_request_tlv_stream,
-                       mut invoice_tlv_stream, mut signature_tlv_stream, experimental_offer_tlv_stream,
-                       experimental_invoice_request_tlv_stream, experimental_invoice_tlv_stream,
-               ) = invoice.as_tlv_stream();
-               invoice_request_tlv_stream.amount = Some(2000);
-               invoice_tlv_stream.amount = Some(2000);
-
-               let tlv_stream =
-                       (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream);
-               let experimental_tlv_stream = (
-                       experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
-                       experimental_invoice_tlv_stream,
-               );
-               let mut bytes = Vec::new();
-               (&tlv_stream, &experimental_tlv_stream).write(&mut bytes).unwrap();
-
-               let message = TaggedHash::from_valid_tlv_stream_bytes(INVOICE_SIGNATURE_TAG, &bytes);
-               let signature = merkle::sign_message(recipient_sign, &message, recipient_pubkey()).unwrap();
-               signature_tlv_stream.signature = Some(&signature);
-
-               let mut encoded_invoice = Vec::new();
-               (tlv_stream, signature_tlv_stream, experimental_tlv_stream)
-                       .write(&mut encoded_invoice)
-                       .unwrap();
-
-               let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
-               assert!(invoice.verify_using_metadata(&expanded_key, &secp_ctx).is_err());
-
-               // Fails verification with altered metadata
-               let (
-                       mut payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
-                       mut signature_tlv_stream, experimental_offer_tlv_stream,
-                       experimental_invoice_request_tlv_stream, experimental_invoice_tlv_stream,
-               ) = invoice.as_tlv_stream();
-               let metadata = payer_tlv_stream.metadata.unwrap().iter().copied().rev().collect();
-               payer_tlv_stream.metadata = Some(&metadata);
-
-               let tlv_stream =
-                       (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream);
-               let experimental_tlv_stream = (
-                       experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
-                       experimental_invoice_tlv_stream,
-               );
-               let mut bytes = Vec::new();
-               (&tlv_stream, &experimental_tlv_stream).write(&mut bytes).unwrap();
-
-               let message = TaggedHash::from_valid_tlv_stream_bytes(INVOICE_SIGNATURE_TAG, &bytes);
-               let signature = merkle::sign_message(recipient_sign, &message, recipient_pubkey()).unwrap();
-               signature_tlv_stream.signature = Some(&signature);
-
-               let mut encoded_invoice = Vec::new();
-               (tlv_stream, signature_tlv_stream, experimental_tlv_stream)
-                       .write(&mut encoded_invoice)
-                       .unwrap();
-
-               let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
-               assert!(invoice.verify_using_metadata(&expanded_key, &secp_ctx).is_err());
-       }
-
        #[test]
        fn builds_invoice_request_with_derived_payer_signing_pubkey() {
                let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
@@ -1636,8 +1471,7 @@ mod tests {
                        .experimental_foo(42)
                        .build().unwrap();
                let invoice_request = offer
-                       .request_invoice_deriving_signing_pubkey(&expanded_key, nonce, &secp_ctx, payment_id)
-                       .unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .experimental_bar(42)
                        .build_and_sign()
                        .unwrap();
@@ -1719,16 +1553,21 @@ mod tests {
 
        #[test]
        fn builds_invoice_request_with_chain() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let mainnet = ChainHash::using_genesis_block(Network::Bitcoin);
                let testnet = ChainHash::using_genesis_block(Network::Testnet);
 
                let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .chain(Network::Bitcoin).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
                let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
                assert_eq!(invoice_request.chain(), mainnet);
                assert_eq!(tlv_stream.chain, None);
@@ -1737,10 +1576,9 @@ mod tests {
                        .amount_msats(1000)
                        .chain(Network::Testnet)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .chain(Network::Testnet).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
                let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
                assert_eq!(invoice_request.chain(), testnet);
                assert_eq!(tlv_stream.chain, Some(&testnet));
@@ -1750,10 +1588,9 @@ mod tests {
                        .chain(Network::Bitcoin)
                        .chain(Network::Testnet)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .chain(Network::Bitcoin).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
                let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
                assert_eq!(invoice_request.chain(), mainnet);
                assert_eq!(tlv_stream.chain, None);
@@ -1763,11 +1600,10 @@ mod tests {
                        .chain(Network::Bitcoin)
                        .chain(Network::Testnet)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .chain(Network::Bitcoin).unwrap()
                        .chain(Network::Testnet).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
                let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
                assert_eq!(invoice_request.chain(), testnet);
                assert_eq!(tlv_stream.chain, Some(&testnet));
@@ -1776,7 +1612,7 @@ mod tests {
                        .amount_msats(1000)
                        .chain(Network::Testnet)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .chain(Network::Bitcoin)
                {
                        Ok(_) => panic!("expected error"),
@@ -1787,8 +1623,8 @@ mod tests {
                        .amount_msats(1000)
                        .chain(Network::Testnet)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign()
                {
                        Ok(_) => panic!("expected error"),
                        Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedChain),
@@ -1797,13 +1633,18 @@ mod tests {
 
        #[test]
        fn builds_invoice_request_with_amount() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(1000).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
                let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
                assert_eq!(invoice_request.amount_msats(), Some(1000));
                assert_eq!(tlv_stream.amount, Some(1000));
@@ -1811,11 +1652,10 @@ mod tests {
                let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(1001).unwrap()
                        .amount_msats(1000).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
                let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
                assert_eq!(invoice_request.amount_msats(), Some(1000));
                assert_eq!(tlv_stream.amount, Some(1000));
@@ -1823,10 +1663,9 @@ mod tests {
                let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(1001).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
                let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
                assert_eq!(invoice_request.amount_msats(), Some(1001));
                assert_eq!(tlv_stream.amount, Some(1001));
@@ -1834,7 +1673,7 @@ mod tests {
                match OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(999)
                {
                        Ok(_) => panic!("expected error"),
@@ -1845,7 +1684,7 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Unbounded)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .quantity(2).unwrap()
                        .amount_msats(1000)
                {
@@ -1856,7 +1695,7 @@ mod tests {
                match OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(MAX_VALUE_MSAT + 1)
                {
                        Ok(_) => panic!("expected error"),
@@ -1867,10 +1706,10 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Unbounded)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(1000).unwrap()
                        .quantity(2).unwrap()
-                       .build()
+                       .build_and_sign()
                {
                        Ok(_) => panic!("expected error"),
                        Err(e) => assert_eq!(e, Bolt12SemanticError::InsufficientAmount),
@@ -1878,8 +1717,8 @@ mod tests {
 
                match OfferBuilder::new(recipient_pubkey())
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign()
                {
                        Ok(_) => panic!("expected error"),
                        Err(e) => assert_eq!(e, Bolt12SemanticError::MissingAmount),
@@ -1889,9 +1728,9 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Unbounded)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .quantity(u64::max_value()).unwrap()
-                       .build()
+                       .build_and_sign()
                {
                        Ok(_) => panic!("expected error"),
                        Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidAmount),
@@ -1900,13 +1739,18 @@ mod tests {
 
        #[test]
        fn builds_invoice_request_with_features() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .features_unchecked(InvoiceRequestFeatures::unknown())
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
                let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
                assert_eq!(invoice_request.invoice_request_features(), &InvoiceRequestFeatures::unknown());
                assert_eq!(tlv_stream.features, Some(&InvoiceRequestFeatures::unknown()));
@@ -1914,11 +1758,10 @@ mod tests {
                let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .features_unchecked(InvoiceRequestFeatures::unknown())
                        .features_unchecked(InvoiceRequestFeatures::empty())
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
                let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
                assert_eq!(invoice_request.invoice_request_features(), &InvoiceRequestFeatures::empty());
                assert_eq!(tlv_stream.features, None);
@@ -1926,6 +1769,12 @@ mod tests {
 
        #[test]
        fn builds_invoice_request_with_quantity() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let one = NonZeroU64::new(1).unwrap();
                let ten = NonZeroU64::new(10).unwrap();
 
@@ -1933,9 +1782,8 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::One)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
                let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
                assert_eq!(invoice_request.quantity(), None);
                assert_eq!(tlv_stream.quantity, None);
@@ -1944,7 +1792,7 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::One)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(2_000).unwrap()
                        .quantity(2)
                {
@@ -1956,11 +1804,10 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Bounded(ten))
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(10_000).unwrap()
                        .quantity(10).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
                let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
                assert_eq!(invoice_request.amount_msats(), Some(10_000));
                assert_eq!(tlv_stream.amount, Some(10_000));
@@ -1969,7 +1816,7 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Bounded(ten))
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(11_000).unwrap()
                        .quantity(11)
                {
@@ -1981,11 +1828,10 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Unbounded)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(2_000).unwrap()
                        .quantity(2).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
                let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
                assert_eq!(invoice_request.amount_msats(), Some(2_000));
                assert_eq!(tlv_stream.amount, Some(2_000));
@@ -1994,8 +1840,8 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Unbounded)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign()
                {
                        Ok(_) => panic!("expected error"),
                        Err(e) => assert_eq!(e, Bolt12SemanticError::MissingQuantity),
@@ -2005,8 +1851,8 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Bounded(one))
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign()
                {
                        Ok(_) => panic!("expected error"),
                        Err(e) => assert_eq!(e, Bolt12SemanticError::MissingQuantity),
@@ -2015,13 +1861,18 @@ mod tests {
 
        #[test]
        fn builds_invoice_request_with_payer_note() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .payer_note("bar".into())
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
                let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
                assert_eq!(invoice_request.payer_note(), Some(PrintableString("bar")));
                assert_eq!(tlv_stream.payer_note, Some(&String::from("bar")));
@@ -2029,50 +1880,29 @@ mod tests {
                let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .payer_note("bar".into())
                        .payer_note("baz".into())
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
                let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
                assert_eq!(invoice_request.payer_note(), Some(PrintableString("baz")));
                assert_eq!(tlv_stream.payer_note, Some(&String::from("baz")));
        }
 
-       #[test]
-       fn fails_signing_invoice_request() {
-               match OfferBuilder::new(recipient_pubkey())
-                       .amount_msats(1000)
-                       .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(fail_sign)
-               {
-                       Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SignError::Signing),
-               }
-
-               match OfferBuilder::new(recipient_pubkey())
-                       .amount_msats(1000)
-                       .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(recipient_sign)
-               {
-                       Ok(_) => panic!("expected error"),
-                       Err(e) => assert_eq!(e, SignError::Verification(secp256k1::Error::IncorrectSignature)),
-               }
-       }
-
        #[test]
        fn fails_responding_with_unknown_required_features() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                match OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![42; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .features_unchecked(InvoiceRequestFeatures::unknown())
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap()
+                       .build_and_sign().unwrap()
                        .respond_with_no_std(payment_paths(), payment_hash(), now())
                {
                        Ok(_) => panic!("expected error"),
@@ -2082,12 +1912,17 @@ mod tests {
 
        #[test]
        fn parses_invoice_request_with_metadata() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2099,13 +1934,18 @@ mod tests {
 
        #[test]
        fn parses_invoice_request_with_chain() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .chain(Network::Bitcoin).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2117,10 +1957,9 @@ mod tests {
                let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .chain_unchecked(Network::Testnet)
-                       .build_unchecked()
-                       .sign(payer_sign).unwrap();
+                       .build_unchecked_and_sign();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2133,12 +1972,17 @@ mod tests {
 
        #[test]
        fn parses_invoice_request_with_amount() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2149,10 +1993,9 @@ mod tests {
 
                let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(1000).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2163,9 +2006,8 @@ mod tests {
 
                let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build_unchecked()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_unchecked_and_sign();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2178,10 +2020,9 @@ mod tests {
                let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats_unchecked(999)
-                       .build_unchecked()
-                       .sign(payer_sign).unwrap();
+                       .build_unchecked_and_sign();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2195,9 +2036,8 @@ mod tests {
                        .description("foo".to_string())
                        .amount(Amount::Currency { iso4217_code: *b"USD", amount: 1000 })
                        .build_unchecked()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build_unchecked()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_unchecked_and_sign();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2213,10 +2053,9 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Unbounded)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .quantity(u64::max_value()).unwrap()
-                       .build_unchecked()
-                       .sign(payer_sign).unwrap();
+                       .build_unchecked_and_sign();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2229,6 +2068,12 @@ mod tests {
 
        #[test]
        fn parses_invoice_request_with_quantity() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let one = NonZeroU64::new(1).unwrap();
                let ten = NonZeroU64::new(10).unwrap();
 
@@ -2236,9 +2081,8 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::One)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2251,11 +2095,10 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::One)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(2_000).unwrap()
                        .quantity_unchecked(2)
-                       .build_unchecked()
-                       .sign(payer_sign).unwrap();
+                       .build_unchecked_and_sign();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2271,11 +2114,10 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Bounded(ten))
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(10_000).unwrap()
                        .quantity(10).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2288,11 +2130,10 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Bounded(ten))
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(11_000).unwrap()
                        .quantity_unchecked(11)
-                       .build_unchecked()
-                       .sign(payer_sign).unwrap();
+                       .build_unchecked_and_sign();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2306,11 +2147,10 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Unbounded)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .amount_msats(2_000).unwrap()
                        .quantity(2).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2323,9 +2163,8 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Unbounded)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build_unchecked()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_unchecked_and_sign();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2339,9 +2178,8 @@ mod tests {
                        .amount_msats(1000)
                        .supported_quantity(Quantity::Bounded(one))
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build_unchecked()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_unchecked_and_sign();
 
                let mut buffer = Vec::new();
                invoice_request.write(&mut buffer).unwrap();
@@ -2354,11 +2192,17 @@ mod tests {
 
        #[test]
        fn fails_parsing_invoice_request_without_metadata() {
-               let offer = OfferBuilder::new(recipient_pubkey())
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
+               let unsigned_invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
-                       .build().unwrap();
-               let unsigned_invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap();
+                       .build().unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_unchecked();
                let mut tlv_stream = unsigned_invoice_request.contents.as_tlv_stream();
                tlv_stream.0.metadata = None;
 
@@ -2375,11 +2219,17 @@ mod tests {
 
        #[test]
        fn fails_parsing_invoice_request_without_payer_signing_pubkey() {
-               let offer = OfferBuilder::new(recipient_pubkey())
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
+               let unsigned_invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
-                       .build().unwrap();
-               let unsigned_invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap();
+                       .build().unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_unchecked();
                let mut tlv_stream = unsigned_invoice_request.contents.as_tlv_stream();
                tlv_stream.2.payer_id = None;
 
@@ -2394,11 +2244,17 @@ mod tests {
 
        #[test]
        fn fails_parsing_invoice_request_without_issuer_id() {
-               let offer = OfferBuilder::new(recipient_pubkey())
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
+               let unsigned_invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
-                       .build().unwrap();
-               let unsigned_invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap();
+                       .build().unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_unchecked();
                let mut tlv_stream = unsigned_invoice_request.contents.as_tlv_stream();
                tlv_stream.1.issuer_id = None;
 
@@ -2415,12 +2271,18 @@ mod tests {
 
        #[test]
        fn fails_parsing_invoice_request_without_signature() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let mut buffer = Vec::new();
                OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_unchecked()
                        .contents
                        .write(&mut buffer).unwrap();
 
@@ -2432,12 +2294,17 @@ mod tests {
 
        #[test]
        fn fails_parsing_invoice_request_with_invalid_signature() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let mut invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
                let last_signature_byte = invoice_request.bytes.last_mut().unwrap();
                *last_signature_byte = last_signature_byte.wrapping_add(1);
 
@@ -2454,16 +2321,21 @@ mod tests {
 
        #[test]
        fn parses_invoice_request_with_unknown_tlv_records() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let payment_id = PaymentId([1; 32]);
+
                const UNKNOWN_ODD_TYPE: u64 = INVOICE_REQUEST_TYPES.end - 1;
                assert!(UNKNOWN_ODD_TYPE % 2 == 1);
 
                let secp_ctx = Secp256k1::new();
                let keys = Keypair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
-               let mut unsigned_invoice_request = OfferBuilder::new(keys.public_key())
+               let (mut unsigned_invoice_request, payer_keys, _) = OfferBuilder::new(keys.public_key())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], keys.public_key()).unwrap()
-                       .build().unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_without_checks();
 
                let mut unknown_bytes = Vec::new();
                BigSize(UNKNOWN_ODD_TYPE).write(&mut unknown_bytes).unwrap();
@@ -2479,6 +2351,7 @@ mod tests {
                unsigned_invoice_request.tagged_hash =
                        TaggedHash::from_valid_tlv_stream_bytes(SIGNATURE_TAG, &unsigned_invoice_request.bytes);
 
+               let keys = payer_keys.unwrap();
                let invoice_request = unsigned_invoice_request
                        .sign(|message: &UnsignedInvoiceRequest|
                                Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
@@ -2496,11 +2369,11 @@ mod tests {
                const UNKNOWN_EVEN_TYPE: u64 = INVOICE_REQUEST_TYPES.end - 2;
                assert!(UNKNOWN_EVEN_TYPE % 2 == 0);
 
-               let mut unsigned_invoice_request = OfferBuilder::new(keys.public_key())
+               let (mut unsigned_invoice_request, payer_keys, _) = OfferBuilder::new(keys.public_key())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], keys.public_key()).unwrap()
-                       .build().unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_without_checks();
 
                let mut unknown_bytes = Vec::new();
                BigSize(UNKNOWN_EVEN_TYPE).write(&mut unknown_bytes).unwrap();
@@ -2516,6 +2389,7 @@ mod tests {
                unsigned_invoice_request.tagged_hash =
                        TaggedHash::from_valid_tlv_stream_bytes(SIGNATURE_TAG, &unsigned_invoice_request.bytes);
 
+               let keys = payer_keys.unwrap();
                let invoice_request = unsigned_invoice_request
                        .sign(|message: &UnsignedInvoiceRequest|
                                Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
@@ -2533,16 +2407,21 @@ mod tests {
 
        #[test]
        fn parses_invoice_request_with_experimental_tlv_records() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let payment_id = PaymentId([1; 32]);
+
                const UNKNOWN_ODD_TYPE: u64 = EXPERIMENTAL_INVOICE_REQUEST_TYPES.start + 1;
                assert!(UNKNOWN_ODD_TYPE % 2 == 1);
 
                let secp_ctx = Secp256k1::new();
                let keys = Keypair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
-               let mut unsigned_invoice_request = OfferBuilder::new(keys.public_key())
+               let (mut unsigned_invoice_request, payer_keys, _) = OfferBuilder::new(keys.public_key())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], keys.public_key()).unwrap()
-                       .build().unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_without_checks();
 
                let mut unknown_bytes = Vec::new();
                BigSize(UNKNOWN_ODD_TYPE).write(&mut unknown_bytes).unwrap();
@@ -2561,6 +2440,7 @@ mod tests {
                unsigned_invoice_request.tagged_hash =
                        TaggedHash::from_tlv_stream(SIGNATURE_TAG, tlv_stream);
 
+               let keys = payer_keys.unwrap();
                let invoice_request = unsigned_invoice_request
                        .sign(|message: &UnsignedInvoiceRequest|
                                Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
@@ -2578,11 +2458,11 @@ mod tests {
                const UNKNOWN_EVEN_TYPE: u64 = EXPERIMENTAL_INVOICE_REQUEST_TYPES.start;
                assert!(UNKNOWN_EVEN_TYPE % 2 == 0);
 
-               let mut unsigned_invoice_request = OfferBuilder::new(keys.public_key())
+               let (mut unsigned_invoice_request, payer_keys, _) = OfferBuilder::new(keys.public_key())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], keys.public_key()).unwrap()
-                       .build().unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_without_checks();
 
                let mut unknown_bytes = Vec::new();
                BigSize(UNKNOWN_EVEN_TYPE).write(&mut unknown_bytes).unwrap();
@@ -2601,6 +2481,7 @@ mod tests {
                unsigned_invoice_request.tagged_hash =
                        TaggedHash::from_tlv_stream(SIGNATURE_TAG, tlv_stream);
 
+               let keys = payer_keys.unwrap();
                let invoice_request = unsigned_invoice_request
                        .sign(|message: &UnsignedInvoiceRequest|
                                Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
@@ -2618,12 +2499,8 @@ mod tests {
                let invoice_request = OfferBuilder::new(keys.public_key())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], keys.public_key()).unwrap()
-                       .build().unwrap()
-                       .sign(|message: &UnsignedInvoiceRequest|
-                               Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
-                       )
-                       .unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
 
                let mut encoded_invoice_request = Vec::new();
                invoice_request.write(&mut encoded_invoice_request).unwrap();
@@ -2640,18 +2517,17 @@ mod tests {
 
        #[test]
        fn fails_parsing_invoice_request_with_out_of_range_tlv_records() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
                let secp_ctx = Secp256k1::new();
-               let keys = Keypair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
+               let payment_id = PaymentId([1; 32]);
 
-               let invoice_request = OfferBuilder::new(keys.public_key())
+               let invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], keys.public_key()).unwrap()
-                       .build().unwrap()
-                       .sign(|message: &UnsignedInvoiceRequest|
-                               Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
-                       )
-                       .unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
 
                let mut encoded_invoice_request = Vec::new();
                invoice_request.write(&mut encoded_invoice_request).unwrap();
@@ -2683,6 +2559,7 @@ mod tests {
                let entropy = FixedEntropy {};
                let nonce = Nonce::from_entropy_source(&entropy);
                let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
 
                #[cfg(c_bindings)]
                use crate::offers::offer::OfferWithDerivedMetadataBuilder as OfferBuilder;
@@ -2693,12 +2570,12 @@ mod tests {
                        .build().unwrap();
                assert_eq!(offer.issuer_signing_pubkey(), Some(node_id));
 
-               let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+               let invoice_request = offer
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .chain(Network::Testnet).unwrap()
                        .quantity(1).unwrap()
                        .payer_note("0".repeat(PAYER_NOTE_LIMIT * 2))
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .build_and_sign().unwrap();
                match invoice_request.verify_using_metadata(&expanded_key, &secp_ctx) {
                        Ok(invoice_request) => {
                                let fields = invoice_request.fields();
@@ -2706,7 +2583,7 @@ mod tests {
                                assert_eq!(
                                        fields,
                                        InvoiceRequestFields {
-                                               payer_signing_pubkey: payer_pubkey(),
+                                               payer_signing_pubkey: invoice_request.payer_signing_pubkey(),
                                                quantity: Some(1),
                                                payer_note_truncated: Some(UntrustedString("0".repeat(PAYER_NOTE_LIMIT))),
                                        }
index 209d1ebb0fde680613dc3d08c18fb79478772206..60b0353f1d050926bcc3f9e462af82ae22cbca7f 100644 (file)
@@ -301,10 +301,15 @@ mod tests {
        use bitcoin::hex::FromHex;
        use bitcoin::secp256k1::{Keypair, Message, Secp256k1, SecretKey};
        use bitcoin::secp256k1::schnorr::Signature;
+       use crate::ln::channelmanager::PaymentId;
+       use crate::ln::inbound_payment::ExpandedKey;
+       use crate::offers::nonce::Nonce;
        use crate::offers::offer::{Amount, OfferBuilder};
        use crate::offers::invoice_request::{InvoiceRequest, UnsignedInvoiceRequest};
        use crate::offers::parse::Bech32Encode;
-       use crate::offers::test_utils::{payer_pubkey, recipient_pubkey};
+       use crate::offers::signer::Metadata;
+       use crate::offers::test_utils::recipient_pubkey;
+       use crate::sign::KeyMaterial;
        use crate::util::ser::Writeable;
 
        #[test]
@@ -329,7 +334,11 @@ mod tests {
 
        #[test]
        fn calculates_merkle_root_hash_from_invoice_request() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let nonce = Nonce([0u8; 16]);
                let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let recipient_pubkey = {
                        let secret_key = SecretKey::from_slice(&<Vec<u8>>::from_hex("4141414141414141414141414141414141414141414141414141414141414141").unwrap()).unwrap();
                        Keypair::from_secret_key(&secp_ctx, &secret_key).public_key()
@@ -344,7 +353,10 @@ mod tests {
                        .description("A Mathematical Treatise".into())
                        .amount(Amount::Currency { iso4217_code: *b"USD", amount: 100 })
                        .build_unchecked()
-                       .request_invoice(vec![0; 8], payer_keys.public_key()).unwrap()
+                       // Override the payer metadata and signing pubkey to match the test vectors
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .payer_metadata(Metadata::Bytes(vec![0; 8]))
+                       .payer_signing_pubkey(payer_keys.public_key())
                        .build_unchecked()
                        .sign(|message: &UnsignedInvoiceRequest|
                                Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &payer_keys))
@@ -366,12 +378,17 @@ mod tests {
 
        #[test]
        fn compute_tagged_hash() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let nonce = Nonce([0u8; 16]);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let unsigned_invoice_request = OfferBuilder::new(recipient_pubkey())
                        .amount_msats(1000)
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
                        .payer_note("bar".into())
-                       .build().unwrap();
+                       .build_unchecked();
 
                // Simply test that we can grab the tag and merkle root exposed by the accessor
                // functions, then use them to succesfully compute a tagged hash.
@@ -384,25 +401,21 @@ mod tests {
 
        #[test]
        fn skips_encoding_signature_tlv_records() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let nonce = Nonce([0u8; 16]);
                let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let recipient_pubkey = {
                        let secret_key = SecretKey::from_slice(&[41; 32]).unwrap();
                        Keypair::from_secret_key(&secp_ctx, &secret_key).public_key()
                };
-               let payer_keys = {
-                       let secret_key = SecretKey::from_slice(&[42; 32]).unwrap();
-                       Keypair::from_secret_key(&secp_ctx, &secret_key)
-               };
 
                let invoice_request = OfferBuilder::new(recipient_pubkey)
                        .amount_msats(100)
                        .build_unchecked()
-                       .request_invoice(vec![0; 8], payer_keys.public_key()).unwrap()
-                       .build_unchecked()
-                       .sign(|message: &UnsignedInvoiceRequest|
-                               Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &payer_keys))
-                       )
-                       .unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
 
                let mut bytes_without_signature = Vec::new();
                let tlv_stream_without_signatures = TlvStream::new(&invoice_request.bytes)
@@ -420,24 +433,21 @@ mod tests {
 
        #[test]
        fn iterates_over_tlv_stream_range() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let nonce = Nonce([0u8; 16]);
                let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                let recipient_pubkey = {
                        let secret_key = SecretKey::from_slice(&[41; 32]).unwrap();
                        Keypair::from_secret_key(&secp_ctx, &secret_key).public_key()
                };
-               let payer_keys = {
-                       let secret_key = SecretKey::from_slice(&[42; 32]).unwrap();
-                       Keypair::from_secret_key(&secp_ctx, &secret_key)
-               };
 
                let invoice_request = OfferBuilder::new(recipient_pubkey)
                        .amount_msats(100)
                        .build_unchecked()
-                       .request_invoice(vec![0; 8], payer_keys.public_key()).unwrap()
-                       .build_unchecked()
-                       .sign(|message: &UnsignedInvoiceRequest|
-                               Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &payer_keys))
-                       )
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign()
                        .unwrap();
 
                let tlv_stream = TlvStream::new(&invoice_request.bytes).range(0..1)
index 4efd0096cfee024c44a42e21a4a743d994097283..c3d8b166f57c1796d08e8ba0ab0436d51e5fc9fb 100644 (file)
@@ -100,11 +100,11 @@ use crate::util::string::PrintableString;
 
 #[cfg(not(c_bindings))]
 use {
-       crate::offers::invoice_request::{DerivedPayerSigningPubkey, ExplicitPayerSigningPubkey, InvoiceRequestBuilder},
+       crate::offers::invoice_request::{DerivedPayerSigningPubkey, InvoiceRequestBuilder},
 };
 #[cfg(c_bindings)]
 use {
-       crate::offers::invoice_request::{InvoiceRequestWithDerivedPayerSigningPubkeyBuilder, InvoiceRequestWithExplicitPayerSigningPubkeyBuilder},
+       crate::offers::invoice_request::InvoiceRequestWithDerivedPayerSigningPubkeyBuilder,
 };
 
 #[allow(unused_imports)]
@@ -729,23 +729,23 @@ impl Offer {
 }
 
 macro_rules! request_invoice_derived_signing_pubkey { ($self: ident, $builder: ty) => {
-       /// Similar to [`Offer::request_invoice`] except it:
+       /// Creates an [`InvoiceRequestBuilder`] for the offer, which
        /// - derives the [`InvoiceRequest::payer_signing_pubkey`] such that a different key can be used
-       ///   for each request,
-       /// - sets [`InvoiceRequest::payer_metadata`] when [`InvoiceRequestBuilder::build`] is called
-       ///   such that it can be used by [`Bolt12Invoice::verify_using_metadata`] to determine if the
-       ///   invoice was requested using a base [`ExpandedKey`] from which the payer id was derived,
-       ///   and
+       ///   for each request in order to protect the sender's privacy,
+       /// - sets [`InvoiceRequest::payer_metadata`] when [`InvoiceRequestBuilder::build_and_sign`] is
+       ///   called such that it can be used by [`Bolt12Invoice::verify_using_metadata`] 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.
+       /// Errors if the offer contains unknown required features.
        ///
        /// [`InvoiceRequest::payer_signing_pubkey`]: crate::offers::invoice_request::InvoiceRequest::payer_signing_pubkey
        /// [`InvoiceRequest::payer_metadata`]: crate::offers::invoice_request::InvoiceRequest::payer_metadata
        /// [`Bolt12Invoice::verify_using_metadata`]: crate::offers::invoice::Bolt12Invoice::verify_using_metadata
        /// [`ExpandedKey`]: crate::ln::inbound_payment::ExpandedKey
-       pub fn request_invoice_deriving_signing_pubkey<
+       pub fn request_invoice<
                'a, 'b,
                #[cfg(not(c_bindings))]
                T: secp256k1::Signing
@@ -765,59 +765,14 @@ macro_rules! request_invoice_derived_signing_pubkey { ($self: ident, $builder: t
        }
 } }
 
-macro_rules! request_invoice_explicit_signing_pubkey { ($self: ident, $builder: ty) => {
-       /// Similar to [`Offer::request_invoice_deriving_signing_pubkey`] except uses `signing_pubkey`
-       /// for the [`InvoiceRequest::payer_signing_pubkey`] instead of deriving a different key for
-       /// each request.
-       ///
-       /// Useful for recurring payments using the same `signing_pubkey` with different invoices.
-       ///
-       /// [`InvoiceRequest::payer_signing_pubkey`]: crate::offers::invoice_request::InvoiceRequest::payer_signing_pubkey
-       pub fn request_invoice_deriving_metadata(
-               &$self, signing_pubkey: PublicKey, expanded_key: &ExpandedKey, nonce: Nonce,
-               payment_id: PaymentId
-       ) -> Result<$builder, Bolt12SemanticError> {
-               if $self.offer_features().requires_unknown_bits() {
-                       return Err(Bolt12SemanticError::UnknownRequiredFeatures);
-               }
-
-               Ok(<$builder>::deriving_metadata($self, signing_pubkey, expanded_key, nonce, payment_id))
-       }
-
-       /// Creates an [`InvoiceRequestBuilder`] for the offer with the given `metadata` and
-       /// `signing_pubkey`, which will be reflected in the `Bolt12Invoice` response.
-       ///
-       /// The `metadata` is useful for including information about the derivation of `signing_pubkey`
-       /// such that invoice response handling can be stateless. Also serves as payer-provided entropy
-       /// while hashing in the signature calculation.
-       ///
-       /// This should not leak any information such as by using a simple BIP-32 derivation path.
-       /// Otherwise, payments may be correlated.
-       ///
-       /// Errors if the offer contains unknown required features.
-       ///
-       /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
-       pub fn request_invoice(
-               &$self, metadata: Vec<u8>, signing_pubkey: PublicKey
-       ) -> Result<$builder, Bolt12SemanticError> {
-               if $self.offer_features().requires_unknown_bits() {
-                       return Err(Bolt12SemanticError::UnknownRequiredFeatures);
-               }
-
-               Ok(<$builder>::new($self, metadata, signing_pubkey))
-       }
-} }
-
 #[cfg(not(c_bindings))]
 impl Offer {
        request_invoice_derived_signing_pubkey!(self, InvoiceRequestBuilder<'a, 'b, DerivedPayerSigningPubkey, T>);
-       request_invoice_explicit_signing_pubkey!(self, InvoiceRequestBuilder<ExplicitPayerSigningPubkey, secp256k1::SignOnly>);
 }
 
 #[cfg(c_bindings)]
 impl Offer {
        request_invoice_derived_signing_pubkey!(self, InvoiceRequestWithDerivedPayerSigningPubkeyBuilder<'a, 'b>);
-       request_invoice_explicit_signing_pubkey!(self, InvoiceRequestWithExplicitPayerSigningPubkeyBuilder);
 }
 
 #[cfg(test)]
@@ -1267,6 +1222,7 @@ mod tests {
        use crate::blinded_path::message::BlindedMessagePath;
        use crate::sign::KeyMaterial;
        use crate::types::features::OfferFeatures;
+       use crate::ln::channelmanager::PaymentId;
        use crate::ln::inbound_payment::ExpandedKey;
        use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
        use crate::offers::nonce::Nonce;
@@ -1391,6 +1347,7 @@ mod tests {
                let entropy = FixedEntropy {};
                let nonce = Nonce::from_entropy_source(&entropy);
                let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
 
                #[cfg(c_bindings)]
                use super::OfferWithDerivedMetadataBuilder as OfferBuilder;
@@ -1401,18 +1358,18 @@ mod tests {
                assert!(offer.metadata().is_some());
                assert_eq!(offer.issuer_signing_pubkey(), Some(node_id));
 
-               let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+               let invoice_request = offer
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
                match invoice_request.verify_using_metadata(&expanded_key, &secp_ctx) {
                        Ok(invoice_request) => assert_eq!(invoice_request.offer_id, offer.id()),
                        Err(_) => panic!("unexpected error"),
                }
 
                // Fails verification when using the wrong method
-               let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+               let invoice_request = offer
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
                assert!(
                        invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).is_err()
                );
@@ -1425,9 +1382,8 @@ mod tests {
                tlv_stream.write(&mut encoded_offer).unwrap();
 
                let invoice_request = Offer::try_from(encoded_offer).unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
                assert!(invoice_request.verify_using_metadata(&expanded_key, &secp_ctx).is_err());
 
                // Fails verification with altered metadata
@@ -1439,9 +1395,8 @@ mod tests {
                tlv_stream.write(&mut encoded_offer).unwrap();
 
                let invoice_request = Offer::try_from(encoded_offer).unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
                assert!(invoice_request.verify_using_metadata(&expanded_key, &secp_ctx).is_err());
        }
 
@@ -1452,6 +1407,7 @@ mod tests {
                let entropy = FixedEntropy {};
                let nonce = Nonce::from_entropy_source(&entropy);
                let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
 
                let blinded_path = BlindedMessagePath::from_raw(
                        pubkey(40), pubkey(41),
@@ -1471,18 +1427,18 @@ mod tests {
                assert!(offer.metadata().is_none());
                assert_ne!(offer.issuer_signing_pubkey(), Some(node_id));
 
-               let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+               let invoice_request = offer
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
                match invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx) {
                        Ok(invoice_request) => assert_eq!(invoice_request.offer_id, offer.id()),
                        Err(_) => panic!("unexpected error"),
                }
 
                // Fails verification when using the wrong method
-               let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+               let invoice_request = offer
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
                assert!(invoice_request.verify_using_metadata(&expanded_key, &secp_ctx).is_err());
 
                // Fails verification with altered offer field
@@ -1493,9 +1449,8 @@ mod tests {
                tlv_stream.write(&mut encoded_offer).unwrap();
 
                let invoice_request = Offer::try_from(encoded_offer).unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
                assert!(
                        invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).is_err()
                );
@@ -1509,9 +1464,8 @@ mod tests {
                tlv_stream.write(&mut encoded_offer).unwrap();
 
                let invoice_request = Offer::try_from(encoded_offer).unwrap()
-                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
-                       .build().unwrap()
-                       .sign(payer_sign).unwrap();
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
+                       .build_and_sign().unwrap();
                assert!(
                        invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).is_err()
                );
@@ -1738,10 +1692,16 @@ mod tests {
 
        #[test]
        fn fails_requesting_invoice_with_unknown_required_features() {
+               let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
+               let entropy = FixedEntropy {};
+               let nonce = Nonce::from_entropy_source(&entropy);
+               let secp_ctx = Secp256k1::new();
+               let payment_id = PaymentId([1; 32]);
+
                match OfferBuilder::new(pubkey(42))
                        .features_unchecked(OfferFeatures::unknown())
                        .build().unwrap()
-                       .request_invoice(vec![1; 32], pubkey(43))
+                       .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id)
                {
                        Ok(_) => panic!("expected error"),
                        Err(e) => assert_eq!(e, Bolt12SemanticError::UnknownRequiredFeatures),