use crate::io;
use crate::blinded_path::BlindedPath;
use crate::ln::PaymentHash;
+use crate::ln::channelmanager::PaymentId;
use crate::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures};
use crate::ln::inbound_payment::ExpandedKey;
use crate::ln::msgs::DecodeError;
#[cfg(feature = "std")]
use std::time::SystemTime;
-const DEFAULT_RELATIVE_EXPIRY: Duration = Duration::from_secs(7200);
+pub(crate) const DEFAULT_RELATIVE_EXPIRY: Duration = Duration::from_secs(7200);
/// Tag for the hash function used when signing a [`Bolt12Invoice`]'s merkle root.
pub const SIGNATURE_TAG: &'static str = concat!("lightning", "invoice", "signature");
Self { bytes, contents, tagged_hash }
}
+ /// Returns the [`TaggedHash`] of the invoice to sign.
+ pub fn tagged_hash(&self) -> &TaggedHash {
+ &self.tagged_hash
+ }
+
/// Signs the [`TaggedHash`] of the invoice using the given function.
///
/// Note: The hash computation may have included unknown, odd TLV records.
merkle::message_digest(SIGNATURE_TAG, &self.bytes).as_ref().clone()
}
- /// Verifies that the invoice was for a request or refund created using the given key.
+ /// Verifies that the invoice was for a request or refund created using the given key. Returns
+ /// the associated [`PaymentId`] to use when sending the payment.
pub fn verify<T: secp256k1::Signing>(
&self, key: &ExpandedKey, secp_ctx: &Secp256k1<T>
- ) -> bool {
+ ) -> Result<PaymentId, ()> {
self.contents.verify(TlvStream::new(&self.bytes), key, secp_ctx)
}
fn verify<T: secp256k1::Signing>(
&self, tlv_stream: TlvStream<'_>, key: &ExpandedKey, secp_ctx: &Secp256k1<T>
- ) -> bool {
+ ) -> Result<PaymentId, ()> {
let offer_records = tlv_stream.clone().range(OFFER_TYPES);
let invreq_records = tlv_stream.range(INVOICE_REQUEST_TYPES).filter(|record| {
match record.r#type {
},
};
- match signer::verify_metadata(metadata, key, iv_bytes, payer_id, tlv_stream, secp_ctx) {
- Ok(_) => true,
- Err(()) => false,
- }
+ signer::verify_payer_metadata(metadata, key, iv_bytes, payer_id, tlv_stream, secp_ctx)
}
fn derives_keys(&self) -> bool {
None => return Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSignature)),
Some(signature) => signature,
};
+ let message = TaggedHash::new(SIGNATURE_TAG, &bytes);
let pubkey = contents.fields().signing_pubkey;
- merkle::verify_signature(&signature, SIGNATURE_TAG, &bytes, pubkey)?;
+ merkle::verify_signature(&signature, message, pubkey)?;
Ok(Bolt12Invoice { bytes, contents, signature })
}
use crate::ln::inbound_payment::ExpandedKey;
use crate::ln::msgs::DecodeError;
use crate::offers::invoice_request::InvoiceRequestTlvStreamRef;
- use crate::offers::merkle::{SignError, SignatureTlvStreamRef, self};
+ use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, self};
use crate::offers::offer::{Amount, OfferBuilder, OfferTlvStreamRef, Quantity};
use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError};
use crate::offers::payer::PayerTlvStreamRef;
assert_eq!(invoice.fallbacks(), vec![]);
assert_eq!(invoice.invoice_features(), &Bolt12InvoiceFeatures::empty());
assert_eq!(invoice.signing_pubkey(), recipient_pubkey());
- assert!(
- merkle::verify_signature(
- &invoice.signature, SIGNATURE_TAG, &invoice.bytes, recipient_pubkey()
- ).is_ok()
- );
+
+ let message = TaggedHash::new(SIGNATURE_TAG, &invoice.bytes);
+ assert!(merkle::verify_signature(&invoice.signature, message, recipient_pubkey()).is_ok());
let digest = Message::from_slice(&invoice.signable_hash()).unwrap();
let pubkey = recipient_pubkey().into();
assert_eq!(invoice.fallbacks(), vec![]);
assert_eq!(invoice.invoice_features(), &Bolt12InvoiceFeatures::empty());
assert_eq!(invoice.signing_pubkey(), recipient_pubkey());
- assert!(
- merkle::verify_signature(
- &invoice.signature, SIGNATURE_TAG, &invoice.bytes, recipient_pubkey()
- ).is_ok()
- );
+
+ let message = TaggedHash::new(SIGNATURE_TAG, &invoice.bytes);
+ assert!(merkle::verify_signature(&invoice.signature, message, recipient_pubkey()).is_ok());
assert_eq!(
invoice.as_tlv_stream(),
.build().unwrap()
.sign(payer_sign).unwrap();
- if let Err(e) = invoice_request
- .verify_and_respond_using_derived_keys_no_std(
- payment_paths(), payment_hash(), now(), &expanded_key, &secp_ctx
- )
- .unwrap()
+ if let Err(e) = invoice_request.clone()
+ .verify(&expanded_key, &secp_ctx).unwrap()
+ .respond_using_derived_keys_no_std(payment_paths(), payment_hash(), now()).unwrap()
.build_and_sign(&secp_ctx)
{
panic!("error building invoice: {:?}", e);
}
let expanded_key = ExpandedKey::new(&KeyMaterial([41; 32]));
- match invoice_request.verify_and_respond_using_derived_keys_no_std(
- payment_paths(), payment_hash(), now(), &expanded_key, &secp_ctx
- ) {
- Ok(_) => panic!("expected error"),
- Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidMetadata),
- }
+ assert!(invoice_request.verify(&expanded_key, &secp_ctx).is_err());
let desc = "foo".to_string();
let offer = OfferBuilder
::deriving_signing_pubkey(desc, node_id, &expanded_key, &entropy, &secp_ctx)
.amount_msats(1000)
+ // Omit the path so that node_id is used for the signing pubkey instead of deriving
.build().unwrap();
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
.build().unwrap()
.sign(payer_sign).unwrap();
- match invoice_request.verify_and_respond_using_derived_keys_no_std(
- payment_paths(), payment_hash(), now(), &expanded_key, &secp_ctx
- ) {
+ match invoice_request
+ .verify(&expanded_key, &secp_ctx).unwrap()
+ .respond_using_derived_keys_no_std(payment_paths(), payment_hash(), now())
+ {
Ok(_) => panic!("expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidMetadata),
}