mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-01-18 13:24:36 +01:00
Merge pull request #3264 from jkczyz/2024-08-remove-user-provided-payer-id
Disallow user-provided `payer_signing_pubkey`
This commit is contained in:
commit
70add1448b
@ -57,7 +57,6 @@ use lightning::ln::msgs::{
|
|||||||
use lightning::ln::script::ShutdownScript;
|
use lightning::ln::script::ShutdownScript;
|
||||||
use lightning::ln::types::ChannelId;
|
use lightning::ln::types::ChannelId;
|
||||||
use lightning::offers::invoice::UnsignedBolt12Invoice;
|
use lightning::offers::invoice::UnsignedBolt12Invoice;
|
||||||
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
|
|
||||||
use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath};
|
use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath};
|
||||||
use lightning::routing::router::{InFlightHtlcs, Path, Route, RouteHop, RouteParameters, Router};
|
use lightning::routing::router::{InFlightHtlcs, Path, Route, RouteHop, RouteParameters, Router};
|
||||||
use lightning::sign::{
|
use lightning::sign::{
|
||||||
@ -340,12 +339,6 @@ impl NodeSigner for KeyProvider {
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_bolt12_invoice_request(
|
|
||||||
&self, _invoice_request: &UnsignedInvoiceRequest,
|
|
||||||
) -> Result<schnorr::Signature, ()> {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sign_bolt12_invoice(
|
fn sign_bolt12_invoice(
|
||||||
&self, _invoice: &UnsignedBolt12Invoice,
|
&self, _invoice: &UnsignedBolt12Invoice,
|
||||||
) -> Result<schnorr::Signature, ()> {
|
) -> Result<schnorr::Signature, ()> {
|
||||||
|
@ -50,7 +50,6 @@ use lightning::ln::peer_handler::{
|
|||||||
use lightning::ln::script::ShutdownScript;
|
use lightning::ln::script::ShutdownScript;
|
||||||
use lightning::ln::types::ChannelId;
|
use lightning::ln::types::ChannelId;
|
||||||
use lightning::offers::invoice::UnsignedBolt12Invoice;
|
use lightning::offers::invoice::UnsignedBolt12Invoice;
|
||||||
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
|
|
||||||
use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath};
|
use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath};
|
||||||
use lightning::routing::gossip::{NetworkGraph, P2PGossipSync};
|
use lightning::routing::gossip::{NetworkGraph, P2PGossipSync};
|
||||||
use lightning::routing::router::{
|
use lightning::routing::router::{
|
||||||
@ -413,12 +412,6 @@ impl NodeSigner for KeyProvider {
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_bolt12_invoice_request(
|
|
||||||
&self, _invoice_request: &UnsignedInvoiceRequest,
|
|
||||||
) -> Result<schnorr::Signature, ()> {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sign_bolt12_invoice(
|
fn sign_bolt12_invoice(
|
||||||
&self, _invoice: &UnsignedBolt12Invoice,
|
&self, _invoice: &UnsignedBolt12Invoice,
|
||||||
) -> Result<schnorr::Signature, ()> {
|
) -> Result<schnorr::Signature, ()> {
|
||||||
|
@ -8,11 +8,15 @@
|
|||||||
// licenses.
|
// licenses.
|
||||||
|
|
||||||
use crate::utils::test_logger;
|
use crate::utils::test_logger;
|
||||||
use bitcoin::secp256k1::{Keypair, PublicKey, Secp256k1, SecretKey};
|
use bitcoin::secp256k1::Secp256k1;
|
||||||
use core::convert::TryFrom;
|
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::offer::{Amount, Offer, Quantity};
|
||||||
use lightning::offers::parse::Bolt12SemanticError;
|
use lightning::offers::parse::Bolt12SemanticError;
|
||||||
|
use lightning::sign::{EntropySource, KeyMaterial};
|
||||||
use lightning::util::ser::Writeable;
|
use lightning::util::ser::Writeable;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -22,27 +26,30 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
|
|||||||
offer.write(&mut bytes).unwrap();
|
offer.write(&mut bytes).unwrap();
|
||||||
assert_eq!(data, bytes);
|
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();
|
let mut buffer = Vec::new();
|
||||||
|
|
||||||
if let Ok(invoice_request) = build_response(&offer, pubkey) {
|
if let Ok(invoice_request) = build_request(&offer) {
|
||||||
invoice_request
|
invoice_request.write(&mut buffer).unwrap();
|
||||||
.sign(|message: &UnsignedInvoiceRequest| {
|
|
||||||
Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
.write(&mut buffer)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_response(
|
struct FixedEntropy;
|
||||||
offer: &Offer, pubkey: PublicKey,
|
|
||||||
) -> Result<UnsignedInvoiceRequest, Bolt12SemanticError> {
|
impl EntropySource for FixedEntropy {
|
||||||
let mut builder = offer.request_invoice(vec![42; 64], pubkey)?;
|
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() {
|
builder = match offer.amount() {
|
||||||
None => builder.amount_msats(1000).unwrap(),
|
None => builder.amount_msats(1000).unwrap(),
|
||||||
@ -56,7 +63,7 @@ fn build_response(
|
|||||||
Quantity::One => builder,
|
Quantity::One => builder,
|
||||||
};
|
};
|
||||||
|
|
||||||
builder.build()
|
builder.build_and_sign()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offer_deser_test<Out: test_logger::Output>(data: &[u8], out: Out) {
|
pub fn offer_deser_test<Out: test_logger::Output>(data: &[u8], out: Out) {
|
||||||
|
@ -13,7 +13,6 @@ use lightning::ln::msgs::{self, DecodeError, OnionMessageHandler};
|
|||||||
use lightning::ln::peer_handler::IgnoringMessageHandler;
|
use lightning::ln::peer_handler::IgnoringMessageHandler;
|
||||||
use lightning::ln::script::ShutdownScript;
|
use lightning::ln::script::ShutdownScript;
|
||||||
use lightning::offers::invoice::UnsignedBolt12Invoice;
|
use lightning::offers::invoice::UnsignedBolt12Invoice;
|
||||||
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
|
|
||||||
use lightning::onion_message::async_payments::{
|
use lightning::onion_message::async_payments::{
|
||||||
AsyncPaymentsMessageHandler, HeldHtlcAvailable, ReleaseHeldHtlc,
|
AsyncPaymentsMessageHandler, HeldHtlcAvailable, ReleaseHeldHtlc,
|
||||||
};
|
};
|
||||||
@ -234,12 +233,6 @@ impl NodeSigner for KeyProvider {
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_bolt12_invoice_request(
|
|
||||||
&self, _invoice_request: &UnsignedInvoiceRequest,
|
|
||||||
) -> Result<schnorr::Signature, ()> {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sign_bolt12_invoice(
|
fn sign_bolt12_invoice(
|
||||||
&self, _invoice: &UnsignedBolt12Invoice,
|
&self, _invoice: &UnsignedBolt12Invoice,
|
||||||
) -> Result<schnorr::Signature, ()> {
|
) -> Result<schnorr::Signature, ()> {
|
||||||
|
@ -27,7 +27,6 @@ use crate::ln::onion_utils;
|
|||||||
use crate::ln::onion_utils::INVALID_ONION_BLINDING;
|
use crate::ln::onion_utils::INVALID_ONION_BLINDING;
|
||||||
use crate::ln::outbound_payment::{Retry, IDEMPOTENCY_TIMEOUT_TICKS};
|
use crate::ln::outbound_payment::{Retry, IDEMPOTENCY_TIMEOUT_TICKS};
|
||||||
use crate::offers::invoice::UnsignedBolt12Invoice;
|
use crate::offers::invoice::UnsignedBolt12Invoice;
|
||||||
use crate::offers::invoice_request::UnsignedInvoiceRequest;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::routing::router::{BlindedTail, Path, Payee, PaymentParameters, RouteHop, RouteParameters};
|
use crate::routing::router::{BlindedTail, Path, Payee, PaymentParameters, RouteHop, RouteParameters};
|
||||||
use crate::sign::{KeyMaterial, NodeSigner, Recipient};
|
use crate::sign::{KeyMaterial, NodeSigner, Recipient};
|
||||||
@ -1540,9 +1539,6 @@ fn route_blinding_spec_test_vector() {
|
|||||||
fn sign_invoice(
|
fn sign_invoice(
|
||||||
&self, _invoice: &RawBolt11Invoice, _recipient: Recipient,
|
&self, _invoice: &RawBolt11Invoice, _recipient: Recipient,
|
||||||
) -> Result<RecoverableSignature, ()> { unreachable!() }
|
) -> Result<RecoverableSignature, ()> { unreachable!() }
|
||||||
fn sign_bolt12_invoice_request(
|
|
||||||
&self, _invoice_request: &UnsignedInvoiceRequest,
|
|
||||||
) -> Result<schnorr::Signature, ()> { unreachable!() }
|
|
||||||
fn sign_bolt12_invoice(
|
fn sign_bolt12_invoice(
|
||||||
&self, _invoice: &UnsignedBolt12Invoice,
|
&self, _invoice: &UnsignedBolt12Invoice,
|
||||||
) -> Result<schnorr::Signature, ()> { unreachable!() }
|
) -> Result<schnorr::Signature, ()> { unreachable!() }
|
||||||
|
@ -66,7 +66,7 @@ use crate::ln::outbound_payment::{OutboundPayments, PendingOutboundPayment, Retr
|
|||||||
use crate::ln::wire::Encode;
|
use crate::ln::wire::Encode;
|
||||||
use crate::offers::invoice::{Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice};
|
use crate::offers::invoice::{Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice};
|
||||||
use crate::offers::invoice_error::InvoiceError;
|
use crate::offers::invoice_error::InvoiceError;
|
||||||
use crate::offers::invoice_request::{DerivedPayerSigningPubkey, InvoiceRequest, InvoiceRequestBuilder};
|
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestBuilder};
|
||||||
use crate::offers::nonce::Nonce;
|
use crate::offers::nonce::Nonce;
|
||||||
use crate::offers::offer::{Offer, OfferBuilder};
|
use crate::offers::offer::{Offer, OfferBuilder};
|
||||||
use crate::offers::parse::Bolt12SemanticError;
|
use crate::offers::parse::Bolt12SemanticError;
|
||||||
@ -9632,8 +9632,8 @@ where
|
|||||||
let secp_ctx = &self.secp_ctx;
|
let secp_ctx = &self.secp_ctx;
|
||||||
|
|
||||||
let nonce = Nonce::from_entropy_source(entropy);
|
let nonce = Nonce::from_entropy_source(entropy);
|
||||||
let builder: InvoiceRequestBuilder<DerivedPayerSigningPubkey, secp256k1::All> = offer
|
let builder: InvoiceRequestBuilder<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();
|
.into();
|
||||||
let builder = builder.chain_hash(self.chain_hash)?;
|
let builder = builder.chain_hash(self.chain_hash)?;
|
||||||
|
|
||||||
|
@ -2745,6 +2745,8 @@ mod tests {
|
|||||||
let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
|
let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
|
||||||
let secp_ctx = Secp256k1::new();
|
let secp_ctx = Secp256k1::new();
|
||||||
let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
|
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 pending_events = Mutex::new(VecDeque::new());
|
||||||
let outbound_payments = OutboundPayments::new(new_hash_map());
|
let outbound_payments = OutboundPayments::new(new_hash_map());
|
||||||
@ -2762,9 +2764,8 @@ mod tests {
|
|||||||
let invoice = OfferBuilder::new(recipient_pubkey())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), created_at).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), created_at).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(recipient_sign).unwrap();
|
.sign(recipient_sign).unwrap();
|
||||||
@ -2801,15 +2802,16 @@ mod tests {
|
|||||||
|
|
||||||
let pending_events = Mutex::new(VecDeque::new());
|
let pending_events = Mutex::new(VecDeque::new());
|
||||||
let outbound_payments = OutboundPayments::new(new_hash_map());
|
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 payment_id = PaymentId([0; 32]);
|
||||||
let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
|
let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
|
||||||
|
|
||||||
let invoice = OfferBuilder::new(recipient_pubkey())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(recipient_sign).unwrap();
|
.sign(recipient_sign).unwrap();
|
||||||
@ -2862,15 +2864,16 @@ mod tests {
|
|||||||
|
|
||||||
let pending_events = Mutex::new(VecDeque::new());
|
let pending_events = Mutex::new(VecDeque::new());
|
||||||
let outbound_payments = OutboundPayments::new(new_hash_map());
|
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 payment_id = PaymentId([0; 32]);
|
||||||
let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
|
let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
|
||||||
|
|
||||||
let invoice = OfferBuilder::new(recipient_pubkey())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(recipient_sign).unwrap();
|
.sign(recipient_sign).unwrap();
|
||||||
@ -2955,7 +2958,7 @@ mod tests {
|
|||||||
OfferBuilder::new(recipient_pubkey())
|
OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice_deriving_signing_pubkey(&expanded_key, nonce, &secp_ctx, payment_id)
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.build_and_sign()
|
.build_and_sign()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1607,6 +1607,7 @@ mod tests {
|
|||||||
use crate::blinded_path::message::BlindedMessagePath;
|
use crate::blinded_path::message::BlindedMessagePath;
|
||||||
use crate::sign::KeyMaterial;
|
use crate::sign::KeyMaterial;
|
||||||
use crate::types::features::{Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures};
|
use crate::types::features::{Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures};
|
||||||
|
use crate::ln::channelmanager::PaymentId;
|
||||||
use crate::ln::inbound_payment::ExpandedKey;
|
use crate::ln::inbound_payment::ExpandedKey;
|
||||||
use crate::ln::msgs::DecodeError;
|
use crate::ln::msgs::DecodeError;
|
||||||
use crate::offers::invoice_request::{ExperimentalInvoiceRequestTlvStreamRef, InvoiceRequestTlvStreamRef};
|
use crate::offers::invoice_request::{ExperimentalInvoiceRequestTlvStreamRef, InvoiceRequestTlvStreamRef};
|
||||||
@ -1648,15 +1649,21 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn builds_invoice_for_offer_with_defaults() {
|
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_paths = payment_paths();
|
||||||
let payment_hash = payment_hash();
|
let payment_hash = payment_hash();
|
||||||
let now = now();
|
let now = now();
|
||||||
let unsigned_invoice = OfferBuilder::new(recipient_pubkey())
|
let unsigned_invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths.clone(), payment_hash, now).unwrap()
|
.respond_with_no_std(payment_paths.clone(), payment_hash, now).unwrap()
|
||||||
.build().unwrap();
|
.build().unwrap();
|
||||||
|
|
||||||
@ -1664,7 +1671,7 @@ mod tests {
|
|||||||
unsigned_invoice.write(&mut buffer).unwrap();
|
unsigned_invoice.write(&mut buffer).unwrap();
|
||||||
|
|
||||||
assert_eq!(unsigned_invoice.bytes, buffer.as_slice());
|
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.offer_chains(), Some(vec![ChainHash::using_genesis_block(Network::Bitcoin)]));
|
||||||
assert_eq!(unsigned_invoice.metadata(), None);
|
assert_eq!(unsigned_invoice.metadata(), None);
|
||||||
assert_eq!(unsigned_invoice.amount(), Some(Amount::Bitcoin { amount_msats: 1000 }));
|
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.amount_msats(), 1000);
|
||||||
assert_eq!(unsigned_invoice.invoice_request_features(), &InvoiceRequestFeatures::empty());
|
assert_eq!(unsigned_invoice.invoice_request_features(), &InvoiceRequestFeatures::empty());
|
||||||
assert_eq!(unsigned_invoice.quantity(), None);
|
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.payer_note(), None);
|
||||||
assert_eq!(unsigned_invoice.payment_paths(), payment_paths.as_slice());
|
assert_eq!(unsigned_invoice.payment_paths(), payment_paths.as_slice());
|
||||||
assert_eq!(unsigned_invoice.created_at(), now);
|
assert_eq!(unsigned_invoice.created_at(), now);
|
||||||
@ -1706,7 +1712,7 @@ mod tests {
|
|||||||
invoice.write(&mut buffer).unwrap();
|
invoice.write(&mut buffer).unwrap();
|
||||||
|
|
||||||
assert_eq!(invoice.bytes, buffer.as_slice());
|
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.offer_chains(), Some(vec![ChainHash::using_genesis_block(Network::Bitcoin)]));
|
||||||
assert_eq!(invoice.metadata(), None);
|
assert_eq!(invoice.metadata(), None);
|
||||||
assert_eq!(invoice.amount(), Some(Amount::Bitcoin { amount_msats: 1000 }));
|
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.amount_msats(), 1000);
|
||||||
assert_eq!(invoice.invoice_request_features(), &InvoiceRequestFeatures::empty());
|
assert_eq!(invoice.invoice_request_features(), &InvoiceRequestFeatures::empty());
|
||||||
assert_eq!(invoice.quantity(), None);
|
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.payer_note(), None);
|
||||||
assert_eq!(invoice.payment_paths(), payment_paths.as_slice());
|
assert_eq!(invoice.payment_paths(), payment_paths.as_slice());
|
||||||
assert_eq!(invoice.created_at(), now);
|
assert_eq!(invoice.created_at(), now);
|
||||||
@ -1744,7 +1753,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
invoice.as_tlv_stream(),
|
invoice.as_tlv_stream(),
|
||||||
(
|
(
|
||||||
PayerTlvStreamRef { metadata: Some(&vec![1; 32]) },
|
PayerTlvStreamRef { metadata: Some(&encrypted_payment_id.to_vec()) },
|
||||||
OfferTlvStreamRef {
|
OfferTlvStreamRef {
|
||||||
chains: None,
|
chains: None,
|
||||||
metadata: None,
|
metadata: None,
|
||||||
@ -1763,7 +1772,7 @@ mod tests {
|
|||||||
amount: None,
|
amount: None,
|
||||||
features: None,
|
features: None,
|
||||||
quantity: None,
|
quantity: None,
|
||||||
payer_id: Some(&payer_pubkey()),
|
payer_id: Some(&invoice.payer_signing_pubkey()),
|
||||||
payer_note: None,
|
payer_note: None,
|
||||||
paths: None,
|
paths: None,
|
||||||
offer_from_hrn: None,
|
offer_from_hrn: None,
|
||||||
@ -1904,6 +1913,12 @@ mod tests {
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[test]
|
#[test]
|
||||||
fn builds_invoice_from_offer_with_expiration() {
|
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 future_expiry = Duration::from_secs(u64::max_value());
|
||||||
let past_expiry = Duration::from_secs(0);
|
let past_expiry = Duration::from_secs(0);
|
||||||
|
|
||||||
@ -1911,9 +1926,8 @@ mod tests {
|
|||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.absolute_expiry(future_expiry)
|
.absolute_expiry(future_expiry)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with(payment_paths(), payment_hash())
|
.respond_with(payment_paths(), payment_hash())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.build()
|
.build()
|
||||||
@ -1925,9 +1939,8 @@ mod tests {
|
|||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.absolute_expiry(past_expiry)
|
.absolute_expiry(past_expiry)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build_unchecked()
|
.build_unchecked_and_sign()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with(payment_paths(), payment_hash())
|
.respond_with(payment_paths(), payment_hash())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.build()
|
.build()
|
||||||
@ -1972,6 +1985,7 @@ mod tests {
|
|||||||
let entropy = FixedEntropy {};
|
let entropy = FixedEntropy {};
|
||||||
let nonce = Nonce::from_entropy_source(&entropy);
|
let nonce = Nonce::from_entropy_source(&entropy);
|
||||||
let secp_ctx = Secp256k1::new();
|
let secp_ctx = Secp256k1::new();
|
||||||
|
let payment_id = PaymentId([1; 32]);
|
||||||
|
|
||||||
let blinded_path = BlindedMessagePath::from_raw(
|
let blinded_path = BlindedMessagePath::from_raw(
|
||||||
pubkey(40), pubkey(41),
|
pubkey(40), pubkey(41),
|
||||||
@ -1983,14 +1997,14 @@ mod tests {
|
|||||||
|
|
||||||
#[cfg(c_bindings)]
|
#[cfg(c_bindings)]
|
||||||
use crate::offers::offer::OfferWithDerivedMetadataBuilder as OfferBuilder;
|
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)
|
.amount_msats(1000)
|
||||||
.path(blinded_path)
|
.path(blinded_path)
|
||||||
.experimental_foo(42)
|
.experimental_foo(42)
|
||||||
.build().unwrap();
|
|
||||||
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
|
||||||
.build().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()
|
if let Err(e) = invoice_request.clone()
|
||||||
.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).unwrap()
|
.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).unwrap()
|
||||||
@ -2005,14 +2019,14 @@ mod tests {
|
|||||||
invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).is_err()
|
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)
|
.amount_msats(1000)
|
||||||
// Omit the path so that node_id is used for the signing pubkey instead of deriving it
|
// Omit the path so that node_id is used for the signing pubkey instead of deriving it
|
||||||
.experimental_foo(42)
|
.experimental_foo(42)
|
||||||
.build().unwrap();
|
|
||||||
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(payer_sign).unwrap();
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
|
.build_and_sign().unwrap();
|
||||||
|
|
||||||
match invoice_request
|
match invoice_request
|
||||||
.verify_using_metadata(&expanded_key, &secp_ctx).unwrap()
|
.verify_using_metadata(&expanded_key, &secp_ctx).unwrap()
|
||||||
@ -2076,15 +2090,20 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn builds_invoice_with_relative_expiry() {
|
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 now = now();
|
||||||
let one_hour = Duration::from_secs(3600);
|
let one_hour = Duration::from_secs(3600);
|
||||||
|
|
||||||
let invoice = OfferBuilder::new(recipient_pubkey())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now).unwrap()
|
||||||
.relative_expiry(one_hour.as_secs() as u32)
|
.relative_expiry(one_hour.as_secs() as u32)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
@ -2098,9 +2117,8 @@ mod tests {
|
|||||||
let invoice = OfferBuilder::new(recipient_pubkey())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now - one_hour).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now - one_hour).unwrap()
|
||||||
.relative_expiry(one_hour.as_secs() as u32 - 1)
|
.relative_expiry(one_hour.as_secs() as u32 - 1)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
@ -2114,13 +2132,18 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn builds_invoice_with_amount_from_request() {
|
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())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.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(1001).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(recipient_sign).unwrap();
|
.sign(recipient_sign).unwrap();
|
||||||
@ -2131,14 +2154,19 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn builds_invoice_with_quantity_from_request() {
|
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())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.supported_quantity(Quantity::Unbounded)
|
.supported_quantity(Quantity::Unbounded)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.quantity(2).unwrap()
|
.quantity(2).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(recipient_sign).unwrap();
|
.sign(recipient_sign).unwrap();
|
||||||
@ -2150,10 +2178,9 @@ mod tests {
|
|||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.supported_quantity(Quantity::Unbounded)
|
.supported_quantity(Quantity::Unbounded)
|
||||||
.build().unwrap()
|
.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()
|
.quantity(u64::max_value()).unwrap()
|
||||||
.build_unchecked()
|
.build_unchecked_and_sign()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now())
|
.respond_with_no_std(payment_paths(), payment_hash(), now())
|
||||||
{
|
{
|
||||||
Ok(_) => panic!("expected error"),
|
Ok(_) => panic!("expected error"),
|
||||||
@ -2163,6 +2190,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn builds_invoice_with_fallback_address() {
|
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 script = ScriptBuf::new();
|
||||||
let pubkey = bitcoin::key::PublicKey::new(recipient_pubkey());
|
let pubkey = bitcoin::key::PublicKey::new(recipient_pubkey());
|
||||||
let x_only_pubkey = XOnlyPublicKey::from_keypair(&recipient_keys()).0;
|
let x_only_pubkey = XOnlyPublicKey::from_keypair(&recipient_keys()).0;
|
||||||
@ -2171,9 +2204,8 @@ mod tests {
|
|||||||
let invoice = OfferBuilder::new(recipient_pubkey())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.fallback_v0_p2wsh(&script.wscript_hash())
|
.fallback_v0_p2wsh(&script.wscript_hash())
|
||||||
.fallback_v0_p2wpkh(&pubkey.wpubkey_hash().unwrap())
|
.fallback_v0_p2wpkh(&pubkey.wpubkey_hash().unwrap())
|
||||||
@ -2210,15 +2242,20 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn builds_invoice_with_allow_mpp() {
|
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();
|
let mut features = Bolt12InvoiceFeatures::empty();
|
||||||
features.set_basic_mpp_optional();
|
features.set_basic_mpp_optional();
|
||||||
|
|
||||||
let invoice = OfferBuilder::new(recipient_pubkey())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.allow_mpp()
|
.allow_mpp()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
@ -2230,12 +2267,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fails_signing_invoice() {
|
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())
|
match OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(fail_sign)
|
.sign(fail_sign)
|
||||||
@ -2247,9 +2289,8 @@ mod tests {
|
|||||||
match OfferBuilder::new(recipient_pubkey())
|
match OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(payer_sign)
|
.sign(payer_sign)
|
||||||
@ -2261,12 +2302,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_invoice_with_payment_paths() {
|
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())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(recipient_sign).unwrap();
|
.sign(recipient_sign).unwrap();
|
||||||
@ -2316,12 +2362,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_invoice_with_created_at() {
|
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())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(recipient_sign).unwrap();
|
.sign(recipient_sign).unwrap();
|
||||||
@ -2346,12 +2397,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_invoice_with_relative_expiry() {
|
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())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.relative_expiry(3600)
|
.relative_expiry(3600)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
@ -2368,12 +2424,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_invoice_with_payment_hash() {
|
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())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(recipient_sign).unwrap();
|
.sign(recipient_sign).unwrap();
|
||||||
@ -2398,12 +2459,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_invoice_with_amount() {
|
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())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(recipient_sign).unwrap();
|
.sign(recipient_sign).unwrap();
|
||||||
@ -2426,12 +2492,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_invoice_with_allow_mpp() {
|
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())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.allow_mpp()
|
.allow_mpp()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
@ -2452,18 +2523,22 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_invoice_with_fallback_address() {
|
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 script = ScriptBuf::new();
|
||||||
let pubkey = bitcoin::key::PublicKey::new(recipient_pubkey());
|
let pubkey = bitcoin::key::PublicKey::new(recipient_pubkey());
|
||||||
let x_only_pubkey = XOnlyPublicKey::from_keypair(&recipient_keys()).0;
|
let x_only_pubkey = XOnlyPublicKey::from_keypair(&recipient_keys()).0;
|
||||||
let tweaked_pubkey = TweakedPublicKey::dangerous_assume_tweaked(x_only_pubkey);
|
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)
|
.amount_msats(1000)
|
||||||
.build().unwrap();
|
|
||||||
let invoice_request = offer
|
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
|
||||||
.build().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))]
|
#[cfg(not(c_bindings))]
|
||||||
let invoice_builder = invoice_request
|
let invoice_builder = invoice_request
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap();
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap();
|
||||||
@ -2512,12 +2587,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_invoice_with_node_id() {
|
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())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(recipient_sign).unwrap();
|
.sign(recipient_sign).unwrap();
|
||||||
@ -2553,6 +2633,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_invoice_with_node_id_from_blinded_path() {
|
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![
|
let paths = vec![
|
||||||
BlindedMessagePath::from_raw(
|
BlindedMessagePath::from_raw(
|
||||||
pubkey(40), pubkey(41),
|
pubkey(40), pubkey(41),
|
||||||
@ -2582,9 +2668,8 @@ mod tests {
|
|||||||
.path(paths[0].clone())
|
.path(paths[0].clone())
|
||||||
.path(paths[1].clone())
|
.path(paths[1].clone())
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std_using_signing_pubkey(
|
.respond_with_no_std_using_signing_pubkey(
|
||||||
payment_paths(), payment_hash(), now(), pubkey(46)
|
payment_paths(), payment_hash(), now(), pubkey(46)
|
||||||
).unwrap()
|
).unwrap()
|
||||||
@ -2604,9 +2689,8 @@ mod tests {
|
|||||||
.path(paths[0].clone())
|
.path(paths[0].clone())
|
||||||
.path(paths[1].clone())
|
.path(paths[1].clone())
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std_using_signing_pubkey(
|
.respond_with_no_std_using_signing_pubkey(
|
||||||
payment_paths(), payment_hash(), now(), recipient_pubkey()
|
payment_paths(), payment_hash(), now(), recipient_pubkey()
|
||||||
).unwrap()
|
).unwrap()
|
||||||
@ -2626,13 +2710,18 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fails_parsing_invoice_without_signature() {
|
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();
|
let mut buffer = Vec::new();
|
||||||
OfferBuilder::new(recipient_pubkey())
|
OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.contents
|
.contents
|
||||||
@ -2646,12 +2735,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fails_parsing_invoice_with_invalid_signature() {
|
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())
|
let mut invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(recipient_sign).unwrap();
|
.sign(recipient_sign).unwrap();
|
||||||
@ -2671,6 +2765,11 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_invoice_with_unknown_tlv_records() {
|
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;
|
const UNKNOWN_ODD_TYPE: u64 = INVOICE_TYPES.end - 1;
|
||||||
assert!(UNKNOWN_ODD_TYPE % 2 == 1);
|
assert!(UNKNOWN_ODD_TYPE % 2 == 1);
|
||||||
|
|
||||||
@ -2679,9 +2778,8 @@ mod tests {
|
|||||||
let mut unsigned_invoice = OfferBuilder::new(keys.public_key())
|
let mut unsigned_invoice = OfferBuilder::new(keys.public_key())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap();
|
.build().unwrap();
|
||||||
|
|
||||||
@ -2717,9 +2815,8 @@ mod tests {
|
|||||||
let mut unsigned_invoice = OfferBuilder::new(keys.public_key())
|
let mut unsigned_invoice = OfferBuilder::new(keys.public_key())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap();
|
.build().unwrap();
|
||||||
|
|
||||||
@ -2752,14 +2849,18 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_invoice_with_experimental_tlv_records() {
|
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 secp_ctx = Secp256k1::new();
|
||||||
let keys = Keypair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
|
let keys = Keypair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
|
||||||
let invoice = OfferBuilder::new(keys.public_key())
|
let invoice = OfferBuilder::new(keys.public_key())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.experimental_baz(42)
|
.experimental_baz(42)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
@ -2779,9 +2880,8 @@ mod tests {
|
|||||||
let mut unsigned_invoice = OfferBuilder::new(keys.public_key())
|
let mut unsigned_invoice = OfferBuilder::new(keys.public_key())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap();
|
.build().unwrap();
|
||||||
|
|
||||||
@ -2819,9 +2919,8 @@ mod tests {
|
|||||||
let mut unsigned_invoice = OfferBuilder::new(keys.public_key())
|
let mut unsigned_invoice = OfferBuilder::new(keys.public_key())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap();
|
.build().unwrap();
|
||||||
|
|
||||||
@ -2856,9 +2955,8 @@ mod tests {
|
|||||||
let invoice = OfferBuilder::new(keys.public_key())
|
let invoice = OfferBuilder::new(keys.public_key())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(|message: &UnsignedBolt12Invoice|
|
.sign(|message: &UnsignedBolt12Invoice|
|
||||||
@ -2881,12 +2979,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fails_parsing_invoice_with_out_of_range_tlv_records() {
|
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())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(recipient_sign).unwrap();
|
.sign(recipient_sign).unwrap();
|
||||||
@ -2905,12 +3008,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fails_parsing_invoice_with_message_paths() {
|
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())
|
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||||
.amount_msats(1000)
|
.amount_msats(1000)
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap()
|
||||||
.sign(payer_sign).unwrap()
|
|
||||||
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.sign(recipient_sign).unwrap();
|
.sign(recipient_sign).unwrap();
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -301,10 +301,15 @@ mod tests {
|
|||||||
use bitcoin::hex::FromHex;
|
use bitcoin::hex::FromHex;
|
||||||
use bitcoin::secp256k1::{Keypair, Message, Secp256k1, SecretKey};
|
use bitcoin::secp256k1::{Keypair, Message, Secp256k1, SecretKey};
|
||||||
use bitcoin::secp256k1::schnorr::Signature;
|
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::offer::{Amount, OfferBuilder};
|
||||||
use crate::offers::invoice_request::{InvoiceRequest, UnsignedInvoiceRequest};
|
use crate::offers::invoice_request::{InvoiceRequest, UnsignedInvoiceRequest};
|
||||||
use crate::offers::parse::Bech32Encode;
|
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;
|
use crate::util::ser::Writeable;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -329,7 +334,11 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn calculates_merkle_root_hash_from_invoice_request() {
|
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 secp_ctx = Secp256k1::new();
|
||||||
|
let payment_id = PaymentId([1; 32]);
|
||||||
|
|
||||||
let recipient_pubkey = {
|
let recipient_pubkey = {
|
||||||
let secret_key = SecretKey::from_slice(&<Vec<u8>>::from_hex("4141414141414141414141414141414141414141414141414141414141414141").unwrap()).unwrap();
|
let secret_key = SecretKey::from_slice(&<Vec<u8>>::from_hex("4141414141414141414141414141414141414141414141414141414141414141").unwrap()).unwrap();
|
||||||
Keypair::from_secret_key(&secp_ctx, &secret_key).public_key()
|
Keypair::from_secret_key(&secp_ctx, &secret_key).public_key()
|
||||||
@ -344,7 +353,10 @@ mod tests {
|
|||||||
.description("A Mathematical Treatise".into())
|
.description("A Mathematical Treatise".into())
|
||||||
.amount(Amount::Currency { iso4217_code: *b"USD", amount: 100 })
|
.amount(Amount::Currency { iso4217_code: *b"USD", amount: 100 })
|
||||||
.build_unchecked()
|
.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()
|
.build_unchecked()
|
||||||
.sign(|message: &UnsignedInvoiceRequest|
|
.sign(|message: &UnsignedInvoiceRequest|
|
||||||
Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &payer_keys))
|
Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &payer_keys))
|
||||||
@ -364,45 +376,46 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compute_tagged_hash() {
|
fn compute_tagged_hash() {
|
||||||
let unsigned_invoice_request = OfferBuilder::new(recipient_pubkey())
|
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
|
||||||
.amount_msats(1000)
|
let nonce = Nonce([0u8; 16]);
|
||||||
.build().unwrap()
|
let secp_ctx = Secp256k1::new();
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
let payment_id = PaymentId([1; 32]);
|
||||||
.payer_note("bar".into())
|
|
||||||
.build().unwrap();
|
|
||||||
|
|
||||||
// Simply test that we can grab the tag and merkle root exposed by the accessor
|
let unsigned_invoice_request = OfferBuilder::new(recipient_pubkey())
|
||||||
// functions, then use them to succesfully compute a tagged hash.
|
.amount_msats(1000)
|
||||||
let tagged_hash = unsigned_invoice_request.as_ref();
|
.build().unwrap()
|
||||||
let expected_digest = unsigned_invoice_request.as_ref().as_digest();
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
let tag = sha256::Hash::hash(tagged_hash.tag().as_bytes());
|
.payer_note("bar".into())
|
||||||
let actual_digest = Message::from_digest(super::tagged_hash(tag, tagged_hash.merkle_root()).to_byte_array());
|
.build_unchecked();
|
||||||
assert_eq!(*expected_digest, actual_digest);
|
|
||||||
}
|
// 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.
|
||||||
|
let tagged_hash = unsigned_invoice_request.as_ref();
|
||||||
|
let expected_digest = unsigned_invoice_request.as_ref().as_digest();
|
||||||
|
let tag = sha256::Hash::hash(tagged_hash.tag().as_bytes());
|
||||||
|
let actual_digest = Message::from_digest(super::tagged_hash(tag, tagged_hash.merkle_root()).to_byte_array());
|
||||||
|
assert_eq!(*expected_digest, actual_digest);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn skips_encoding_signature_tlv_records() {
|
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 secp_ctx = Secp256k1::new();
|
||||||
|
let payment_id = PaymentId([1; 32]);
|
||||||
|
|
||||||
let recipient_pubkey = {
|
let recipient_pubkey = {
|
||||||
let secret_key = SecretKey::from_slice(&[41; 32]).unwrap();
|
let secret_key = SecretKey::from_slice(&[41; 32]).unwrap();
|
||||||
Keypair::from_secret_key(&secp_ctx, &secret_key).public_key()
|
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)
|
let invoice_request = OfferBuilder::new(recipient_pubkey)
|
||||||
.amount_msats(100)
|
.amount_msats(100)
|
||||||
.build_unchecked()
|
.build_unchecked()
|
||||||
.request_invoice(vec![0; 8], payer_keys.public_key()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build_unchecked()
|
.build_and_sign().unwrap();
|
||||||
.sign(|message: &UnsignedInvoiceRequest|
|
|
||||||
Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &payer_keys))
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut bytes_without_signature = Vec::new();
|
let mut bytes_without_signature = Vec::new();
|
||||||
let tlv_stream_without_signatures = TlvStream::new(&invoice_request.bytes)
|
let tlv_stream_without_signatures = TlvStream::new(&invoice_request.bytes)
|
||||||
@ -420,24 +433,21 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn iterates_over_tlv_stream_range() {
|
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 secp_ctx = Secp256k1::new();
|
||||||
|
let payment_id = PaymentId([1; 32]);
|
||||||
|
|
||||||
let recipient_pubkey = {
|
let recipient_pubkey = {
|
||||||
let secret_key = SecretKey::from_slice(&[41; 32]).unwrap();
|
let secret_key = SecretKey::from_slice(&[41; 32]).unwrap();
|
||||||
Keypair::from_secret_key(&secp_ctx, &secret_key).public_key()
|
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)
|
let invoice_request = OfferBuilder::new(recipient_pubkey)
|
||||||
.amount_msats(100)
|
.amount_msats(100)
|
||||||
.build_unchecked()
|
.build_unchecked()
|
||||||
.request_invoice(vec![0; 8], payer_keys.public_key()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build_unchecked()
|
.build_and_sign()
|
||||||
.sign(|message: &UnsignedInvoiceRequest|
|
|
||||||
Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &payer_keys))
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let tlv_stream = TlvStream::new(&invoice_request.bytes).range(0..1)
|
let tlv_stream = TlvStream::new(&invoice_request.bytes).range(0..1)
|
||||||
|
@ -100,11 +100,11 @@ use crate::util::string::PrintableString;
|
|||||||
|
|
||||||
#[cfg(not(c_bindings))]
|
#[cfg(not(c_bindings))]
|
||||||
use {
|
use {
|
||||||
crate::offers::invoice_request::{DerivedPayerSigningPubkey, ExplicitPayerSigningPubkey, InvoiceRequestBuilder},
|
crate::offers::invoice_request::InvoiceRequestBuilder,
|
||||||
};
|
};
|
||||||
#[cfg(c_bindings)]
|
#[cfg(c_bindings)]
|
||||||
use {
|
use {
|
||||||
crate::offers::invoice_request::{InvoiceRequestWithDerivedPayerSigningPubkeyBuilder, InvoiceRequestWithExplicitPayerSigningPubkeyBuilder},
|
crate::offers::invoice_request::InvoiceRequestWithDerivedPayerSigningPubkeyBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
@ -729,23 +729,23 @@ impl Offer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! request_invoice_derived_signing_pubkey { ($self: ident, $builder: ty) => {
|
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
|
/// - derives the [`InvoiceRequest::payer_signing_pubkey`] such that a different key can be used
|
||||||
/// for each request,
|
/// for each request in order to protect the sender's privacy,
|
||||||
/// - sets [`InvoiceRequest::payer_metadata`] when [`InvoiceRequestBuilder::build`] is called
|
/// - sets [`InvoiceRequest::payer_metadata`] when [`InvoiceRequestBuilder::build_and_sign`] is
|
||||||
/// such that it can be used by [`Bolt12Invoice::verify_using_metadata`] to determine if the
|
/// called such that it can be used by [`Bolt12Invoice::verify_using_metadata`] to determine
|
||||||
/// invoice was requested using a base [`ExpandedKey`] from which the payer id was derived,
|
/// if the invoice was requested using a base [`ExpandedKey`] from which the payer id was
|
||||||
/// and
|
/// derived, and
|
||||||
/// - includes the [`PaymentId`] encrypted in [`InvoiceRequest::payer_metadata`] so that it can
|
/// - includes the [`PaymentId`] encrypted in [`InvoiceRequest::payer_metadata`] so that it can
|
||||||
/// be used when sending the payment for the requested invoice.
|
/// 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_signing_pubkey`]: crate::offers::invoice_request::InvoiceRequest::payer_signing_pubkey
|
||||||
/// [`InvoiceRequest::payer_metadata`]: crate::offers::invoice_request::InvoiceRequest::payer_metadata
|
/// [`InvoiceRequest::payer_metadata`]: crate::offers::invoice_request::InvoiceRequest::payer_metadata
|
||||||
/// [`Bolt12Invoice::verify_using_metadata`]: crate::offers::invoice::Bolt12Invoice::verify_using_metadata
|
/// [`Bolt12Invoice::verify_using_metadata`]: crate::offers::invoice::Bolt12Invoice::verify_using_metadata
|
||||||
/// [`ExpandedKey`]: crate::ln::inbound_payment::ExpandedKey
|
/// [`ExpandedKey`]: crate::ln::inbound_payment::ExpandedKey
|
||||||
pub fn request_invoice_deriving_signing_pubkey<
|
pub fn request_invoice<
|
||||||
'a, 'b,
|
'a, 'b,
|
||||||
#[cfg(not(c_bindings))]
|
#[cfg(not(c_bindings))]
|
||||||
T: secp256k1::Signing
|
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))]
|
#[cfg(not(c_bindings))]
|
||||||
impl Offer {
|
impl Offer {
|
||||||
request_invoice_derived_signing_pubkey!(self, InvoiceRequestBuilder<'a, 'b, DerivedPayerSigningPubkey, T>);
|
request_invoice_derived_signing_pubkey!(self, InvoiceRequestBuilder<'a, 'b, T>);
|
||||||
request_invoice_explicit_signing_pubkey!(self, InvoiceRequestBuilder<ExplicitPayerSigningPubkey, secp256k1::SignOnly>);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(c_bindings)]
|
#[cfg(c_bindings)]
|
||||||
impl Offer {
|
impl Offer {
|
||||||
request_invoice_derived_signing_pubkey!(self, InvoiceRequestWithDerivedPayerSigningPubkeyBuilder<'a, 'b>);
|
request_invoice_derived_signing_pubkey!(self, InvoiceRequestWithDerivedPayerSigningPubkeyBuilder<'a, 'b>);
|
||||||
request_invoice_explicit_signing_pubkey!(self, InvoiceRequestWithExplicitPayerSigningPubkeyBuilder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -1267,6 +1222,7 @@ mod tests {
|
|||||||
use crate::blinded_path::message::BlindedMessagePath;
|
use crate::blinded_path::message::BlindedMessagePath;
|
||||||
use crate::sign::KeyMaterial;
|
use crate::sign::KeyMaterial;
|
||||||
use crate::types::features::OfferFeatures;
|
use crate::types::features::OfferFeatures;
|
||||||
|
use crate::ln::channelmanager::PaymentId;
|
||||||
use crate::ln::inbound_payment::ExpandedKey;
|
use crate::ln::inbound_payment::ExpandedKey;
|
||||||
use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
|
use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
|
||||||
use crate::offers::nonce::Nonce;
|
use crate::offers::nonce::Nonce;
|
||||||
@ -1391,6 +1347,7 @@ mod tests {
|
|||||||
let entropy = FixedEntropy {};
|
let entropy = FixedEntropy {};
|
||||||
let nonce = Nonce::from_entropy_source(&entropy);
|
let nonce = Nonce::from_entropy_source(&entropy);
|
||||||
let secp_ctx = Secp256k1::new();
|
let secp_ctx = Secp256k1::new();
|
||||||
|
let payment_id = PaymentId([1; 32]);
|
||||||
|
|
||||||
#[cfg(c_bindings)]
|
#[cfg(c_bindings)]
|
||||||
use super::OfferWithDerivedMetadataBuilder as OfferBuilder;
|
use super::OfferWithDerivedMetadataBuilder as OfferBuilder;
|
||||||
@ -1401,18 +1358,18 @@ mod tests {
|
|||||||
assert!(offer.metadata().is_some());
|
assert!(offer.metadata().is_some());
|
||||||
assert_eq!(offer.issuer_signing_pubkey(), Some(node_id));
|
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
|
||||||
.build().unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.sign(payer_sign).unwrap();
|
.build_and_sign().unwrap();
|
||||||
match invoice_request.verify_using_metadata(&expanded_key, &secp_ctx) {
|
match invoice_request.verify_using_metadata(&expanded_key, &secp_ctx) {
|
||||||
Ok(invoice_request) => assert_eq!(invoice_request.offer_id, offer.id()),
|
Ok(invoice_request) => assert_eq!(invoice_request.offer_id, offer.id()),
|
||||||
Err(_) => panic!("unexpected error"),
|
Err(_) => panic!("unexpected error"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fails verification when using the wrong method
|
// Fails verification when using the wrong method
|
||||||
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
let invoice_request = offer
|
||||||
.build().unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.sign(payer_sign).unwrap();
|
.build_and_sign().unwrap();
|
||||||
assert!(
|
assert!(
|
||||||
invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).is_err()
|
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();
|
tlv_stream.write(&mut encoded_offer).unwrap();
|
||||||
|
|
||||||
let invoice_request = Offer::try_from(encoded_offer).unwrap()
|
let invoice_request = Offer::try_from(encoded_offer).unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap();
|
||||||
.sign(payer_sign).unwrap();
|
|
||||||
assert!(invoice_request.verify_using_metadata(&expanded_key, &secp_ctx).is_err());
|
assert!(invoice_request.verify_using_metadata(&expanded_key, &secp_ctx).is_err());
|
||||||
|
|
||||||
// Fails verification with altered metadata
|
// Fails verification with altered metadata
|
||||||
@ -1439,9 +1395,8 @@ mod tests {
|
|||||||
tlv_stream.write(&mut encoded_offer).unwrap();
|
tlv_stream.write(&mut encoded_offer).unwrap();
|
||||||
|
|
||||||
let invoice_request = Offer::try_from(encoded_offer).unwrap()
|
let invoice_request = Offer::try_from(encoded_offer).unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap();
|
||||||
.sign(payer_sign).unwrap();
|
|
||||||
assert!(invoice_request.verify_using_metadata(&expanded_key, &secp_ctx).is_err());
|
assert!(invoice_request.verify_using_metadata(&expanded_key, &secp_ctx).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1452,6 +1407,7 @@ mod tests {
|
|||||||
let entropy = FixedEntropy {};
|
let entropy = FixedEntropy {};
|
||||||
let nonce = Nonce::from_entropy_source(&entropy);
|
let nonce = Nonce::from_entropy_source(&entropy);
|
||||||
let secp_ctx = Secp256k1::new();
|
let secp_ctx = Secp256k1::new();
|
||||||
|
let payment_id = PaymentId([1; 32]);
|
||||||
|
|
||||||
let blinded_path = BlindedMessagePath::from_raw(
|
let blinded_path = BlindedMessagePath::from_raw(
|
||||||
pubkey(40), pubkey(41),
|
pubkey(40), pubkey(41),
|
||||||
@ -1471,18 +1427,18 @@ mod tests {
|
|||||||
assert!(offer.metadata().is_none());
|
assert!(offer.metadata().is_none());
|
||||||
assert_ne!(offer.issuer_signing_pubkey(), Some(node_id));
|
assert_ne!(offer.issuer_signing_pubkey(), Some(node_id));
|
||||||
|
|
||||||
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
let invoice_request = offer
|
||||||
.build().unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.sign(payer_sign).unwrap();
|
.build_and_sign().unwrap();
|
||||||
match invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx) {
|
match invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx) {
|
||||||
Ok(invoice_request) => assert_eq!(invoice_request.offer_id, offer.id()),
|
Ok(invoice_request) => assert_eq!(invoice_request.offer_id, offer.id()),
|
||||||
Err(_) => panic!("unexpected error"),
|
Err(_) => panic!("unexpected error"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fails verification when using the wrong method
|
// Fails verification when using the wrong method
|
||||||
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
let invoice_request = offer
|
||||||
.build().unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.sign(payer_sign).unwrap();
|
.build_and_sign().unwrap();
|
||||||
assert!(invoice_request.verify_using_metadata(&expanded_key, &secp_ctx).is_err());
|
assert!(invoice_request.verify_using_metadata(&expanded_key, &secp_ctx).is_err());
|
||||||
|
|
||||||
// Fails verification with altered offer field
|
// Fails verification with altered offer field
|
||||||
@ -1493,9 +1449,8 @@ mod tests {
|
|||||||
tlv_stream.write(&mut encoded_offer).unwrap();
|
tlv_stream.write(&mut encoded_offer).unwrap();
|
||||||
|
|
||||||
let invoice_request = Offer::try_from(encoded_offer).unwrap()
|
let invoice_request = Offer::try_from(encoded_offer).unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap();
|
||||||
.sign(payer_sign).unwrap();
|
|
||||||
assert!(
|
assert!(
|
||||||
invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).is_err()
|
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();
|
tlv_stream.write(&mut encoded_offer).unwrap();
|
||||||
|
|
||||||
let invoice_request = Offer::try_from(encoded_offer).unwrap()
|
let invoice_request = Offer::try_from(encoded_offer).unwrap()
|
||||||
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
|
||||||
.build().unwrap()
|
.build_and_sign().unwrap();
|
||||||
.sign(payer_sign).unwrap();
|
|
||||||
assert!(
|
assert!(
|
||||||
invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).is_err()
|
invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).is_err()
|
||||||
);
|
);
|
||||||
@ -1738,10 +1692,16 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fails_requesting_invoice_with_unknown_required_features() {
|
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))
|
match OfferBuilder::new(pubkey(42))
|
||||||
.features_unchecked(OfferFeatures::unknown())
|
.features_unchecked(OfferFeatures::unknown())
|
||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
.request_invoice(vec![1; 32], pubkey(43))
|
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id)
|
||||||
{
|
{
|
||||||
Ok(_) => panic!("expected error"),
|
Ok(_) => panic!("expected error"),
|
||||||
Err(e) => assert_eq!(e, Bolt12SemanticError::UnknownRequiredFeatures),
|
Err(e) => assert_eq!(e, Bolt12SemanticError::UnknownRequiredFeatures),
|
||||||
|
@ -56,7 +56,6 @@ use crate::ln::msgs::PartialSignatureWithNonce;
|
|||||||
use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage};
|
use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage};
|
||||||
use crate::ln::script::ShutdownScript;
|
use crate::ln::script::ShutdownScript;
|
||||||
use crate::offers::invoice::UnsignedBolt12Invoice;
|
use crate::offers::invoice::UnsignedBolt12Invoice;
|
||||||
use crate::offers::invoice_request::UnsignedInvoiceRequest;
|
|
||||||
use crate::types::payment::PaymentPreimage;
|
use crate::types::payment::PaymentPreimage;
|
||||||
use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer};
|
use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer};
|
||||||
use crate::util::transaction_utils;
|
use crate::util::transaction_utils;
|
||||||
@ -870,21 +869,6 @@ pub trait NodeSigner {
|
|||||||
&self, invoice: &RawBolt11Invoice, recipient: Recipient,
|
&self, invoice: &RawBolt11Invoice, recipient: Recipient,
|
||||||
) -> Result<RecoverableSignature, ()>;
|
) -> Result<RecoverableSignature, ()>;
|
||||||
|
|
||||||
/// Signs the [`TaggedHash`] of a BOLT 12 invoice request.
|
|
||||||
///
|
|
||||||
/// May be called by a function passed to [`UnsignedInvoiceRequest::sign`] where
|
|
||||||
/// `invoice_request` is the callee.
|
|
||||||
///
|
|
||||||
/// Implementors may check that the `invoice_request` is expected rather than blindly signing
|
|
||||||
/// the tagged hash. An `Ok` result should sign `invoice_request.tagged_hash().as_digest()` with
|
|
||||||
/// the node's signing key or an ephemeral key to preserve privacy, whichever is associated with
|
|
||||||
/// [`UnsignedInvoiceRequest::payer_signing_pubkey`].
|
|
||||||
///
|
|
||||||
/// [`TaggedHash`]: crate::offers::merkle::TaggedHash
|
|
||||||
fn sign_bolt12_invoice_request(
|
|
||||||
&self, invoice_request: &UnsignedInvoiceRequest,
|
|
||||||
) -> Result<schnorr::Signature, ()>;
|
|
||||||
|
|
||||||
/// Signs the [`TaggedHash`] of a BOLT 12 invoice.
|
/// Signs the [`TaggedHash`] of a BOLT 12 invoice.
|
||||||
///
|
///
|
||||||
/// May be called by a function passed to [`UnsignedBolt12Invoice::sign`] where `invoice` is the
|
/// May be called by a function passed to [`UnsignedBolt12Invoice::sign`] where `invoice` is the
|
||||||
@ -2206,15 +2190,6 @@ impl NodeSigner for KeysManager {
|
|||||||
Ok(self.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&hash), secret))
|
Ok(self.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&hash), secret))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_bolt12_invoice_request(
|
|
||||||
&self, invoice_request: &UnsignedInvoiceRequest,
|
|
||||||
) -> Result<schnorr::Signature, ()> {
|
|
||||||
let message = invoice_request.tagged_hash().as_digest();
|
|
||||||
let keys = Keypair::from_secret_key(&self.secp_ctx, &self.node_secret);
|
|
||||||
let aux_rand = self.get_secure_random_bytes();
|
|
||||||
Ok(self.secp_ctx.sign_schnorr_with_aux_rand(message, &keys, &aux_rand))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sign_bolt12_invoice(
|
fn sign_bolt12_invoice(
|
||||||
&self, invoice: &UnsignedBolt12Invoice,
|
&self, invoice: &UnsignedBolt12Invoice,
|
||||||
) -> Result<schnorr::Signature, ()> {
|
) -> Result<schnorr::Signature, ()> {
|
||||||
@ -2384,12 +2359,6 @@ impl NodeSigner for PhantomKeysManager {
|
|||||||
Ok(self.inner.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&hash), secret))
|
Ok(self.inner.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&hash), secret))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_bolt12_invoice_request(
|
|
||||||
&self, invoice_request: &UnsignedInvoiceRequest,
|
|
||||||
) -> Result<schnorr::Signature, ()> {
|
|
||||||
self.inner.sign_bolt12_invoice_request(invoice_request)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sign_bolt12_invoice(
|
fn sign_bolt12_invoice(
|
||||||
&self, invoice: &UnsignedBolt12Invoice,
|
&self, invoice: &UnsignedBolt12Invoice,
|
||||||
) -> Result<schnorr::Signature, ()> {
|
) -> Result<schnorr::Signature, ()> {
|
||||||
|
@ -34,7 +34,6 @@ use crate::ln::{msgs, wire};
|
|||||||
use crate::ln::msgs::LightningError;
|
use crate::ln::msgs::LightningError;
|
||||||
use crate::ln::script::ShutdownScript;
|
use crate::ln::script::ShutdownScript;
|
||||||
use crate::offers::invoice::UnsignedBolt12Invoice;
|
use crate::offers::invoice::UnsignedBolt12Invoice;
|
||||||
use crate::offers::invoice_request::UnsignedInvoiceRequest;
|
|
||||||
use crate::onion_message::messenger::{DefaultMessageRouter, Destination, MessageRouter, OnionMessagePath};
|
use crate::onion_message::messenger::{DefaultMessageRouter, Destination, MessageRouter, OnionMessagePath};
|
||||||
use crate::routing::gossip::{EffectiveCapacity, NetworkGraph, NodeId, RoutingFees};
|
use crate::routing::gossip::{EffectiveCapacity, NetworkGraph, NodeId, RoutingFees};
|
||||||
use crate::routing::utxo::{UtxoLookup, UtxoLookupError, UtxoResult};
|
use crate::routing::utxo::{UtxoLookup, UtxoLookupError, UtxoResult};
|
||||||
@ -1216,12 +1215,6 @@ impl NodeSigner for TestNodeSigner {
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_bolt12_invoice_request(
|
|
||||||
&self, _invoice_request: &UnsignedInvoiceRequest
|
|
||||||
) -> Result<schnorr::Signature, ()> {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sign_bolt12_invoice(
|
fn sign_bolt12_invoice(
|
||||||
&self, _invoice: &UnsignedBolt12Invoice,
|
&self, _invoice: &UnsignedBolt12Invoice,
|
||||||
) -> Result<schnorr::Signature, ()> {
|
) -> Result<schnorr::Signature, ()> {
|
||||||
@ -1269,12 +1262,6 @@ impl NodeSigner for TestKeysInterface {
|
|||||||
self.backing.sign_invoice(invoice, recipient)
|
self.backing.sign_invoice(invoice, recipient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_bolt12_invoice_request(
|
|
||||||
&self, invoice_request: &UnsignedInvoiceRequest
|
|
||||||
) -> Result<schnorr::Signature, ()> {
|
|
||||||
self.backing.sign_bolt12_invoice_request(invoice_request)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sign_bolt12_invoice(
|
fn sign_bolt12_invoice(
|
||||||
&self, invoice: &UnsignedBolt12Invoice,
|
&self, invoice: &UnsignedBolt12Invoice,
|
||||||
) -> Result<schnorr::Signature, ()> {
|
) -> Result<schnorr::Signature, ()> {
|
||||||
|
Loading…
Reference in New Issue
Block a user