let even_pubkey = x_only_pubkey.public_key(Parity::Even);
if signing_pubkey == odd_pubkey || signing_pubkey == even_pubkey {
unsigned_invoice
- .sign::<_, Infallible>(
- |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
- )
+ .sign(|message: &UnsignedBolt12Invoice| -> Result<_, Infallible> {
+ Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
+ })
.unwrap()
.write(&mut buffer)
.unwrap();
} else {
unsigned_invoice
- .sign::<_, Infallible>(
- |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
- )
+ .sign(|message: &UnsignedBolt12Invoice| -> Result<_, Infallible> {
+ Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
+ })
.unwrap_err();
}
}
if let Ok(invoice_request) = build_response(&offer, pubkey) {
invoice_request
- .sign::<_, Infallible>(
- |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
- )
+ .sign(|message: &UnsignedInvoiceRequest| -> Result<_, Infallible> {
+ Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
+ })
.unwrap()
.write(&mut buffer)
.unwrap();
if let Ok(invoice) = build_response(&refund, pubkey, &secp_ctx) {
invoice
- .sign::<_, Infallible>(
- |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
- )
+ .sign(|message: &UnsignedBolt12Invoice| -> Result<_, Infallible> {
+ Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
+ })
.unwrap()
.write(&mut buffer)
.unwrap();
use crate::ln::outbound_payment;
use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, PaymentAttempts, PendingOutboundPayment, SendAlongPathArgs, StaleExpiration};
use crate::ln::wire::Encode;
-use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder};
+use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice};
use crate::offers::invoice_error::InvoiceError;
use crate::offers::invoice_request::{DerivedPayerId, InvoiceRequestBuilder};
use crate::offers::merkle::SignError;
.and_then(|invoice| {
#[cfg(c_bindings)]
let mut invoice = invoice;
- match invoice.sign(|invoice| self.node_signer.sign_bolt12_invoice(invoice)) {
+ match invoice.sign(|invoice: &UnsignedBolt12Invoice|
+ self.node_signer.sign_bolt12_invoice(invoice)
+ ) {
Ok(invoice) => Ok(OffersMessage::Invoice(invoice)),
Err(SignError::Signing(())) => Err(OffersMessage::InvoiceError(
InvoiceError::from_string("Failed signing invoice".to_string())
//! use bitcoin::hashes::Hash;
//! use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey};
//! use core::convert::{Infallible, TryFrom};
+//! use lightning::offers::invoice::UnsignedBolt12Invoice;
//! use lightning::offers::invoice_request::InvoiceRequest;
//! use lightning::offers::refund::Refund;
//! use lightning::util::ser::Writeable;
//! .allow_mpp()
//! .fallback_v0_p2wpkh(&wpubkey_hash)
//! .build()?
-//! .sign::<_, Infallible>(
-//! |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
-//! )
+//! .sign(|message: &UnsignedBolt12Invoice| -> Result<_, Infallible> {
+//! Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
+//! })
//! .expect("failed verifying signature")
//! .write(&mut buffer)
//! .unwrap();
//! .allow_mpp()
//! .fallback_v0_p2wpkh(&wpubkey_hash)
//! .build()?
-//! .sign::<_, Infallible>(
-//! |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
-//! )
+//! .sign(|message: &UnsignedBolt12Invoice| -> Result<_, Infallible> {
+//! Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
+//! })
//! .expect("failed verifying signature")
//! .write(&mut buffer)
//! .unwrap();
use crate::ln::inbound_payment::ExpandedKey;
use crate::ln::msgs::DecodeError;
use crate::offers::invoice_request::{INVOICE_REQUEST_PAYER_ID_TYPE, INVOICE_REQUEST_TYPES, IV_BYTES as INVOICE_REQUEST_IV_BYTES, InvoiceRequest, InvoiceRequestContents, InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef};
-use crate::offers::merkle::{SignError, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, TlvStream, WithoutSignatures, self};
+use crate::offers::merkle::{SignError, SignFn, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, TlvStream, WithoutSignatures, self};
use crate::offers::offer::{Amount, OFFER_TYPES, OfferTlvStream, OfferTlvStreamRef, Quantity};
use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
use crate::offers::payer::{PAYER_METADATA_TYPE, PayerTlvStream, PayerTlvStreamRef};
let mut unsigned_invoice = UnsignedBolt12Invoice::new(invreq_bytes, invoice.clone());
let invoice = unsigned_invoice
- .sign::<_, Infallible>(
- |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
- )
+ .sign(|message: &UnsignedBolt12Invoice| -> Result<_, Infallible> {
+ Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
+ })
.unwrap();
Ok(invoice)
}
tagged_hash: TaggedHash,
}
+/// A function for signing an [`UnsignedBolt12Invoice`].
+pub trait SignBolt12InvoiceFn {
+ /// Error type returned by the function.
+ type Error;
+
+ /// Signs a [`TaggedHash`] computed over the merkle root of `message`'s TLV stream.
+ fn sign_invoice(&self, message: &UnsignedBolt12Invoice) -> Result<Signature, Self::Error>;
+}
+
+impl<F, E> SignBolt12InvoiceFn for F
+where
+ F: Fn(&UnsignedBolt12Invoice) -> Result<Signature, E>,
+{
+ type Error = E;
+
+ fn sign_invoice(&self, message: &UnsignedBolt12Invoice) -> Result<Signature, E> {
+ self(message)
+ }
+}
+
+impl<F, E> SignFn<UnsignedBolt12Invoice> for F
+where
+ F: SignBolt12InvoiceFn<Error = E>,
+{
+ type Error = E;
+
+ fn sign(&self, message: &UnsignedBolt12Invoice) -> Result<Signature, Self::Error> {
+ self.sign_invoice(message)
+ }
+}
+
impl UnsignedBolt12Invoice {
fn new(invreq_bytes: &[u8], contents: InvoiceContents) -> Self {
// Use the invoice_request bytes instead of the invoice_request TLV stream as the latter may
/// Signs the [`TaggedHash`] of the invoice using the given function.
///
/// Note: The hash computation may have included unknown, odd TLV records.
- ///
- /// This is not exported to bindings users as functions aren't currently mapped.
- pub fn sign<F, E>($($self_mut)* $self: $self_type, sign: F) -> Result<Bolt12Invoice, SignError<E>>
- where
- F: FnOnce(&Self) -> Result<Signature, E>
- {
+ pub fn sign<F: SignBolt12InvoiceFn>(
+ $($self_mut)* $self: $self_type, sign: F
+ ) -> Result<Bolt12Invoice, SignError<F::Error>> {
let pubkey = $self.contents.fields().signing_pubkey;
let signature = merkle::sign_message(sign, &$self, pubkey)?;
.sign(payer_sign).unwrap()
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
.build().unwrap()
- .sign(|_| Err(()))
+ .sign(fail_sign)
{
Ok(_) => panic!("expected error"),
Err(e) => assert_eq!(e, SignError::Signing(())),
//! use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey};
//! use core::convert::Infallible;
//! use lightning::ln::features::OfferFeatures;
+//! use lightning::offers::invoice_request::UnsignedInvoiceRequest;
//! use lightning::offers::offer::Offer;
//! use lightning::util::ser::Writeable;
//!
//! .quantity(5)?
//! .payer_note("foo".to_string())
//! .build()?
-//! .sign::<_, Infallible>(
-//! |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
-//! )
+//! .sign(|message: &UnsignedInvoiceRequest| -> Result<_, Infallible> {
+//! Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
+//! })
//! .expect("failed verifying signature")
//! .write(&mut buffer)
//! .unwrap();
use crate::ln::inbound_payment::{ExpandedKey, IV_LEN, Nonce};
use crate::ln::msgs::DecodeError;
use crate::offers::invoice::BlindedPayInfo;
-use crate::offers::merkle::{SignError, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, self};
+use crate::offers::merkle::{SignError, SignFn, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, self};
use crate::offers::offer::{Offer, OfferContents, OfferTlvStream, OfferTlvStreamRef};
use crate::offers::parse::{Bolt12ParseError, ParsedMessage, Bolt12SemanticError};
use crate::offers::payer::{PayerContents, PayerTlvStream, PayerTlvStreamRef};
let secp_ctx = secp_ctx.unwrap();
let keys = keys.unwrap();
let invoice_request = unsigned_invoice_request
- .sign::<_, Infallible>(
- |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
- )
+ .sign(|message: &UnsignedInvoiceRequest| -> Result<_, Infallible> {
+ Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
+ })
.unwrap();
Ok(invoice_request)
}
tagged_hash: TaggedHash,
}
+/// A function for signing an [`UnsignedInvoiceRequest`].
+pub trait SignInvoiceRequestFn {
+ /// Error type returned by the function.
+ type Error;
+
+ /// Signs a [`TaggedHash`] computed over the merkle root of `message`'s TLV stream.
+ fn sign_invoice_request(&self, message: &UnsignedInvoiceRequest) -> Result<Signature, Self::Error>;
+}
+
+impl<F, E> SignInvoiceRequestFn for F
+where
+ F: Fn(&UnsignedInvoiceRequest) -> Result<Signature, E>,
+{
+ type Error = E;
+
+ fn sign_invoice_request(&self, message: &UnsignedInvoiceRequest) -> Result<Signature, E> {
+ self(message)
+ }
+}
+
+impl<F, E> SignFn<UnsignedInvoiceRequest> for F
+where
+ F: SignInvoiceRequestFn<Error = E>,
+{
+ type Error = E;
+
+ fn sign(&self, message: &UnsignedInvoiceRequest) -> Result<Signature, Self::Error> {
+ self.sign_invoice_request(message)
+ }
+}
+
impl UnsignedInvoiceRequest {
fn new(offer: &Offer, contents: InvoiceRequestContents) -> Self {
// Use the offer bytes instead of the offer TLV stream as the offer may have contained
/// Signs the [`TaggedHash`] of the invoice request using the given function.
///
/// Note: The hash computation may have included unknown, odd TLV records.
- ///
- /// This is not exported to bindings users as functions are not yet mapped.
- pub fn sign<F, E>($($self_mut)* $self: $self_type, sign: F) -> Result<InvoiceRequest, SignError<E>>
- where
- F: FnOnce(&Self) -> Result<Signature, E>
- {
+ pub fn sign<F: SignInvoiceRequestFn>(
+ $($self_mut)* $self: $self_type, sign: F
+ ) -> Result<InvoiceRequest, SignError<F::Error>> {
let pubkey = $self.contents.payer_id;
let signature = merkle::sign_message(sign, &$self, pubkey)?;
.build().unwrap()
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
.build().unwrap()
- .sign(|_| Err(()))
+ .sign(fail_sign)
{
Ok(_) => panic!("expected error"),
Err(e) => assert_eq!(e, SignError::Signing(())),
.build().unwrap()
.request_invoice(vec![1; 32], keys.public_key()).unwrap()
.build().unwrap()
- .sign::<_, Infallible>(
- |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
- )
+ .sign(|message: &UnsignedInvoiceRequest| -> Result<_, Infallible> {
+ Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
+ })
.unwrap();
let mut encoded_invoice_request = Vec::new();
/// Error when signing messages.
#[derive(Debug, PartialEq)]
-pub enum SignError<E> {
+pub enum SignError<E = ()> {
/// User-defined error when signing the message.
Signing(E),
/// Error when verifying the produced signature using the given pubkey.
Verification(secp256k1::Error),
}
+/// A function for signing a [`TaggedHash`].
+pub(super) trait SignFn<T: AsRef<TaggedHash>> {
+ /// Error type returned by the function.
+ type Error;
+
+ /// Signs a [`TaggedHash`] computed over the merkle root of `message`'s TLV stream.
+ fn sign(&self, message: &T) -> Result<Signature, Self::Error>;
+}
+
+impl<F, E> SignFn<TaggedHash> for F
+where
+ F: Fn(&TaggedHash) -> Result<Signature, E>,
+{
+ type Error = E;
+
+ fn sign(&self, message: &TaggedHash) -> Result<Signature, E> {
+ self(message)
+ }
+}
+
/// Signs a [`TaggedHash`] computed over the merkle root of `message`'s TLV stream, checking if it
/// can be verified with the supplied `pubkey`.
///
///
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
-pub(super) fn sign_message<F, E, T>(
- sign: F, message: &T, pubkey: PublicKey,
+pub(super) fn sign_message<F, T, E>(
+ f: F, message: &T, pubkey: PublicKey,
) -> Result<Signature, SignError<E>>
where
- F: FnOnce(&T) -> Result<Signature, E>,
+ F: SignFn<T, Error = E>,
T: AsRef<TaggedHash>,
{
- let signature = sign(message).map_err(|e| SignError::Signing(e))?;
+ let signature = f.sign(message).map_err(|e| SignError::Signing(e))?;
let digest = message.as_ref().as_digest();
let pubkey = pubkey.into();
use bitcoin::secp256k1::schnorr::Signature;
use core::convert::Infallible;
use crate::offers::offer::{Amount, OfferBuilder};
- use crate::offers::invoice_request::InvoiceRequest;
+ use crate::offers::invoice_request::{InvoiceRequest, UnsignedInvoiceRequest};
use crate::offers::parse::Bech32Encode;
use crate::offers::test_utils::{payer_pubkey, recipient_pubkey};
use crate::util::ser::Writeable;
.build_unchecked()
.request_invoice(vec![0; 8], payer_keys.public_key()).unwrap()
.build_unchecked()
- .sign::<_, Infallible>(
- |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &payer_keys))
- )
+ .sign(|message: &UnsignedInvoiceRequest| -> Result<_, Infallible> {
+ Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &payer_keys))
+ })
.unwrap();
assert_eq!(
invoice_request.to_string(),
.build_unchecked()
.request_invoice(vec![0; 8], payer_keys.public_key()).unwrap()
.build_unchecked()
- .sign::<_, Infallible>(
- |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &payer_keys))
- )
+ .sign(|message: &UnsignedInvoiceRequest| -> Result<_, Infallible> {
+ Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &payer_keys))
+ })
.unwrap();
let mut bytes_without_signature = Vec::new();
.build_unchecked()
.request_invoice(vec![0; 8], payer_keys.public_key()).unwrap()
.build_unchecked()
- .sign::<_, Infallible>(
- |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &payer_keys))
- )
+ .sign(|message: &UnsignedInvoiceRequest| -> Result<_, Infallible> {
+ Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &payer_keys))
+ })
.unwrap();
let tlv_stream = TlvStream::new(&invoice_request.bytes).range(0..1)
use crate::offers::invoice::BlindedPayInfo;
use crate::offers::merkle::TaggedHash;
+pub(crate) fn fail_sign<T: AsRef<TaggedHash>>(_message: &T) -> Result<Signature, ()> {
+ Err(())
+}
+
pub(crate) fn payer_keys() -> KeyPair {
let secp_ctx = Secp256k1::new();
KeyPair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap())