} }
macro_rules! invoice_request_verify_method { ($self: ident, $self_type: ty) => {
- /// Verifies that the request was for an offer created using the given key. Returns the verified
- /// request which contains the derived keys needed to sign a [`Bolt12Invoice`] for the request
- /// if they could be extracted from the metadata.
+ /// Verifies that the request was for an offer created using the given key by checking the
+ /// metadata from the offer.
+ ///
+ /// Returns the verified request which contains the derived keys needed to sign a
+ /// [`Bolt12Invoice`] for the request if they could be extracted from the metadata.
///
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
pub fn verify<
})
}
+ /// Verifies that the request was for an offer created using the given key by checking a nonce
+ /// included with the [`BlindedPath`] for which the request was sent through.
+ ///
+ /// Returns the verified request which contains the derived keys needed to sign a
+ /// [`Bolt12Invoice`] for the request if they could be extracted from the metadata.
+ ///
+ /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
+ pub fn verify_using_recipient_data<
+ #[cfg(not(c_bindings))]
+ T: secp256k1::Signing
+ >(
+ $self: $self_type, nonce: Nonce, key: &ExpandedKey,
+ #[cfg(not(c_bindings))]
+ secp_ctx: &Secp256k1<T>,
+ #[cfg(c_bindings)]
+ secp_ctx: &Secp256k1<secp256k1::All>,
+ ) -> Result<VerifiedInvoiceRequest, ()> {
+ let (offer_id, keys) = $self.contents.inner.offer.verify_using_recipient_data(
+ &$self.bytes, nonce, key, secp_ctx
+ )?;
+ Ok(VerifiedInvoiceRequest {
+ offer_id,
+ #[cfg(not(c_bindings))]
+ inner: $self,
+ #[cfg(c_bindings)]
+ inner: $self.clone(),
+ keys,
+ })
+ }
} }
#[cfg(not(c_bindings))]
self.signing_pubkey
}
- /// Verifies that the offer metadata was produced from the offer in the TLV stream.
pub(super) fn verify<T: secp256k1::Signing>(
&self, bytes: &[u8], key: &ExpandedKey, secp_ctx: &Secp256k1<T>
) -> Result<(OfferId, Option<Keypair>), ()> {
- match self.metadata() {
+ self.verify_using_metadata(bytes, self.metadata.as_ref(), key, 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_using_metadata(bytes, Some(&Metadata::RecipientData(nonce)), key, secp_ctx)
+ }
+
+ /// Verifies that the offer metadata was produced from the offer in the TLV stream.
+ fn verify_using_metadata<T: secp256k1::Signing>(
+ &self, bytes: &[u8], metadata: Option<&Metadata>, key: &ExpandedKey, secp_ctx: &Secp256k1<T>
+ ) -> Result<(OfferId, Option<Keypair>), ()> {
+ match metadata {
Some(metadata) => {
let tlv_stream = TlvStream::new(bytes).range(OFFER_TYPES).filter(|record| {
match record.r#type {
OFFER_METADATA_TYPE => false,
- OFFER_NODE_ID_TYPE => {
- !self.metadata.as_ref().unwrap().derives_recipient_keys()
- },
+ OFFER_NODE_ID_TYPE => !metadata.derives_recipient_keys(),
_ => true,
}
});
None => return Err(()),
};
let keys = signer::verify_recipient_metadata(
- metadata, 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);
Err(_) => panic!("unexpected error"),
}
+ // Fails verification when using the wrong method
+ let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+ .build().unwrap()
+ .sign(payer_sign).unwrap();
+ assert!(
+ invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).is_err()
+ );
+
// Fails verification with altered offer field
let mut tlv_stream = offer.as_tlv_stream();
tlv_stream.amount = Some(100);
Err(_) => panic!("unexpected error"),
}
+ let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+ .build().unwrap()
+ .sign(payer_sign).unwrap();
+ match invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx) {
+ Ok(invoice_request) => assert_eq!(invoice_request.offer_id, offer.id()),
+ Err(_) => panic!("unexpected error"),
+ }
+
// Fails verification with altered offer field
let mut tlv_stream = offer.as_tlv_stream();
tlv_stream.amount = Some(100);
/// Metadata as parsed, supplied by the user, or derived from the message contents.
Bytes(Vec<u8>),
+ /// Metadata for deriving keys included as recipient data in a blinded path.
+ RecipientData(Nonce),
+
/// Metadata to be derived from message contents and given material.
Derived(MetadataMaterial),
pub fn as_bytes(&self) -> Option<&Vec<u8>> {
match self {
Metadata::Bytes(bytes) => Some(bytes),
+ Metadata::RecipientData(_) => None,
Metadata::Derived(_) => None,
Metadata::DerivedSigningPubkey(_) => None,
}
pub fn has_derivation_material(&self) -> bool {
match self {
Metadata::Bytes(_) => false,
+ Metadata::RecipientData(_) => false,
Metadata::Derived(_) => true,
Metadata::DerivedSigningPubkey(_) => true,
}
// derived, as wouldn't be the case if a Metadata::Bytes with length PaymentId::LENGTH +
// Nonce::LENGTH had been set explicitly.
Metadata::Bytes(bytes) => bytes.len() == PaymentId::LENGTH + Nonce::LENGTH,
+ Metadata::RecipientData(_) => false,
Metadata::Derived(_) => false,
Metadata::DerivedSigningPubkey(_) => true,
}
// derived, as wouldn't be the case if a Metadata::Bytes with length Nonce::LENGTH had
// been set explicitly.
Metadata::Bytes(bytes) => bytes.len() == Nonce::LENGTH,
+ Metadata::RecipientData(_) => true,
Metadata::Derived(_) => false,
Metadata::DerivedSigningPubkey(_) => true,
}
pub fn without_keys(self) -> Self {
match self {
Metadata::Bytes(_) => self,
+ Metadata::RecipientData(_) => self,
Metadata::Derived(_) => self,
Metadata::DerivedSigningPubkey(material) => Metadata::Derived(material),
}
) -> (Self, Option<Keypair>) {
match self {
Metadata::Bytes(_) => (self, None),
+ Metadata::RecipientData(_) => (self, None),
Metadata::Derived(mut metadata_material) => {
tlv_stream.write(&mut metadata_material.hmac).unwrap();
(Metadata::Bytes(metadata_material.derive_metadata()), None)
}
}
+impl AsRef<[u8]> for Metadata {
+ fn as_ref(&self) -> &[u8] {
+ match self {
+ Metadata::Bytes(bytes) => &bytes,
+ Metadata::RecipientData(nonce) => &nonce.0,
+ Metadata::Derived(_) => &[],
+ Metadata::DerivedSigningPubkey(_) => &[],
+ }
+ }
+}
+
impl fmt::Debug for Metadata {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Metadata::Bytes(bytes) => bytes.fmt(f),
+ Metadata::RecipientData(Nonce(bytes)) => bytes.fmt(f),
Metadata::Derived(_) => f.write_str("Derived"),
Metadata::DerivedSigningPubkey(_) => f.write_str("DerivedSigningPubkey"),
}
} else {
false
},
+ Metadata::RecipientData(_) => false,
Metadata::Derived(_) => false,
Metadata::DerivedSigningPubkey(_) => false,
}