use crate::ln::types::PaymentHash;
use crate::ln::channelmanager::PaymentId;
use crate::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures};
-use crate::ln::inbound_payment::ExpandedKey;
+use crate::ln::inbound_payment::{ExpandedKey, IV_LEN};
use crate::ln::msgs::DecodeError;
use crate::offers::invoice_macros::{invoice_accessors_common, invoice_builder_methods_common};
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::offer::{Amount, OFFER_TYPES, OfferTlvStream, OfferTlvStreamRef, Quantity};
use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
use crate::offers::payer::{PAYER_METADATA_TYPE, PayerTlvStream, PayerTlvStreamRef};
-use crate::offers::refund::{IV_BYTES as REFUND_IV_BYTES, Refund, RefundContents};
+use crate::offers::refund::{IV_BYTES_WITH_METADATA as REFUND_IV_BYTES_WITH_METADATA, IV_BYTES_WITHOUT_METADATA as REFUND_IV_BYTES_WITHOUT_METADATA, Refund, RefundContents};
use crate::offers::signer::{Metadata, self};
use crate::util::ser::{HighZeroBytesDroppedBigSize, Iterable, Readable, SeekReadable, WithoutLength, Writeable, Writer};
use crate::util::string::PrintableString;
pub fn verify_using_metadata<T: secp256k1::Signing>(
&self, key: &ExpandedKey, secp_ctx: &Secp256k1<T>
) -> Result<PaymentId, ()> {
- let metadata = match &self.contents {
- InvoiceContents::ForOffer { invoice_request, .. } => &invoice_request.inner.payer.0,
- InvoiceContents::ForRefund { refund, .. } => &refund.payer.0,
+ let (metadata, iv_bytes) = match &self.contents {
+ InvoiceContents::ForOffer { invoice_request, .. } => {
+ (&invoice_request.inner.payer.0, INVOICE_REQUEST_IV_BYTES)
+ },
+ InvoiceContents::ForRefund { refund, .. } => {
+ (&refund.payer.0, REFUND_IV_BYTES_WITH_METADATA)
+ },
};
- self.contents.verify(TlvStream::new(&self.bytes), metadata, key, secp_ctx)
+ self.contents.verify(TlvStream::new(&self.bytes), metadata, key, iv_bytes, secp_ctx)
}
/// Verifies that the invoice was for a request or refund created using the given key by
&self, payment_id: PaymentId, nonce: Nonce, key: &ExpandedKey, secp_ctx: &Secp256k1<T>
) -> Result<PaymentId, ()> {
let metadata = Metadata::payer_data(payment_id, nonce, key);
- self.contents.verify(TlvStream::new(&self.bytes), &metadata, key, secp_ctx)
+ let iv_bytes = match &self.contents {
+ InvoiceContents::ForOffer { .. } => INVOICE_REQUEST_IV_BYTES,
+ InvoiceContents::ForRefund { .. } => REFUND_IV_BYTES_WITHOUT_METADATA,
+ };
+ self.contents.verify(TlvStream::new(&self.bytes), &metadata, key, iv_bytes, secp_ctx)
.and_then(|extracted_payment_id| (payment_id == extracted_payment_id)
.then(|| payment_id)
.ok_or(())
fn verify<T: secp256k1::Signing>(
&self, tlv_stream: TlvStream<'_>, metadata: &Metadata, key: &ExpandedKey,
- secp_ctx: &Secp256k1<T>
+ iv_bytes: &[u8; IV_LEN], secp_ctx: &Secp256k1<T>
) -> Result<PaymentId, ()> {
let offer_records = tlv_stream.clone().range(OFFER_TYPES);
let invreq_records = tlv_stream.range(INVOICE_REQUEST_TYPES).filter(|record| {
let tlv_stream = offer_records.chain(invreq_records);
let payer_id = self.payer_id();
- let iv_bytes = match self {
- InvoiceContents::ForOffer { .. } => INVOICE_REQUEST_IV_BYTES,
- InvoiceContents::ForRefund { .. } => REFUND_IV_BYTES,
- };
-
signer::verify_payer_metadata(
metadata.as_ref(), key, iv_bytes, payer_id, tlv_stream, secp_ctx,
)
#[cfg(feature = "std")]
use std::time::SystemTime;
-pub(super) const IV_BYTES: &[u8; IV_LEN] = b"LDK Offer ~~~~~~";
+pub(super) const IV_BYTES_WITH_METADATA: &[u8; IV_LEN] = b"LDK Offer ~~~~~~";
+pub(super) const IV_BYTES_WITHOUT_METADATA: &[u8; IV_LEN] = b"LDK Offer v2~~~~";
/// An identifier for an [`Offer`] built using [`DerivedMetadata`].
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
// Don't derive keys if no blinded paths were given since this means the signing
// pubkey must be the node id of an announced node.
- if $self.offer.paths.is_none() {
+ let iv_bytes = if $self.offer.paths.is_none() {
metadata = metadata.without_keys();
- }
+ IV_BYTES_WITH_METADATA
+ } else {
+ IV_BYTES_WITHOUT_METADATA
+ };
let mut tlv_stream = $self.offer.as_tlv_stream();
debug_assert_eq!(tlv_stream.metadata, None);
// for verification. In the former case, the blinded paths must include
// `OffersContext::InvoiceRequest` instead.
let (derived_metadata, keys) =
- metadata.derive_from(IV_BYTES, tlv_stream, $self.secp_ctx);
+ metadata.derive_from(iv_bytes, tlv_stream, $self.secp_ctx);
match keys {
Some(keys) => $self.offer.signing_pubkey = Some(keys.public_key()),
None => $self.offer.metadata = Some(derived_metadata),
pub(super) fn verify_using_metadata<T: secp256k1::Signing>(
&self, bytes: &[u8], key: &ExpandedKey, secp_ctx: &Secp256k1<T>
) -> Result<(OfferId, Option<Keypair>), ()> {
- self.verify(bytes, self.metadata.as_ref(), key, secp_ctx)
+ self.verify(bytes, self.metadata.as_ref(), key, IV_BYTES_WITH_METADATA, secp_ctx)
}
pub(super) fn verify_using_recipient_data<T: secp256k1::Signing>(
&self, bytes: &[u8], nonce: Nonce, key: &ExpandedKey, secp_ctx: &Secp256k1<T>
) -> Result<(OfferId, Option<Keypair>), ()> {
- self.verify(bytes, Some(&Metadata::RecipientData(nonce)), key, secp_ctx)
+ let metadata = Metadata::RecipientData(nonce);
+ self.verify(bytes, Some(&metadata), key, IV_BYTES_WITHOUT_METADATA, secp_ctx)
}
/// Verifies that the offer metadata was produced from the offer in the TLV stream.
fn verify<T: secp256k1::Signing>(
- &self, bytes: &[u8], metadata: Option<&Metadata>, key: &ExpandedKey, secp_ctx: &Secp256k1<T>
+ &self, bytes: &[u8], metadata: Option<&Metadata>, key: &ExpandedKey,
+ iv_bytes: &[u8; IV_LEN], secp_ctx: &Secp256k1<T>
) -> Result<(OfferId, Option<Keypair>), ()> {
match metadata {
Some(metadata) => {
None => return Err(()),
};
let keys = signer::verify_recipient_metadata(
- metadata.as_ref(), key, IV_BYTES, signing_pubkey, tlv_stream, secp_ctx
+ metadata.as_ref(), key, iv_bytes, signing_pubkey, tlv_stream, secp_ctx
)?;
let offer_id = OfferId::from_valid_invreq_tlv_stream(bytes);
#[cfg(feature = "std")]
use std::time::SystemTime;
-pub(super) const IV_BYTES: &[u8; IV_LEN] = b"LDK Refund ~~~~~";
+pub(super) const IV_BYTES_WITH_METADATA: &[u8; IV_LEN] = b"LDK Refund ~~~~~";
+pub(super) const IV_BYTES_WITHOUT_METADATA: &[u8; IV_LEN] = b"LDK Refund v2~~~";
/// Builds a [`Refund`] for the "offer for money" flow.
///
if $self.refund.payer.0.has_derivation_material() {
let mut metadata = core::mem::take(&mut $self.refund.payer.0);
- if $self.refund.paths.is_none() {
+ let iv_bytes = if $self.refund.paths.is_none() {
metadata = metadata.without_keys();
- }
+ IV_BYTES_WITH_METADATA
+ } else {
+ IV_BYTES_WITHOUT_METADATA
+ };
let mut tlv_stream = $self.refund.as_tlv_stream();
tlv_stream.0.metadata = None;
}
let (derived_metadata, keys) =
- metadata.derive_from(IV_BYTES, tlv_stream, $self.secp_ctx);
+ metadata.derive_from(iv_bytes, tlv_stream, $self.secp_ctx);
metadata = derived_metadata;
if let Some(keys) = keys {
$self.refund.payer_id = keys.public_key();