1use crate::blinded_path::message::BlindedMessagePath;
13use crate::blinded_path::payment::BlindedPaymentPath;
14use crate::io;
15use crate::ln::inbound_payment::ExpandedKey;
16use crate::ln::msgs::DecodeError;
17use crate::offers::invoice::{
18 check_invoice_signing_pubkey, construct_payment_paths, filter_fallbacks,
19 ExperimentalInvoiceTlvStream, ExperimentalInvoiceTlvStreamRef, FallbackAddress,
20 InvoiceTlvStream, InvoiceTlvStreamRef,
21};
22#[cfg(test)]
23use crate::offers::invoice_macros::invoice_builder_methods_test_common;
24use crate::offers::invoice_macros::{invoice_accessors_common, invoice_builder_methods_common};
25use crate::offers::invoice_request::InvoiceRequest;
26use crate::offers::merkle::{
27 self, SignError, SignFn, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, TlvStream,
28};
29use crate::offers::nonce::Nonce;
30use crate::offers::offer::{
31 Amount, ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, Offer, OfferContents,
32 OfferId, OfferTlvStream, OfferTlvStreamRef, Quantity, EXPERIMENTAL_OFFER_TYPES, OFFER_TYPES,
33};
34use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
35use crate::types::features::{Bolt12InvoiceFeatures, OfferFeatures};
36use crate::types::string::PrintableString;
37use crate::util::ser::{
38 CursorReadable, Iterable, LengthLimitedRead, LengthReadable, WithoutLength, Writeable, Writer,
39};
40use bitcoin::address::Address;
41use bitcoin::constants::ChainHash;
42use bitcoin::secp256k1::schnorr::Signature;
43use bitcoin::secp256k1::{self, Keypair, PublicKey, Secp256k1};
44use core::time::Duration;
45
46#[cfg(feature = "std")]
47use crate::offers::invoice::is_expired;
48
49#[allow(unused_imports)]
50use crate::prelude::*;
51
52pub const DEFAULT_RELATIVE_EXPIRY: Duration = Duration::from_secs(3600 * 24 * 14);
54
55pub const SIGNATURE_TAG: &'static str = concat!("lightning", "static_invoice", "signature");
57
58#[derive(Clone, Debug)]
69pub struct StaticInvoice {
70 bytes: Vec<u8>,
71 contents: InvoiceContents,
72 signature: Signature,
73 offer_id: OfferId,
74}
75
76impl PartialEq for StaticInvoice {
77 fn eq(&self, other: &Self) -> bool {
78 self.bytes.eq(&other.bytes)
79 }
80}
81
82impl Eq for StaticInvoice {}
83
84impl core::hash::Hash for StaticInvoice {
85 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
86 self.bytes.hash(state);
87 }
88}
89
90#[derive(Clone, Debug)]
94struct InvoiceContents {
95 offer: OfferContents,
96 payment_paths: Vec<BlindedPaymentPath>,
97 created_at: Duration,
98 relative_expiry: Option<Duration>,
99 fallbacks: Option<Vec<FallbackAddress>>,
100 features: Bolt12InvoiceFeatures,
101 signing_pubkey: PublicKey,
102 message_paths: Vec<BlindedMessagePath>,
103 #[cfg(test)]
104 experimental_baz: Option<u64>,
105}
106
107pub struct StaticInvoiceBuilder<'a> {
113 offer_bytes: &'a Vec<u8>,
114 invoice: InvoiceContents,
115 keys: Keypair,
116}
117
118impl<'a> StaticInvoiceBuilder<'a> {
119 pub fn for_offer_using_derived_keys<T: secp256k1::Signing>(
124 offer: &'a Offer, payment_paths: Vec<BlindedPaymentPath>,
125 message_paths: Vec<BlindedMessagePath>, created_at: Duration, expanded_key: &ExpandedKey,
126 nonce: Nonce, secp_ctx: &Secp256k1<T>,
127 ) -> Result<Self, Bolt12SemanticError> {
128 if offer.chains().len() > 1 {
129 return Err(Bolt12SemanticError::UnexpectedChain);
130 }
131
132 if payment_paths.is_empty() || message_paths.is_empty() || offer.paths().is_empty() {
133 return Err(Bolt12SemanticError::MissingPaths);
134 }
135
136 let issuer_signing_pubkey =
137 offer.issuer_signing_pubkey().ok_or(Bolt12SemanticError::MissingIssuerSigningPubkey)?;
138
139 let keys = offer
140 .verify(nonce, &expanded_key, &secp_ctx)
141 .map_err(|()| Bolt12SemanticError::InvalidMetadata)?
142 .1
143 .ok_or(Bolt12SemanticError::MissingSigningPubkey)?;
144
145 let signing_pubkey = keys.public_key();
146 if signing_pubkey != issuer_signing_pubkey {
147 return Err(Bolt12SemanticError::InvalidSigningPubkey);
148 }
149
150 let invoice =
151 InvoiceContents::new(offer, payment_paths, message_paths, created_at, signing_pubkey);
152
153 Ok(Self { offer_bytes: &offer.bytes, invoice, keys })
154 }
155
156 pub fn build(self) -> Result<(UnsignedStaticInvoice, Keypair), Bolt12SemanticError> {
159 #[cfg(feature = "std")]
160 {
161 if self.invoice.is_offer_expired() {
162 return Err(Bolt12SemanticError::AlreadyExpired);
163 }
164 }
165
166 #[cfg(not(feature = "std"))]
167 {
168 if self.invoice.is_offer_expired_no_std(self.invoice.created_at()) {
169 return Err(Bolt12SemanticError::AlreadyExpired);
170 }
171 }
172
173 let Self { offer_bytes, invoice, keys } = self;
174 Ok((UnsignedStaticInvoice::new(&offer_bytes, invoice), keys))
175 }
176
177 pub fn build_and_sign<T: secp256k1::Signing>(
179 self, secp_ctx: &Secp256k1<T>,
180 ) -> Result<StaticInvoice, Bolt12SemanticError> {
181 let (unsigned_invoice, keys) = self.build()?;
182 let invoice = unsigned_invoice
183 .sign(|message: &UnsignedStaticInvoice| {
184 Ok(secp_ctx.sign_schnorr_no_aux_rand(message.tagged_hash.as_digest(), &keys))
185 })
186 .unwrap();
187 Ok(invoice)
188 }
189
190 invoice_builder_methods_common!(self, Self, self.invoice, Self, self, StaticInvoice, mut);
191
192 #[cfg(test)]
193 invoice_builder_methods_test_common!(self, Self, self.invoice, Self, self, mut);
194}
195
196pub struct UnsignedStaticInvoice {
198 bytes: Vec<u8>,
199 experimental_bytes: Vec<u8>,
200 contents: InvoiceContents,
201 tagged_hash: TaggedHash,
202}
203
204macro_rules! invoice_accessors { ($self: ident, $contents: expr) => {
205 pub fn chain(&$self) -> ChainHash {
208 $contents.chain()
209 }
210
211 pub fn metadata(&$self) -> Option<&Vec<u8>> {
215 $contents.metadata()
216 }
217
218 pub fn amount(&$self) -> Option<Amount> {
224 $contents.amount()
225 }
226
227 pub fn offer_features(&$self) -> &OfferFeatures {
232 $contents.offer_features()
233 }
234
235 pub fn description(&$self) -> Option<PrintableString<'_>> {
239 $contents.description()
240 }
241
242 pub fn absolute_expiry(&$self) -> Option<Duration> {
247 $contents.absolute_expiry()
248 }
249
250 pub fn issuer(&$self) -> Option<PrintableString<'_>> {
254 $contents.issuer()
255 }
256
257 pub fn offer_message_paths(&$self) -> &[BlindedMessagePath] {
262 $contents.offer_message_paths()
263 }
264
265 pub fn message_paths(&$self) -> &[BlindedMessagePath] {
268 $contents.message_paths()
269 }
270
271 pub fn supported_quantity(&$self) -> Quantity {
275 $contents.supported_quantity()
276 }
277
278 pub fn issuer_signing_pubkey(&$self) -> Option<PublicKey> {
283 $contents.issuer_signing_pubkey()
284 }
285} }
286
287macro_rules! invoice_accessors_signing_pubkey {
288 ($self: ident, $contents: expr, $invoice_type: ty) =>
289{
290 pub fn signing_pubkey(&$self) -> PublicKey {
299 $contents.signing_pubkey()
300 }
301} }
302
303impl UnsignedStaticInvoice {
304 fn new(offer_bytes: &Vec<u8>, contents: InvoiceContents) -> Self {
305 let (_, invoice_tlv_stream, _, experimental_invoice_tlv_stream) = contents.as_tlv_stream();
306
307 const INVOICE_ALLOCATION_SIZE: usize = 1024;
308 let mut bytes = Vec::with_capacity(INVOICE_ALLOCATION_SIZE);
309
310 for record in TlvStream::new(offer_bytes).range(OFFER_TYPES) {
313 record.write(&mut bytes).unwrap();
314 }
315
316 let remaining_bytes = &offer_bytes[bytes.len()..];
317
318 invoice_tlv_stream.write(&mut bytes).unwrap();
319
320 const EXPERIMENTAL_TLV_ALLOCATION_SIZE: usize = 0;
321 let mut experimental_bytes = Vec::with_capacity(EXPERIMENTAL_TLV_ALLOCATION_SIZE);
322
323 let experimental_tlv_stream =
324 TlvStream::new(remaining_bytes).range(EXPERIMENTAL_OFFER_TYPES);
325 for record in experimental_tlv_stream {
326 record.write(&mut experimental_bytes).unwrap();
327 }
328
329 experimental_invoice_tlv_stream.write(&mut experimental_bytes).unwrap();
330
331 let tlv_stream = TlvStream::new(&bytes).chain(TlvStream::new(&experimental_bytes));
332 let tagged_hash = TaggedHash::from_tlv_stream(SIGNATURE_TAG, tlv_stream);
333
334 Self { bytes, experimental_bytes, contents, tagged_hash }
335 }
336
337 pub fn sign<F: SignStaticInvoiceFn>(mut self, sign: F) -> Result<StaticInvoice, SignError> {
341 let pubkey = self.contents.signing_pubkey;
342 let signature = merkle::sign_message(sign, &self, pubkey)?;
343
344 let signature_tlv_stream = SignatureTlvStreamRef { signature: Some(&signature) };
346 signature_tlv_stream.write(&mut self.bytes).unwrap();
347
348 self.bytes.extend_from_slice(&self.experimental_bytes);
350
351 let offer_id = OfferId::from_valid_bolt12_tlv_stream(&self.bytes);
352 Ok(StaticInvoice { bytes: self.bytes, contents: self.contents, signature, offer_id })
353 }
354
355 invoice_accessors_common!(self, self.contents, UnsignedStaticInvoice);
356 invoice_accessors_signing_pubkey!(self, self.contents, UnsignedStaticInvoice);
357 invoice_accessors!(self, self.contents);
358}
359
360impl AsRef<TaggedHash> for UnsignedStaticInvoice {
361 fn as_ref(&self) -> &TaggedHash {
362 &self.tagged_hash
363 }
364}
365
366pub trait SignStaticInvoiceFn {
368 fn sign_invoice(&self, message: &UnsignedStaticInvoice) -> Result<Signature, ()>;
370}
371
372impl<F> SignStaticInvoiceFn for F
373where
374 F: Fn(&UnsignedStaticInvoice) -> Result<Signature, ()>,
375{
376 fn sign_invoice(&self, message: &UnsignedStaticInvoice) -> Result<Signature, ()> {
377 self(message)
378 }
379}
380
381impl<F> SignFn<UnsignedStaticInvoice> for F
382where
383 F: SignStaticInvoiceFn,
384{
385 fn sign(&self, message: &UnsignedStaticInvoice) -> Result<Signature, ()> {
386 self.sign_invoice(message)
387 }
388}
389
390impl StaticInvoice {
391 invoice_accessors_common!(self, self.contents, StaticInvoice);
392 invoice_accessors_signing_pubkey!(self, self.contents, StaticInvoice);
393 invoice_accessors!(self, self.contents);
394
395 pub fn signature(&self) -> Signature {
397 self.signature
398 }
399
400 #[cfg(feature = "std")]
402 pub fn is_offer_expired(&self) -> bool {
403 self.contents.is_expired()
404 }
405
406 pub fn is_offer_expired_no_std(&self, duration_since_epoch: Duration) -> bool {
409 self.contents.is_offer_expired_no_std(duration_since_epoch)
410 }
411
412 pub fn offer_id(&self) -> OfferId {
416 self.offer_id
417 }
418
419 #[allow(unused)] pub(crate) fn is_from_same_offer(&self, invreq: &InvoiceRequest) -> bool {
421 let invoice_offer_tlv_stream =
422 Offer::tlv_stream_iter(&self.bytes).map(|tlv_record| tlv_record.record_bytes);
423 let invreq_offer_tlv_stream =
424 Offer::tlv_stream_iter(invreq.bytes()).map(|tlv_record| tlv_record.record_bytes);
425 invoice_offer_tlv_stream.eq(invreq_offer_tlv_stream)
426 }
427}
428
429impl InvoiceContents {
430 #[cfg(feature = "std")]
431 fn is_offer_expired(&self) -> bool {
432 self.offer.is_expired()
433 }
434
435 fn is_offer_expired_no_std(&self, duration_since_epoch: Duration) -> bool {
436 self.offer.is_expired_no_std(duration_since_epoch)
437 }
438
439 fn new(
440 offer: &Offer, payment_paths: Vec<BlindedPaymentPath>,
441 message_paths: Vec<BlindedMessagePath>, created_at: Duration, signing_pubkey: PublicKey,
442 ) -> Self {
443 Self {
444 offer: offer.contents.clone(),
445 payment_paths,
446 message_paths,
447 created_at,
448 relative_expiry: None,
449 fallbacks: None,
450 features: Bolt12InvoiceFeatures::empty(),
451 signing_pubkey,
452 #[cfg(test)]
453 experimental_baz: None,
454 }
455 }
456
457 fn as_tlv_stream(&self) -> PartialInvoiceTlvStreamRef<'_> {
458 let features = {
459 if self.features == Bolt12InvoiceFeatures::empty() {
460 None
461 } else {
462 Some(&self.features)
463 }
464 };
465
466 let invoice = InvoiceTlvStreamRef {
467 paths: Some(Iterable(self.payment_paths.iter().map(|path| path.inner_blinded_path()))),
468 message_paths: Some(self.message_paths.as_ref()),
469 blindedpay: Some(Iterable(self.payment_paths.iter().map(|path| &path.payinfo))),
470 created_at: Some(self.created_at.as_secs()),
471 relative_expiry: self.relative_expiry.map(|duration| duration.as_secs() as u32),
472 fallbacks: self.fallbacks.as_ref(),
473 features,
474 node_id: Some(&self.signing_pubkey),
475 amount: None,
476 payment_hash: None,
477 };
478
479 let experimental_invoice = ExperimentalInvoiceTlvStreamRef {
480 #[cfg(test)]
481 experimental_baz: self.experimental_baz,
482 };
483
484 let (offer, experimental_offer) = self.offer.as_tlv_stream();
485
486 (offer, invoice, experimental_offer, experimental_invoice)
487 }
488
489 fn chain(&self) -> ChainHash {
490 debug_assert_eq!(self.offer.chains().len(), 1);
491 self.offer.chains().first().cloned().unwrap_or_else(|| self.offer.implied_chain())
492 }
493
494 fn metadata(&self) -> Option<&Vec<u8>> {
495 self.offer.metadata()
496 }
497
498 fn amount(&self) -> Option<Amount> {
499 self.offer.amount()
500 }
501
502 fn offer_features(&self) -> &OfferFeatures {
503 self.offer.features()
504 }
505
506 fn description(&self) -> Option<PrintableString<'_>> {
507 self.offer.description()
508 }
509
510 fn absolute_expiry(&self) -> Option<Duration> {
511 self.offer.absolute_expiry()
512 }
513
514 fn issuer(&self) -> Option<PrintableString<'_>> {
515 self.offer.issuer()
516 }
517
518 fn offer_message_paths(&self) -> &[BlindedMessagePath] {
519 self.offer.paths()
520 }
521
522 fn message_paths(&self) -> &[BlindedMessagePath] {
523 &self.message_paths[..]
524 }
525
526 fn supported_quantity(&self) -> Quantity {
527 self.offer.supported_quantity()
528 }
529
530 fn issuer_signing_pubkey(&self) -> Option<PublicKey> {
531 self.offer.issuer_signing_pubkey()
532 }
533
534 fn payment_paths(&self) -> &[BlindedPaymentPath] {
535 &self.payment_paths[..]
536 }
537
538 fn created_at(&self) -> Duration {
539 self.created_at
540 }
541
542 fn relative_expiry(&self) -> Duration {
543 self.relative_expiry.unwrap_or(DEFAULT_RELATIVE_EXPIRY)
544 }
545
546 #[cfg(feature = "std")]
547 fn is_expired(&self) -> bool {
548 is_expired(self.created_at(), self.relative_expiry())
549 }
550
551 fn is_expired_no_std(&self, duration_since_epoch: Duration) -> bool {
552 self.created_at().saturating_add(self.relative_expiry()) < duration_since_epoch
553 }
554
555 fn fallbacks(&self) -> Vec<Address> {
556 let chain = self.chain();
557 self.fallbacks
558 .as_ref()
559 .map(|fallbacks| filter_fallbacks(chain, fallbacks))
560 .unwrap_or_else(Vec::new)
561 }
562
563 fn features(&self) -> &Bolt12InvoiceFeatures {
564 &self.features
565 }
566
567 fn signing_pubkey(&self) -> PublicKey {
568 self.signing_pubkey
569 }
570}
571
572impl Writeable for StaticInvoice {
573 fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
574 WithoutLength(&self.bytes).write(writer)
575 }
576}
577impl LengthReadable for StaticInvoice {
578 fn read_from_fixed_length_buffer<R: LengthLimitedRead>(r: &mut R) -> Result<Self, DecodeError> {
579 let bytes: WithoutLength<Vec<u8>> = LengthReadable::read_from_fixed_length_buffer(r)?;
580 Self::try_from(bytes.0).map_err(|_| DecodeError::InvalidValue)
581 }
582}
583
584impl TryFrom<Vec<u8>> for StaticInvoice {
585 type Error = Bolt12ParseError;
586
587 fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
588 let parsed_invoice = ParsedMessage::<FullInvoiceTlvStream>::try_from(bytes)?;
589 StaticInvoice::try_from(parsed_invoice)
590 }
591}
592
593type FullInvoiceTlvStream = (
594 OfferTlvStream,
595 InvoiceTlvStream,
596 SignatureTlvStream,
597 ExperimentalOfferTlvStream,
598 ExperimentalInvoiceTlvStream,
599);
600
601impl CursorReadable for FullInvoiceTlvStream {
602 fn read<R: AsRef<[u8]>>(r: &mut io::Cursor<R>) -> Result<Self, DecodeError> {
603 let offer = CursorReadable::read(r)?;
604 let invoice = CursorReadable::read(r)?;
605 let signature = CursorReadable::read(r)?;
606 let experimental_offer = CursorReadable::read(r)?;
607 let experimental_invoice = CursorReadable::read(r)?;
608
609 Ok((offer, invoice, signature, experimental_offer, experimental_invoice))
610 }
611}
612
613type PartialInvoiceTlvStream =
614 (OfferTlvStream, InvoiceTlvStream, ExperimentalOfferTlvStream, ExperimentalInvoiceTlvStream);
615
616type PartialInvoiceTlvStreamRef<'a> = (
617 OfferTlvStreamRef<'a>,
618 InvoiceTlvStreamRef<'a>,
619 ExperimentalOfferTlvStreamRef,
620 ExperimentalInvoiceTlvStreamRef,
621);
622
623impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for StaticInvoice {
624 type Error = Bolt12ParseError;
625
626 fn try_from(invoice: ParsedMessage<FullInvoiceTlvStream>) -> Result<Self, Self::Error> {
627 let ParsedMessage { bytes, tlv_stream } = invoice;
628 let (
629 offer_tlv_stream,
630 invoice_tlv_stream,
631 SignatureTlvStream { signature },
632 experimental_offer_tlv_stream,
633 experimental_invoice_tlv_stream,
634 ) = tlv_stream;
635 let contents = InvoiceContents::try_from((
636 offer_tlv_stream,
637 invoice_tlv_stream,
638 experimental_offer_tlv_stream,
639 experimental_invoice_tlv_stream,
640 ))?;
641
642 let signature = match signature {
643 None => {
644 return Err(Bolt12ParseError::InvalidSemantics(
645 Bolt12SemanticError::MissingSignature,
646 ))
647 },
648 Some(signature) => signature,
649 };
650 let tagged_hash = TaggedHash::from_valid_tlv_stream_bytes(SIGNATURE_TAG, &bytes);
651 let pubkey = contents.signing_pubkey;
652 merkle::verify_signature(&signature, &tagged_hash, pubkey)?;
653
654 let offer_id = OfferId::from_valid_bolt12_tlv_stream(&bytes);
655 Ok(StaticInvoice { bytes, contents, signature, offer_id })
656 }
657}
658
659impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
660 type Error = Bolt12SemanticError;
661
662 fn try_from(tlv_stream: PartialInvoiceTlvStream) -> Result<Self, Self::Error> {
663 let (
664 offer_tlv_stream,
665 InvoiceTlvStream {
666 paths,
667 blindedpay,
668 created_at,
669 relative_expiry,
670 fallbacks,
671 features,
672 node_id,
673 message_paths,
674 payment_hash,
675 amount,
676 },
677 experimental_offer_tlv_stream,
678 ExperimentalInvoiceTlvStream {
679 #[cfg(test)]
680 experimental_baz,
681 },
682 ) = tlv_stream;
683
684 if payment_hash.is_some() {
685 return Err(Bolt12SemanticError::UnexpectedPaymentHash);
686 }
687 if amount.is_some() {
688 return Err(Bolt12SemanticError::UnexpectedAmount);
689 }
690
691 let payment_paths = construct_payment_paths(blindedpay, paths)?;
692 let message_paths = message_paths.ok_or(Bolt12SemanticError::MissingPaths)?;
693
694 let created_at = match created_at {
695 None => return Err(Bolt12SemanticError::MissingCreationTime),
696 Some(timestamp) => Duration::from_secs(timestamp),
697 };
698
699 let relative_expiry = relative_expiry.map(Into::<u64>::into).map(Duration::from_secs);
700
701 let features = features.unwrap_or_else(Bolt12InvoiceFeatures::empty);
702
703 let signing_pubkey = node_id.ok_or(Bolt12SemanticError::MissingSigningPubkey)?;
704 check_invoice_signing_pubkey(&signing_pubkey, &offer_tlv_stream)?;
705
706 if offer_tlv_stream.paths.is_none() {
707 return Err(Bolt12SemanticError::MissingPaths);
708 }
709 if offer_tlv_stream.chains.as_ref().map_or(0, |chains| chains.len()) > 1 {
710 return Err(Bolt12SemanticError::UnexpectedChain);
711 }
712
713 Ok(InvoiceContents {
714 offer: OfferContents::try_from((offer_tlv_stream, experimental_offer_tlv_stream))?,
715 payment_paths,
716 message_paths,
717 created_at,
718 relative_expiry,
719 fallbacks,
720 features,
721 signing_pubkey,
722 #[cfg(test)]
723 experimental_baz,
724 })
725 }
726}
727
728#[cfg(test)]
729mod tests {
730 use crate::blinded_path::message::BlindedMessagePath;
731 use crate::blinded_path::BlindedHop;
732 use crate::ln::inbound_payment::ExpandedKey;
733 use crate::ln::msgs::DecodeError;
734 use crate::offers::invoice::{
735 ExperimentalInvoiceTlvStreamRef, InvoiceTlvStreamRef, EXPERIMENTAL_INVOICE_TYPES,
736 INVOICE_TYPES,
737 };
738 use crate::offers::merkle;
739 use crate::offers::merkle::{SignatureTlvStreamRef, TaggedHash, TlvStream};
740 use crate::offers::nonce::Nonce;
741 use crate::offers::offer::{
742 ExperimentalOfferTlvStreamRef, Offer, OfferBuilder, OfferTlvStreamRef, Quantity,
743 };
744 use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError};
745 use crate::offers::static_invoice::{
746 StaticInvoice, StaticInvoiceBuilder, UnsignedStaticInvoice, DEFAULT_RELATIVE_EXPIRY,
747 SIGNATURE_TAG,
748 };
749 use crate::offers::test_utils::*;
750 use crate::types::features::{Bolt12InvoiceFeatures, OfferFeatures};
751 use crate::util::ser::{BigSize, Iterable, Writeable};
752 use bitcoin::constants::ChainHash;
753 use bitcoin::secp256k1::{self, Secp256k1};
754 use bitcoin::Network;
755 use core::time::Duration;
756
757 type FullInvoiceTlvStreamRef<'a> = (
758 OfferTlvStreamRef<'a>,
759 InvoiceTlvStreamRef<'a>,
760 SignatureTlvStreamRef<'a>,
761 ExperimentalOfferTlvStreamRef,
762 ExperimentalInvoiceTlvStreamRef,
763 );
764
765 impl StaticInvoice {
766 fn as_tlv_stream(&self) -> FullInvoiceTlvStreamRef<'_> {
767 let (
768 offer_tlv_stream,
769 invoice_tlv_stream,
770 experimental_offer_tlv_stream,
771 experimental_invoice_tlv_stream,
772 ) = self.contents.as_tlv_stream();
773 (
774 offer_tlv_stream,
775 invoice_tlv_stream,
776 SignatureTlvStreamRef { signature: Some(&self.signature) },
777 experimental_offer_tlv_stream,
778 experimental_invoice_tlv_stream,
779 )
780 }
781 }
782
783 fn tlv_stream_to_bytes(
784 tlv_stream: &(
785 OfferTlvStreamRef,
786 InvoiceTlvStreamRef,
787 SignatureTlvStreamRef,
788 ExperimentalOfferTlvStreamRef,
789 ExperimentalInvoiceTlvStreamRef,
790 ),
791 ) -> Vec<u8> {
792 let mut buffer = Vec::new();
793 tlv_stream.0.write(&mut buffer).unwrap();
794 tlv_stream.1.write(&mut buffer).unwrap();
795 tlv_stream.2.write(&mut buffer).unwrap();
796 tlv_stream.3.write(&mut buffer).unwrap();
797 tlv_stream.4.write(&mut buffer).unwrap();
798 buffer
799 }
800
801 fn invoice() -> StaticInvoice {
802 let node_id = recipient_pubkey();
803 let payment_paths = payment_paths();
804 let now = now();
805 let expanded_key = ExpandedKey::new([42; 32]);
806 let entropy = FixedEntropy {};
807 let nonce = Nonce::from_entropy_source(&entropy);
808 let secp_ctx = Secp256k1::new();
809
810 let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
811 .path(blinded_path())
812 .build()
813 .unwrap();
814
815 StaticInvoiceBuilder::for_offer_using_derived_keys(
816 &offer,
817 payment_paths.clone(),
818 vec![blinded_path()],
819 now,
820 &expanded_key,
821 nonce,
822 &secp_ctx,
823 )
824 .unwrap()
825 .build_and_sign(&secp_ctx)
826 .unwrap()
827 }
828
829 fn blinded_path() -> BlindedMessagePath {
830 BlindedMessagePath::from_blinded_path(
831 pubkey(40),
832 pubkey(41),
833 vec![
834 BlindedHop { blinded_node_id: pubkey(42), encrypted_payload: vec![0; 43] },
835 BlindedHop { blinded_node_id: pubkey(43), encrypted_payload: vec![0; 44] },
836 ],
837 )
838 }
839
840 #[test]
841 fn builds_invoice_for_offer_with_defaults() {
842 let node_id = recipient_pubkey();
843 let payment_paths = payment_paths();
844 let now = now();
845 let expanded_key = ExpandedKey::new([42; 32]);
846 let entropy = FixedEntropy {};
847 let nonce = Nonce::from_entropy_source(&entropy);
848 let secp_ctx = Secp256k1::new();
849
850 let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
851 .path(blinded_path())
852 .build()
853 .unwrap();
854
855 let invoice = StaticInvoiceBuilder::for_offer_using_derived_keys(
856 &offer,
857 payment_paths.clone(),
858 vec![blinded_path()],
859 now,
860 &expanded_key,
861 nonce,
862 &secp_ctx,
863 )
864 .unwrap()
865 .build_and_sign(&secp_ctx)
866 .unwrap();
867
868 let mut buffer = Vec::new();
869 invoice.write(&mut buffer).unwrap();
870
871 assert_eq!(invoice.bytes, buffer.as_slice());
872 assert_eq!(invoice.metadata(), None);
873 assert_eq!(invoice.amount(), None);
874 assert_eq!(invoice.description(), None);
875 assert_eq!(invoice.offer_features(), &OfferFeatures::empty());
876 assert_eq!(invoice.absolute_expiry(), None);
877 assert_eq!(invoice.offer_message_paths(), &[blinded_path()]);
878 assert_eq!(invoice.message_paths(), &[blinded_path()]);
879 assert_eq!(invoice.issuer(), None);
880 assert_eq!(invoice.supported_quantity(), Quantity::One);
881 assert_ne!(invoice.signing_pubkey(), recipient_pubkey());
882 assert_eq!(invoice.chain(), ChainHash::using_genesis_block(Network::Bitcoin));
883 assert_eq!(invoice.payment_paths(), payment_paths.as_slice());
884 assert_eq!(invoice.created_at(), now);
885 assert_eq!(invoice.relative_expiry(), DEFAULT_RELATIVE_EXPIRY);
886 #[cfg(feature = "std")]
887 assert!(!invoice.is_expired());
888 assert!(invoice.fallbacks().is_empty());
889 assert_eq!(invoice.invoice_features(), &Bolt12InvoiceFeatures::empty());
890
891 let signing_pubkey = offer.issuer_signing_pubkey().unwrap();
892 let message = TaggedHash::from_valid_tlv_stream_bytes(SIGNATURE_TAG, &invoice.bytes);
893 assert!(merkle::verify_signature(&invoice.signature, &message, signing_pubkey).is_ok());
894
895 let paths = vec![blinded_path()];
896 assert_eq!(
897 invoice.as_tlv_stream(),
898 (
899 OfferTlvStreamRef {
900 chains: None,
901 metadata: None,
902 currency: None,
903 amount: None,
904 description: None,
905 features: None,
906 absolute_expiry: None,
907 paths: Some(&paths),
908 issuer: None,
909 quantity_max: None,
910 issuer_id: Some(&signing_pubkey),
911 },
912 InvoiceTlvStreamRef {
913 paths: Some(Iterable(
914 payment_paths.iter().map(|path| path.inner_blinded_path())
915 )),
916 blindedpay: Some(Iterable(payment_paths.iter().map(|path| &path.payinfo))),
917 created_at: Some(now.as_secs()),
918 relative_expiry: None,
919 payment_hash: None,
920 amount: None,
921 fallbacks: None,
922 features: None,
923 node_id: Some(&signing_pubkey),
924 message_paths: Some(&paths),
925 },
926 SignatureTlvStreamRef { signature: Some(&invoice.signature()) },
927 ExperimentalOfferTlvStreamRef { experimental_foo: None },
928 ExperimentalInvoiceTlvStreamRef { experimental_baz: None },
929 )
930 );
931
932 if let Err(e) = StaticInvoice::try_from(buffer) {
933 panic!("error parsing invoice: {:?}", e);
934 }
935 }
936
937 #[cfg(feature = "std")]
938 #[test]
939 fn builds_invoice_from_offer_with_expiration() {
940 let node_id = recipient_pubkey();
941 let now = now();
942 let expanded_key = ExpandedKey::new([42; 32]);
943 let entropy = FixedEntropy {};
944 let nonce = Nonce::from_entropy_source(&entropy);
945 let secp_ctx = Secp256k1::new();
946
947 let future_expiry = Duration::from_secs(u64::max_value());
948 let past_expiry = Duration::from_secs(0);
949
950 let valid_offer =
951 OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
952 .path(blinded_path())
953 .absolute_expiry(future_expiry)
954 .build()
955 .unwrap();
956
957 let invoice = StaticInvoiceBuilder::for_offer_using_derived_keys(
958 &valid_offer,
959 payment_paths(),
960 vec![blinded_path()],
961 now,
962 &expanded_key,
963 nonce,
964 &secp_ctx,
965 )
966 .unwrap()
967 .build_and_sign(&secp_ctx)
968 .unwrap();
969 assert!(!invoice.is_expired());
970 assert_eq!(invoice.absolute_expiry(), Some(future_expiry));
971
972 let expired_offer =
973 OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
974 .path(blinded_path())
975 .absolute_expiry(past_expiry)
976 .build()
977 .unwrap();
978 if let Err(e) = StaticInvoiceBuilder::for_offer_using_derived_keys(
979 &expired_offer,
980 payment_paths(),
981 vec![blinded_path()],
982 now,
983 &expanded_key,
984 nonce,
985 &secp_ctx,
986 )
987 .unwrap()
988 .build_and_sign(&secp_ctx)
989 {
990 assert_eq!(e, Bolt12SemanticError::AlreadyExpired);
991 } else {
992 panic!("expected error")
993 }
994 }
995
996 #[test]
997 fn builds_invoice_from_offer_using_derived_key() {
998 let node_id = recipient_pubkey();
999 let now = now();
1000 let expanded_key = ExpandedKey::new([42; 32]);
1001 let entropy = FixedEntropy {};
1002 let nonce = Nonce::from_entropy_source(&entropy);
1003 let secp_ctx = Secp256k1::new();
1004
1005 let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
1006 .path(blinded_path())
1007 .experimental_foo(42)
1008 .build()
1009 .unwrap();
1010
1011 if let Err(e) = StaticInvoiceBuilder::for_offer_using_derived_keys(
1012 &offer,
1013 payment_paths(),
1014 vec![blinded_path()],
1015 now,
1016 &expanded_key,
1017 nonce,
1018 &secp_ctx,
1019 )
1020 .unwrap()
1021 .build_and_sign(&secp_ctx)
1022 {
1023 panic!("error building invoice: {:?}", e);
1024 }
1025
1026 let expanded_key = ExpandedKey::new([41; 32]);
1027 if let Err(e) = StaticInvoiceBuilder::for_offer_using_derived_keys(
1028 &offer,
1029 payment_paths(),
1030 vec![blinded_path()],
1031 now,
1032 &expanded_key,
1033 nonce,
1034 &secp_ctx,
1035 ) {
1036 assert_eq!(e, Bolt12SemanticError::InvalidMetadata);
1037 } else {
1038 panic!("expected error")
1039 }
1040 }
1041
1042 #[test]
1043 fn fails_build_with_missing_paths() {
1044 let node_id = recipient_pubkey();
1045 let now = now();
1046 let expanded_key = ExpandedKey::new([42; 32]);
1047 let entropy = FixedEntropy {};
1048 let nonce = Nonce::from_entropy_source(&entropy);
1049 let secp_ctx = Secp256k1::new();
1050
1051 let valid_offer =
1052 OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
1053 .path(blinded_path())
1054 .build()
1055 .unwrap();
1056
1057 if let Err(e) = StaticInvoiceBuilder::for_offer_using_derived_keys(
1059 &valid_offer,
1060 Vec::new(),
1061 vec![blinded_path()],
1062 now,
1063 &expanded_key,
1064 nonce,
1065 &secp_ctx,
1066 ) {
1067 assert_eq!(e, Bolt12SemanticError::MissingPaths);
1068 } else {
1069 panic!("expected error")
1070 }
1071
1072 if let Err(e) = StaticInvoiceBuilder::for_offer_using_derived_keys(
1074 &valid_offer,
1075 payment_paths(),
1076 Vec::new(),
1077 now,
1078 &expanded_key,
1079 nonce,
1080 &secp_ctx,
1081 ) {
1082 assert_eq!(e, Bolt12SemanticError::MissingPaths);
1083 } else {
1084 panic!("expected error")
1085 }
1086
1087 let mut offer_without_paths = valid_offer.clone();
1089 let (mut offer_tlv_stream, _) = offer_without_paths.as_tlv_stream();
1090 offer_tlv_stream.paths.take();
1091 let mut buffer = Vec::new();
1092 offer_tlv_stream.write(&mut buffer).unwrap();
1093 offer_without_paths = Offer::try_from(buffer).unwrap();
1094 if let Err(e) = StaticInvoiceBuilder::for_offer_using_derived_keys(
1095 &offer_without_paths,
1096 payment_paths(),
1097 vec![blinded_path()],
1098 now,
1099 &expanded_key,
1100 nonce,
1101 &secp_ctx,
1102 ) {
1103 assert_eq!(e, Bolt12SemanticError::MissingPaths);
1104 } else {
1105 panic!("expected error")
1106 }
1107 }
1108
1109 #[test]
1110 fn fails_building_with_missing_issuer_signing_pubkey() {
1111 let node_id = recipient_pubkey();
1112 let now = now();
1113 let expanded_key = ExpandedKey::new([42; 32]);
1114 let entropy = FixedEntropy {};
1115 let nonce = Nonce::from_entropy_source(&entropy);
1116 let secp_ctx = Secp256k1::new();
1117
1118 let valid_offer =
1119 OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
1120 .path(blinded_path())
1121 .build()
1122 .unwrap();
1123
1124 let mut offer_missing_issuer_id = valid_offer.clone();
1125 let (mut offer_tlv_stream, _) = offer_missing_issuer_id.as_tlv_stream();
1126 offer_tlv_stream.issuer_id.take();
1127 let mut buffer = Vec::new();
1128 offer_tlv_stream.write(&mut buffer).unwrap();
1129 offer_missing_issuer_id = Offer::try_from(buffer).unwrap();
1130
1131 if let Err(e) = StaticInvoiceBuilder::for_offer_using_derived_keys(
1132 &offer_missing_issuer_id,
1133 payment_paths(),
1134 vec![blinded_path()],
1135 now,
1136 &expanded_key,
1137 nonce,
1138 &secp_ctx,
1139 ) {
1140 assert_eq!(e, Bolt12SemanticError::MissingIssuerSigningPubkey);
1141 } else {
1142 panic!("expected error")
1143 }
1144 }
1145
1146 #[test]
1147 fn fails_building_with_invalid_metadata() {
1148 let now = now();
1149 let expanded_key = ExpandedKey::new([42; 32]);
1150 let entropy = FixedEntropy {};
1151 let nonce = Nonce::from_entropy_source(&entropy);
1152 let secp_ctx = Secp256k1::new();
1153
1154 let offer = OfferBuilder::new(recipient_pubkey())
1155 .path(blinded_path())
1156 .metadata(vec![42; 32])
1157 .unwrap()
1158 .build()
1159 .unwrap();
1160 if let Err(e) = StaticInvoiceBuilder::for_offer_using_derived_keys(
1161 &offer,
1162 payment_paths(),
1163 vec![blinded_path()],
1164 now,
1165 &expanded_key,
1166 nonce,
1167 &secp_ctx,
1168 ) {
1169 assert_eq!(e, Bolt12SemanticError::InvalidMetadata);
1170 } else {
1171 panic!("expected error")
1172 }
1173 }
1174
1175 #[test]
1176 fn fails_building_with_extra_offer_chains() {
1177 let node_id = recipient_pubkey();
1178 let now = now();
1179 let expanded_key = ExpandedKey::new([42; 32]);
1180 let entropy = FixedEntropy {};
1181 let nonce = Nonce::from_entropy_source(&entropy);
1182 let secp_ctx = Secp256k1::new();
1183
1184 let offer_with_extra_chain =
1185 OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
1186 .path(blinded_path())
1187 .chain(Network::Bitcoin)
1188 .chain(Network::Testnet)
1189 .build()
1190 .unwrap();
1191
1192 if let Err(e) = StaticInvoiceBuilder::for_offer_using_derived_keys(
1193 &offer_with_extra_chain,
1194 payment_paths(),
1195 vec![blinded_path()],
1196 now,
1197 &expanded_key,
1198 nonce,
1199 &secp_ctx,
1200 ) {
1201 assert_eq!(e, Bolt12SemanticError::UnexpectedChain);
1202 } else {
1203 panic!("expected error")
1204 }
1205 }
1206
1207 #[test]
1208 fn parses_invoice_with_relative_expiry() {
1209 let node_id = recipient_pubkey();
1210 let payment_paths = payment_paths();
1211 let now = now();
1212 let expanded_key = ExpandedKey::new([42; 32]);
1213 let entropy = FixedEntropy {};
1214 let nonce = Nonce::from_entropy_source(&entropy);
1215 let secp_ctx = Secp256k1::new();
1216
1217 let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
1218 .path(blinded_path())
1219 .build()
1220 .unwrap();
1221
1222 const TEST_RELATIVE_EXPIRY: u32 = 3600;
1223 let invoice = StaticInvoiceBuilder::for_offer_using_derived_keys(
1224 &offer,
1225 payment_paths.clone(),
1226 vec![blinded_path()],
1227 now,
1228 &expanded_key,
1229 nonce,
1230 &secp_ctx,
1231 )
1232 .unwrap()
1233 .relative_expiry(TEST_RELATIVE_EXPIRY)
1234 .build_and_sign(&secp_ctx)
1235 .unwrap();
1236
1237 let mut buffer = Vec::new();
1238 invoice.write(&mut buffer).unwrap();
1239
1240 match StaticInvoice::try_from(buffer) {
1241 Ok(invoice) => assert_eq!(
1242 invoice.relative_expiry(),
1243 Duration::from_secs(TEST_RELATIVE_EXPIRY as u64)
1244 ),
1245 Err(e) => panic!("error parsing invoice: {:?}", e),
1246 }
1247 }
1248
1249 #[test]
1250 fn parses_invoice_with_allow_mpp() {
1251 let node_id = recipient_pubkey();
1252 let payment_paths = payment_paths();
1253 let now = now();
1254 let expanded_key = ExpandedKey::new([42; 32]);
1255 let entropy = FixedEntropy {};
1256 let nonce = Nonce::from_entropy_source(&entropy);
1257 let secp_ctx = Secp256k1::new();
1258
1259 let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
1260 .path(blinded_path())
1261 .build()
1262 .unwrap();
1263
1264 let invoice = StaticInvoiceBuilder::for_offer_using_derived_keys(
1265 &offer,
1266 payment_paths.clone(),
1267 vec![blinded_path()],
1268 now,
1269 &expanded_key,
1270 nonce,
1271 &secp_ctx,
1272 )
1273 .unwrap()
1274 .allow_mpp()
1275 .build_and_sign(&secp_ctx)
1276 .unwrap();
1277
1278 let mut buffer = Vec::new();
1279 invoice.write(&mut buffer).unwrap();
1280
1281 match StaticInvoice::try_from(buffer) {
1282 Ok(invoice) => {
1283 let mut features = Bolt12InvoiceFeatures::empty();
1284 features.set_basic_mpp_optional();
1285 assert_eq!(invoice.invoice_features(), &features);
1286 },
1287 Err(e) => panic!("error parsing invoice: {:?}", e),
1288 }
1289 }
1290
1291 #[test]
1292 fn fails_parsing_missing_invoice_fields() {
1293 let missing_created_at_invoice = invoice();
1295 let mut tlv_stream = missing_created_at_invoice.as_tlv_stream();
1296 tlv_stream.1.created_at = None;
1297 match StaticInvoice::try_from(tlv_stream_to_bytes(&tlv_stream)) {
1298 Ok(_) => panic!("expected error"),
1299 Err(e) => {
1300 assert_eq!(
1301 e,
1302 Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingCreationTime)
1303 );
1304 },
1305 }
1306
1307 let missing_node_id_invoice = invoice();
1309 let mut tlv_stream = missing_node_id_invoice.as_tlv_stream();
1310 tlv_stream.1.node_id = None;
1311 match StaticInvoice::try_from(tlv_stream_to_bytes(&tlv_stream)) {
1312 Ok(_) => panic!("expected error"),
1313 Err(e) => {
1314 assert_eq!(
1315 e,
1316 Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSigningPubkey)
1317 );
1318 },
1319 }
1320
1321 let missing_message_paths_invoice = invoice();
1323 let mut tlv_stream = missing_message_paths_invoice.as_tlv_stream();
1324 tlv_stream.1.message_paths = None;
1325 match StaticInvoice::try_from(tlv_stream_to_bytes(&tlv_stream)) {
1326 Ok(_) => panic!("expected error"),
1327 Err(e) => {
1328 assert_eq!(
1329 e,
1330 Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingPaths)
1331 );
1332 },
1333 }
1334
1335 let invoice = invoice();
1337 let mut buffer = Vec::new();
1338 invoice.contents.as_tlv_stream().write(&mut buffer).unwrap();
1339 match StaticInvoice::try_from(buffer) {
1340 Ok(_) => panic!("expected error"),
1341 Err(e) => assert_eq!(
1342 e,
1343 Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSignature)
1344 ),
1345 }
1346 }
1347
1348 #[test]
1349 fn fails_parsing_invalid_signing_pubkey() {
1350 let invoice = invoice();
1351 let invalid_pubkey = payer_pubkey();
1352 let mut tlv_stream = invoice.as_tlv_stream();
1353 tlv_stream.1.node_id = Some(&invalid_pubkey);
1354
1355 match StaticInvoice::try_from(tlv_stream_to_bytes(&tlv_stream)) {
1356 Ok(_) => panic!("expected error"),
1357 Err(e) => {
1358 assert_eq!(
1359 e,
1360 Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::InvalidSigningPubkey)
1361 );
1362 },
1363 }
1364 }
1365
1366 #[test]
1367 fn fails_parsing_invoice_with_invalid_signature() {
1368 let mut invoice = invoice();
1369 let last_signature_byte = invoice.bytes.last_mut().unwrap();
1370 *last_signature_byte = last_signature_byte.wrapping_add(1);
1371
1372 let mut buffer = Vec::new();
1373 invoice.write(&mut buffer).unwrap();
1374
1375 match StaticInvoice::try_from(buffer) {
1376 Ok(_) => panic!("expected error"),
1377 Err(e) => {
1378 assert_eq!(
1379 e,
1380 Bolt12ParseError::InvalidSignature(secp256k1::Error::IncorrectSignature)
1381 );
1382 },
1383 }
1384 }
1385
1386 #[test]
1387 fn parses_invoice_with_unknown_tlv_records() {
1388 let node_id = recipient_pubkey();
1389 let payment_paths = payment_paths();
1390 let now = now();
1391 let expanded_key = ExpandedKey::new([42; 32]);
1392 let entropy = FixedEntropy {};
1393 let nonce = Nonce::from_entropy_source(&entropy);
1394 let secp_ctx = Secp256k1::new();
1395
1396 let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
1397 .path(blinded_path())
1398 .build()
1399 .unwrap();
1400
1401 const UNKNOWN_ODD_TYPE: u64 = INVOICE_TYPES.end - 1;
1402 assert!(UNKNOWN_ODD_TYPE % 2 == 1);
1403
1404 let (mut unsigned_invoice, keys) = StaticInvoiceBuilder::for_offer_using_derived_keys(
1405 &offer,
1406 payment_paths.clone(),
1407 vec![blinded_path()],
1408 now,
1409 &expanded_key,
1410 nonce,
1411 &secp_ctx,
1412 )
1413 .unwrap()
1414 .build()
1415 .unwrap();
1416
1417 let mut unknown_bytes = Vec::new();
1418 BigSize(UNKNOWN_ODD_TYPE).write(&mut unknown_bytes).unwrap();
1419 BigSize(32).write(&mut unknown_bytes).unwrap();
1420 [42u8; 32].write(&mut unknown_bytes).unwrap();
1421
1422 unsigned_invoice.bytes.extend_from_slice(&unknown_bytes);
1423 unsigned_invoice.tagged_hash =
1424 TaggedHash::from_valid_tlv_stream_bytes(SIGNATURE_TAG, &unsigned_invoice.bytes);
1425
1426 let invoice = unsigned_invoice
1427 .sign(|message: &UnsignedStaticInvoice| {
1428 Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
1429 })
1430 .unwrap();
1431
1432 let mut encoded_invoice = Vec::new();
1433 invoice.write(&mut encoded_invoice).unwrap();
1434
1435 match StaticInvoice::try_from(encoded_invoice.clone()) {
1436 Ok(invoice) => assert_eq!(invoice.bytes, encoded_invoice),
1437 Err(e) => panic!("error parsing invoice: {:?}", e),
1438 }
1439
1440 const UNKNOWN_EVEN_TYPE: u64 = INVOICE_TYPES.end - 2;
1441 assert!(UNKNOWN_EVEN_TYPE % 2 == 0);
1442
1443 let (mut unsigned_invoice, keys) = StaticInvoiceBuilder::for_offer_using_derived_keys(
1444 &offer,
1445 payment_paths.clone(),
1446 vec![blinded_path()],
1447 now,
1448 &expanded_key,
1449 nonce,
1450 &secp_ctx,
1451 )
1452 .unwrap()
1453 .build()
1454 .unwrap();
1455
1456 let mut unknown_bytes = Vec::new();
1457 BigSize(UNKNOWN_EVEN_TYPE).write(&mut unknown_bytes).unwrap();
1458 BigSize(32).write(&mut unknown_bytes).unwrap();
1459 [42u8; 32].write(&mut unknown_bytes).unwrap();
1460
1461 unsigned_invoice.bytes.extend_from_slice(&unknown_bytes);
1462 unsigned_invoice.tagged_hash =
1463 TaggedHash::from_valid_tlv_stream_bytes(SIGNATURE_TAG, &unsigned_invoice.bytes);
1464
1465 let invoice = unsigned_invoice
1466 .sign(|message: &UnsignedStaticInvoice| {
1467 Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
1468 })
1469 .unwrap();
1470
1471 let mut encoded_invoice = Vec::new();
1472 invoice.write(&mut encoded_invoice).unwrap();
1473
1474 match StaticInvoice::try_from(encoded_invoice) {
1475 Ok(_) => panic!("expected error"),
1476 Err(e) => assert_eq!(e, Bolt12ParseError::Decode(DecodeError::UnknownRequiredFeature)),
1477 }
1478 }
1479
1480 #[test]
1481 fn parses_invoice_with_experimental_tlv_records() {
1482 let node_id = recipient_pubkey();
1483 let payment_paths = payment_paths();
1484 let now = now();
1485 let expanded_key = ExpandedKey::new([42; 32]);
1486 let entropy = FixedEntropy {};
1487 let nonce = Nonce::from_entropy_source(&entropy);
1488 let secp_ctx = Secp256k1::new();
1489
1490 let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
1491 .path(blinded_path())
1492 .build()
1493 .unwrap();
1494
1495 let invoice = StaticInvoiceBuilder::for_offer_using_derived_keys(
1496 &offer,
1497 payment_paths.clone(),
1498 vec![blinded_path()],
1499 now,
1500 &expanded_key,
1501 nonce,
1502 &secp_ctx,
1503 )
1504 .unwrap()
1505 .experimental_baz(42)
1506 .build_and_sign(&secp_ctx)
1507 .unwrap();
1508
1509 let mut encoded_invoice = Vec::new();
1510 invoice.write(&mut encoded_invoice).unwrap();
1511
1512 assert!(StaticInvoice::try_from(encoded_invoice).is_ok());
1513
1514 const UNKNOWN_ODD_TYPE: u64 = EXPERIMENTAL_INVOICE_TYPES.start + 1;
1515 assert!(UNKNOWN_ODD_TYPE % 2 == 1);
1516
1517 let (mut unsigned_invoice, keys) = StaticInvoiceBuilder::for_offer_using_derived_keys(
1518 &offer,
1519 payment_paths.clone(),
1520 vec![blinded_path()],
1521 now,
1522 &expanded_key,
1523 nonce,
1524 &secp_ctx,
1525 )
1526 .unwrap()
1527 .build()
1528 .unwrap();
1529
1530 let mut unknown_bytes = Vec::new();
1531 BigSize(UNKNOWN_ODD_TYPE).write(&mut unknown_bytes).unwrap();
1532 BigSize(32).write(&mut unknown_bytes).unwrap();
1533 [42u8; 32].write(&mut unknown_bytes).unwrap();
1534
1535 unsigned_invoice.experimental_bytes.extend_from_slice(&unknown_bytes);
1536
1537 let tlv_stream = TlvStream::new(&unsigned_invoice.bytes)
1538 .chain(TlvStream::new(&unsigned_invoice.experimental_bytes));
1539 unsigned_invoice.tagged_hash = TaggedHash::from_tlv_stream(SIGNATURE_TAG, tlv_stream);
1540
1541 let invoice = unsigned_invoice
1542 .sign(|message: &UnsignedStaticInvoice| {
1543 Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
1544 })
1545 .unwrap();
1546
1547 let mut encoded_invoice = Vec::new();
1548 invoice.write(&mut encoded_invoice).unwrap();
1549
1550 match StaticInvoice::try_from(encoded_invoice.clone()) {
1551 Ok(invoice) => assert_eq!(invoice.bytes, encoded_invoice),
1552 Err(e) => panic!("error parsing invoice: {:?}", e),
1553 }
1554
1555 const UNKNOWN_EVEN_TYPE: u64 = EXPERIMENTAL_INVOICE_TYPES.start;
1556 assert!(UNKNOWN_EVEN_TYPE % 2 == 0);
1557
1558 let (mut unsigned_invoice, keys) = StaticInvoiceBuilder::for_offer_using_derived_keys(
1559 &offer,
1560 payment_paths.clone(),
1561 vec![blinded_path()],
1562 now,
1563 &expanded_key,
1564 nonce,
1565 &secp_ctx,
1566 )
1567 .unwrap()
1568 .build()
1569 .unwrap();
1570
1571 let mut unknown_bytes = Vec::new();
1572 BigSize(UNKNOWN_EVEN_TYPE).write(&mut unknown_bytes).unwrap();
1573 BigSize(32).write(&mut unknown_bytes).unwrap();
1574 [42u8; 32].write(&mut unknown_bytes).unwrap();
1575
1576 unsigned_invoice.experimental_bytes.extend_from_slice(&unknown_bytes);
1577
1578 let tlv_stream = TlvStream::new(&unsigned_invoice.bytes)
1579 .chain(TlvStream::new(&unsigned_invoice.experimental_bytes));
1580 unsigned_invoice.tagged_hash = TaggedHash::from_tlv_stream(SIGNATURE_TAG, tlv_stream);
1581
1582 let invoice = unsigned_invoice
1583 .sign(|message: &UnsignedStaticInvoice| {
1584 Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
1585 })
1586 .unwrap();
1587
1588 let mut encoded_invoice = Vec::new();
1589 invoice.write(&mut encoded_invoice).unwrap();
1590
1591 match StaticInvoice::try_from(encoded_invoice) {
1592 Ok(_) => panic!("expected error"),
1593 Err(e) => assert_eq!(e, Bolt12ParseError::Decode(DecodeError::UnknownRequiredFeature)),
1594 }
1595
1596 let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
1597 .path(blinded_path())
1598 .build()
1599 .unwrap();
1600
1601 let invoice = StaticInvoiceBuilder::for_offer_using_derived_keys(
1602 &offer,
1603 payment_paths.clone(),
1604 vec![blinded_path()],
1605 now,
1606 &expanded_key,
1607 nonce,
1608 &secp_ctx,
1609 )
1610 .unwrap()
1611 .build_and_sign(&secp_ctx)
1612 .unwrap();
1613
1614 let mut encoded_invoice = Vec::new();
1615 invoice.write(&mut encoded_invoice).unwrap();
1616
1617 BigSize(UNKNOWN_ODD_TYPE).write(&mut encoded_invoice).unwrap();
1618 BigSize(32).write(&mut encoded_invoice).unwrap();
1619 [42u8; 32].write(&mut encoded_invoice).unwrap();
1620
1621 match StaticInvoice::try_from(encoded_invoice) {
1622 Ok(_) => panic!("expected error"),
1623 Err(e) => assert_eq!(
1624 e,
1625 Bolt12ParseError::InvalidSignature(secp256k1::Error::IncorrectSignature)
1626 ),
1627 }
1628 }
1629
1630 #[test]
1631 fn fails_parsing_invoice_with_out_of_range_tlv_records() {
1632 let invoice = invoice();
1633 let mut encoded_invoice = Vec::new();
1634 invoice.write(&mut encoded_invoice).unwrap();
1635 BigSize(1002).write(&mut encoded_invoice).unwrap();
1636 BigSize(32).write(&mut encoded_invoice).unwrap();
1637 [42u8; 32].write(&mut encoded_invoice).unwrap();
1638
1639 match StaticInvoice::try_from(encoded_invoice) {
1640 Ok(_) => panic!("expected error"),
1641 Err(e) => assert_eq!(e, Bolt12ParseError::Decode(DecodeError::InvalidValue)),
1642 }
1643 }
1644
1645 #[test]
1646 fn fails_parsing_invoice_with_invalid_offer_fields() {
1647 let missing_offer_paths_invoice = invoice();
1649 let mut tlv_stream = missing_offer_paths_invoice.as_tlv_stream();
1650 tlv_stream.0.paths = None;
1651 match StaticInvoice::try_from(tlv_stream_to_bytes(&tlv_stream)) {
1652 Ok(_) => panic!("expected error"),
1653 Err(e) => {
1654 assert_eq!(
1655 e,
1656 Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingPaths)
1657 );
1658 },
1659 }
1660
1661 let invalid_offer_chains_invoice = invoice();
1663 let mut tlv_stream = invalid_offer_chains_invoice.as_tlv_stream();
1664 let invalid_chains = vec![
1665 ChainHash::using_genesis_block(Network::Bitcoin),
1666 ChainHash::using_genesis_block(Network::Testnet),
1667 ];
1668 tlv_stream.0.chains = Some(&invalid_chains);
1669 match StaticInvoice::try_from(tlv_stream_to_bytes(&tlv_stream)) {
1670 Ok(_) => panic!("expected error"),
1671 Err(e) => {
1672 assert_eq!(
1673 e,
1674 Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::UnexpectedChain)
1675 );
1676 },
1677 }
1678 }
1679
1680 #[test]
1681 fn static_invoice_offer_id_matches_offer_id() {
1682 let node_id = recipient_pubkey();
1683 let payment_paths = payment_paths();
1684 let now = now();
1685 let expanded_key = ExpandedKey::new([42; 32]);
1686 let entropy = FixedEntropy {};
1687 let nonce = Nonce::from_entropy_source(&entropy);
1688 let secp_ctx = Secp256k1::new();
1689
1690 let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
1691 .path(blinded_path())
1692 .build()
1693 .unwrap();
1694
1695 let offer_id = offer.id();
1696
1697 let invoice = StaticInvoiceBuilder::for_offer_using_derived_keys(
1698 &offer,
1699 payment_paths.clone(),
1700 vec![blinded_path()],
1701 now,
1702 &expanded_key,
1703 nonce,
1704 &secp_ctx,
1705 )
1706 .unwrap()
1707 .build_and_sign(&secp_ctx)
1708 .unwrap();
1709
1710 assert_eq!(invoice.offer_id(), offer_id);
1711 }
1712}