Builder for creating static invoices from offers
[rust-lightning] / lightning / src / offers / static_invoice.rs
1 // This file is Copyright its original authors, visible in version control
2 // history.
3 //
4 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7 // You may not use this file except in accordance with one or both of these
8 // licenses.
9
10 //! Data structures and encoding for static BOLT 12 invoices.
11
12 use crate::blinded_path::BlindedPath;
13 use crate::io;
14 use crate::ln::features::{Bolt12InvoiceFeatures, OfferFeatures};
15 use crate::ln::inbound_payment::ExpandedKey;
16 use crate::ln::msgs::DecodeError;
17 use crate::offers::invoice::{
18         check_invoice_signing_pubkey, construct_payment_paths, filter_fallbacks, BlindedPathIter,
19         BlindedPayInfo, BlindedPayInfoIter, FallbackAddress, InvoiceTlvStream, InvoiceTlvStreamRef,
20 };
21 use crate::offers::invoice_macros::{invoice_accessors_common, invoice_builder_methods_common};
22 use crate::offers::merkle::{
23         self, SignError, SignFn, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash,
24 };
25 use crate::offers::offer::{
26         Amount, Offer, OfferContents, OfferTlvStream, OfferTlvStreamRef, Quantity,
27 };
28 use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
29 use crate::util::ser::{
30         HighZeroBytesDroppedBigSize, Iterable, SeekReadable, WithoutLength, Writeable, Writer,
31 };
32 use crate::util::string::PrintableString;
33 use bitcoin::address::Address;
34 use bitcoin::blockdata::constants::ChainHash;
35 use bitcoin::secp256k1::schnorr::Signature;
36 use bitcoin::secp256k1::{self, Keypair, PublicKey, Secp256k1};
37 use core::time::Duration;
38
39 #[cfg(feature = "std")]
40 use crate::offers::invoice::is_expired;
41
42 #[allow(unused_imports)]
43 use crate::prelude::*;
44
45 /// Static invoices default to expiring after 2 weeks.
46 const DEFAULT_RELATIVE_EXPIRY: Duration = Duration::from_secs(3600 * 24 * 14);
47
48 /// Tag for the hash function used when signing a [`StaticInvoice`]'s merkle root.
49 pub const SIGNATURE_TAG: &'static str = concat!("lightning", "static_invoice", "signature");
50
51 /// A `StaticInvoice` is a reusable payment request corresponding to an [`Offer`].
52 ///
53 /// A static invoice may be sent in response to an [`InvoiceRequest`] and includes all the
54 /// information needed to pay the recipient. However, unlike [`Bolt12Invoice`]s, static invoices do
55 /// not provide proof-of-payment. Therefore, [`Bolt12Invoice`]s should be preferred when the
56 /// recipient is online to provide one.
57 ///
58 /// [`Offer`]: crate::offers::offer::Offer
59 /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
60 /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
61 #[derive(Clone, Debug)]
62 pub struct StaticInvoice {
63         bytes: Vec<u8>,
64         contents: InvoiceContents,
65         signature: Signature,
66 }
67
68 /// The contents of a [`StaticInvoice`] for responding to an [`Offer`].
69 ///
70 /// [`Offer`]: crate::offers::offer::Offer
71 #[derive(Clone, Debug)]
72 struct InvoiceContents {
73         offer: OfferContents,
74         payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
75         created_at: Duration,
76         relative_expiry: Option<Duration>,
77         fallbacks: Option<Vec<FallbackAddress>>,
78         features: Bolt12InvoiceFeatures,
79         signing_pubkey: PublicKey,
80         message_paths: Vec<BlindedPath>,
81 }
82
83 /// Builds a [`StaticInvoice`] from an [`Offer`].
84 ///
85 /// [`Offer`]: crate::offers::offer::Offer
86 /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
87 // TODO: add module-level docs and link here
88 pub struct StaticInvoiceBuilder<'a> {
89         offer_bytes: &'a Vec<u8>,
90         invoice: InvoiceContents,
91         keys: Keypair,
92 }
93
94 impl<'a> StaticInvoiceBuilder<'a> {
95         /// Initialize a [`StaticInvoiceBuilder`] from the given [`Offer`].
96         ///
97         /// Unless [`StaticInvoiceBuilder::relative_expiry`] is set, the invoice will expire 24 hours
98         /// after `created_at`.
99         pub fn for_offer_using_derived_keys<T: secp256k1::Signing>(
100                 offer: &'a Offer, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
101                 message_paths: Vec<BlindedPath>, created_at: Duration, expanded_key: &ExpandedKey,
102                 secp_ctx: &Secp256k1<T>,
103         ) -> Result<Self, Bolt12SemanticError> {
104                 if offer.chains().len() > 1 {
105                         return Err(Bolt12SemanticError::UnexpectedChain);
106                 }
107
108                 if payment_paths.is_empty() || message_paths.is_empty() || offer.paths().is_empty() {
109                         return Err(Bolt12SemanticError::MissingPaths);
110                 }
111
112                 let offer_signing_pubkey =
113                         offer.signing_pubkey().ok_or(Bolt12SemanticError::MissingSigningPubkey)?;
114
115                 let keys = offer
116                         .verify(&expanded_key, &secp_ctx)
117                         .map_err(|()| Bolt12SemanticError::InvalidMetadata)?
118                         .1
119                         .ok_or(Bolt12SemanticError::MissingSigningPubkey)?;
120
121                 let signing_pubkey = keys.public_key();
122                 if signing_pubkey != offer_signing_pubkey {
123                         return Err(Bolt12SemanticError::InvalidSigningPubkey);
124                 }
125
126                 let invoice =
127                         InvoiceContents::new(offer, payment_paths, message_paths, created_at, signing_pubkey);
128
129                 Ok(Self { offer_bytes: &offer.bytes, invoice, keys })
130         }
131
132         /// Builds a signed [`StaticInvoice`] after checking for valid semantics.
133         pub fn build_and_sign<T: secp256k1::Signing>(
134                 self, secp_ctx: &Secp256k1<T>,
135         ) -> Result<StaticInvoice, Bolt12SemanticError> {
136                 #[cfg(feature = "std")]
137                 {
138                         if self.invoice.is_offer_expired() {
139                                 return Err(Bolt12SemanticError::AlreadyExpired);
140                         }
141                 }
142
143                 #[cfg(not(feature = "std"))]
144                 {
145                         if self.invoice.is_offer_expired_no_std(self.invoice.created_at()) {
146                                 return Err(Bolt12SemanticError::AlreadyExpired);
147                         }
148                 }
149
150                 let Self { offer_bytes, invoice, keys } = self;
151                 let unsigned_invoice = UnsignedStaticInvoice::new(&offer_bytes, invoice);
152                 let invoice = unsigned_invoice
153                         .sign(|message: &UnsignedStaticInvoice| {
154                                 Ok(secp_ctx.sign_schnorr_no_aux_rand(message.tagged_hash.as_digest(), &keys))
155                         })
156                         .unwrap();
157                 Ok(invoice)
158         }
159
160         invoice_builder_methods_common!(self, Self, self.invoice, Self, self, S, StaticInvoice, mut);
161 }
162
163 /// A semantically valid [`StaticInvoice`] that hasn't been signed.
164 pub struct UnsignedStaticInvoice {
165         bytes: Vec<u8>,
166         contents: InvoiceContents,
167         tagged_hash: TaggedHash,
168 }
169
170 macro_rules! invoice_accessors { ($self: ident, $contents: expr) => {
171         /// The chain that must be used when paying the invoice. [`StaticInvoice`]s currently can only be
172         /// created from offers that support a single chain.
173         pub fn chain(&$self) -> ChainHash {
174                 $contents.chain()
175         }
176
177         /// Opaque bytes set by the originating [`Offer::metadata`].
178         ///
179         /// [`Offer::metadata`]: crate::offers::offer::Offer::metadata
180         pub fn metadata(&$self) -> Option<&Vec<u8>> {
181                 $contents.metadata()
182         }
183
184         /// The minimum amount required for a successful payment of a single item.
185         ///
186         /// From [`Offer::amount`].
187         ///
188         /// [`Offer::amount`]: crate::offers::offer::Offer::amount
189         pub fn amount(&$self) -> Option<Amount> {
190                 $contents.amount()
191         }
192
193         /// Features pertaining to the originating [`Offer`], from [`Offer::offer_features`].
194         ///
195         /// [`Offer`]: crate::offers::offer::Offer
196         /// [`Offer::offer_features`]: crate::offers::offer::Offer::offer_features
197         pub fn offer_features(&$self) -> &OfferFeatures {
198                 $contents.offer_features()
199         }
200
201         /// A complete description of the purpose of the originating offer, from [`Offer::description`].
202         ///
203         /// [`Offer::description`]: crate::offers::offer::Offer::description
204         pub fn description(&$self) -> Option<PrintableString> {
205                 $contents.description()
206         }
207
208         /// Duration since the Unix epoch when an invoice should no longer be requested, from
209         /// [`Offer::absolute_expiry`].
210         ///
211         /// [`Offer::absolute_expiry`]: crate::offers::offer::Offer::absolute_expiry
212         pub fn absolute_expiry(&$self) -> Option<Duration> {
213                 $contents.absolute_expiry()
214         }
215
216         /// The issuer of the offer, from [`Offer::issuer`].
217         ///
218         /// [`Offer::issuer`]: crate::offers::offer::Offer::issuer
219         pub fn issuer(&$self) -> Option<PrintableString> {
220                 $contents.issuer()
221         }
222
223         /// Paths to the node that may supply the invoice on the recipient's behalf, originating from
224         /// publicly reachable nodes. Taken from [`Offer::paths`].
225         ///
226         /// [`Offer::paths`]: crate::offers::offer::Offer::paths
227         pub fn offer_message_paths(&$self) -> &[BlindedPath] {
228                 $contents.offer_message_paths()
229         }
230
231         /// Paths to the recipient for indicating that a held HTLC is available to claim when they next
232         /// come online.
233         pub fn message_paths(&$self) -> &[BlindedPath] {
234                 $contents.message_paths()
235         }
236
237         /// The quantity of items supported, from [`Offer::supported_quantity`].
238         ///
239         /// [`Offer::supported_quantity`]: crate::offers::offer::Offer::supported_quantity
240         pub fn supported_quantity(&$self) -> Quantity {
241                 $contents.supported_quantity()
242         }
243 } }
244
245 impl UnsignedStaticInvoice {
246         fn new(offer_bytes: &Vec<u8>, contents: InvoiceContents) -> Self {
247                 let (_, invoice_tlv_stream) = contents.as_tlv_stream();
248                 let offer_bytes = WithoutLength(offer_bytes);
249                 let unsigned_tlv_stream = (offer_bytes, invoice_tlv_stream);
250
251                 let mut bytes = Vec::new();
252                 unsigned_tlv_stream.write(&mut bytes).unwrap();
253
254                 let tagged_hash = TaggedHash::from_valid_tlv_stream_bytes(SIGNATURE_TAG, &bytes);
255
256                 Self { contents, tagged_hash, bytes }
257         }
258
259         /// Signs the [`TaggedHash`] of the invoice using the given function.
260         ///
261         /// Note: The hash computation may have included unknown, odd TLV records.
262         pub fn sign<F: SignStaticInvoiceFn>(mut self, sign: F) -> Result<StaticInvoice, SignError> {
263                 let pubkey = self.contents.signing_pubkey;
264                 let signature = merkle::sign_message(sign, &self, pubkey)?;
265
266                 // Append the signature TLV record to the bytes.
267                 let signature_tlv_stream = SignatureTlvStreamRef { signature: Some(&signature) };
268                 signature_tlv_stream.write(&mut self.bytes).unwrap();
269
270                 Ok(StaticInvoice { bytes: self.bytes, contents: self.contents, signature })
271         }
272
273         invoice_accessors_common!(self, self.contents, StaticInvoice);
274         invoice_accessors!(self, self.contents);
275 }
276
277 impl AsRef<TaggedHash> for UnsignedStaticInvoice {
278         fn as_ref(&self) -> &TaggedHash {
279                 &self.tagged_hash
280         }
281 }
282
283 /// A function for signing an [`UnsignedStaticInvoice`].
284 pub trait SignStaticInvoiceFn {
285         /// Signs a [`TaggedHash`] computed over the merkle root of `message`'s TLV stream.
286         fn sign_invoice(&self, message: &UnsignedStaticInvoice) -> Result<Signature, ()>;
287 }
288
289 impl<F> SignStaticInvoiceFn for F
290 where
291         F: Fn(&UnsignedStaticInvoice) -> Result<Signature, ()>,
292 {
293         fn sign_invoice(&self, message: &UnsignedStaticInvoice) -> Result<Signature, ()> {
294                 self(message)
295         }
296 }
297
298 impl<F> SignFn<UnsignedStaticInvoice> for F
299 where
300         F: SignStaticInvoiceFn,
301 {
302         fn sign(&self, message: &UnsignedStaticInvoice) -> Result<Signature, ()> {
303                 self.sign_invoice(message)
304         }
305 }
306
307 impl StaticInvoice {
308         invoice_accessors_common!(self, self.contents, StaticInvoice);
309         invoice_accessors!(self, self.contents);
310
311         /// Signature of the invoice verified using [`StaticInvoice::signing_pubkey`].
312         pub fn signature(&self) -> Signature {
313                 self.signature
314         }
315 }
316
317 impl InvoiceContents {
318         #[cfg(feature = "std")]
319         fn is_offer_expired(&self) -> bool {
320                 self.offer.is_expired()
321         }
322
323         #[cfg(not(feature = "std"))]
324         fn is_offer_expired_no_std(&self, duration_since_epoch: Duration) -> bool {
325                 self.offer.is_expired_no_std(duration_since_epoch)
326         }
327
328         fn new(
329                 offer: &Offer, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
330                 message_paths: Vec<BlindedPath>, created_at: Duration, signing_pubkey: PublicKey,
331         ) -> Self {
332                 Self {
333                         offer: offer.contents.clone(),
334                         payment_paths,
335                         message_paths,
336                         created_at,
337                         relative_expiry: None,
338                         fallbacks: None,
339                         features: Bolt12InvoiceFeatures::empty(),
340                         signing_pubkey,
341                 }
342         }
343
344         fn as_tlv_stream(&self) -> PartialInvoiceTlvStreamRef {
345                 let features = {
346                         if self.features == Bolt12InvoiceFeatures::empty() {
347                                 None
348                         } else {
349                                 Some(&self.features)
350                         }
351                 };
352
353                 let invoice = InvoiceTlvStreamRef {
354                         paths: Some(Iterable(self.payment_paths.iter().map(|(_, path)| path))),
355                         message_paths: Some(self.message_paths.as_ref()),
356                         blindedpay: Some(Iterable(self.payment_paths.iter().map(|(payinfo, _)| payinfo))),
357                         created_at: Some(self.created_at.as_secs()),
358                         relative_expiry: self.relative_expiry.map(|duration| duration.as_secs() as u32),
359                         fallbacks: self.fallbacks.as_ref(),
360                         features,
361                         node_id: Some(&self.signing_pubkey),
362                         amount: None,
363                         payment_hash: None,
364                 };
365
366                 (self.offer.as_tlv_stream(), invoice)
367         }
368
369         fn chain(&self) -> ChainHash {
370                 debug_assert_eq!(self.offer.chains().len(), 1);
371                 self.offer.chains().first().cloned().unwrap_or_else(|| self.offer.implied_chain())
372         }
373
374         fn metadata(&self) -> Option<&Vec<u8>> {
375                 self.offer.metadata()
376         }
377
378         fn amount(&self) -> Option<Amount> {
379                 self.offer.amount()
380         }
381
382         fn offer_features(&self) -> &OfferFeatures {
383                 self.offer.features()
384         }
385
386         fn description(&self) -> Option<PrintableString> {
387                 self.offer.description()
388         }
389
390         fn absolute_expiry(&self) -> Option<Duration> {
391                 self.offer.absolute_expiry()
392         }
393
394         fn issuer(&self) -> Option<PrintableString> {
395                 self.offer.issuer()
396         }
397
398         fn offer_message_paths(&self) -> &[BlindedPath] {
399                 self.offer.paths()
400         }
401
402         fn message_paths(&self) -> &[BlindedPath] {
403                 &self.message_paths[..]
404         }
405
406         fn supported_quantity(&self) -> Quantity {
407                 self.offer.supported_quantity()
408         }
409
410         fn payment_paths(&self) -> &[(BlindedPayInfo, BlindedPath)] {
411                 &self.payment_paths[..]
412         }
413
414         fn created_at(&self) -> Duration {
415                 self.created_at
416         }
417
418         fn relative_expiry(&self) -> Duration {
419                 self.relative_expiry.unwrap_or(DEFAULT_RELATIVE_EXPIRY)
420         }
421
422         #[cfg(feature = "std")]
423         fn is_expired(&self) -> bool {
424                 is_expired(self.created_at(), self.relative_expiry())
425         }
426
427         fn fallbacks(&self) -> Vec<Address> {
428                 let chain = self.chain();
429                 self.fallbacks
430                         .as_ref()
431                         .map(|fallbacks| filter_fallbacks(chain, fallbacks))
432                         .unwrap_or_else(Vec::new)
433         }
434
435         fn features(&self) -> &Bolt12InvoiceFeatures {
436                 &self.features
437         }
438
439         fn signing_pubkey(&self) -> PublicKey {
440                 self.signing_pubkey
441         }
442 }
443
444 impl Writeable for StaticInvoice {
445         fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
446                 WithoutLength(&self.bytes).write(writer)
447         }
448 }
449
450 impl TryFrom<Vec<u8>> for StaticInvoice {
451         type Error = Bolt12ParseError;
452
453         fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
454                 let parsed_invoice = ParsedMessage::<FullInvoiceTlvStream>::try_from(bytes)?;
455                 StaticInvoice::try_from(parsed_invoice)
456         }
457 }
458
459 type FullInvoiceTlvStream = (OfferTlvStream, InvoiceTlvStream, SignatureTlvStream);
460
461 impl SeekReadable for FullInvoiceTlvStream {
462         fn read<R: io::Read + io::Seek>(r: &mut R) -> Result<Self, DecodeError> {
463                 let offer = SeekReadable::read(r)?;
464                 let invoice = SeekReadable::read(r)?;
465                 let signature = SeekReadable::read(r)?;
466
467                 Ok((offer, invoice, signature))
468         }
469 }
470
471 type PartialInvoiceTlvStream = (OfferTlvStream, InvoiceTlvStream);
472
473 type PartialInvoiceTlvStreamRef<'a> = (OfferTlvStreamRef<'a>, InvoiceTlvStreamRef<'a>);
474
475 impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for StaticInvoice {
476         type Error = Bolt12ParseError;
477
478         fn try_from(invoice: ParsedMessage<FullInvoiceTlvStream>) -> Result<Self, Self::Error> {
479                 let ParsedMessage { bytes, tlv_stream } = invoice;
480                 let (offer_tlv_stream, invoice_tlv_stream, SignatureTlvStream { signature }) = tlv_stream;
481                 let contents = InvoiceContents::try_from((offer_tlv_stream, invoice_tlv_stream))?;
482
483                 let signature = match signature {
484                         None => {
485                                 return Err(Bolt12ParseError::InvalidSemantics(
486                                         Bolt12SemanticError::MissingSignature,
487                                 ))
488                         },
489                         Some(signature) => signature,
490                 };
491                 let tagged_hash = TaggedHash::from_valid_tlv_stream_bytes(SIGNATURE_TAG, &bytes);
492                 let pubkey = contents.signing_pubkey;
493                 merkle::verify_signature(&signature, &tagged_hash, pubkey)?;
494
495                 Ok(StaticInvoice { bytes, contents, signature })
496         }
497 }
498
499 impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
500         type Error = Bolt12SemanticError;
501
502         fn try_from(tlv_stream: PartialInvoiceTlvStream) -> Result<Self, Self::Error> {
503                 let (
504                         offer_tlv_stream,
505                         InvoiceTlvStream {
506                                 paths,
507                                 blindedpay,
508                                 created_at,
509                                 relative_expiry,
510                                 fallbacks,
511                                 features,
512                                 node_id,
513                                 message_paths,
514                                 payment_hash,
515                                 amount,
516                         },
517                 ) = tlv_stream;
518
519                 if payment_hash.is_some() {
520                         return Err(Bolt12SemanticError::UnexpectedPaymentHash);
521                 }
522                 if amount.is_some() {
523                         return Err(Bolt12SemanticError::UnexpectedAmount);
524                 }
525
526                 let payment_paths = construct_payment_paths(blindedpay, paths)?;
527                 let message_paths = message_paths.ok_or(Bolt12SemanticError::MissingPaths)?;
528
529                 let created_at = match created_at {
530                         None => return Err(Bolt12SemanticError::MissingCreationTime),
531                         Some(timestamp) => Duration::from_secs(timestamp),
532                 };
533
534                 let relative_expiry = relative_expiry.map(Into::<u64>::into).map(Duration::from_secs);
535
536                 let features = features.unwrap_or_else(Bolt12InvoiceFeatures::empty);
537
538                 let signing_pubkey = node_id.ok_or(Bolt12SemanticError::MissingSigningPubkey)?;
539                 check_invoice_signing_pubkey(&signing_pubkey, &offer_tlv_stream)?;
540
541                 if offer_tlv_stream.paths.is_none() {
542                         return Err(Bolt12SemanticError::MissingPaths);
543                 }
544                 if offer_tlv_stream.chains.as_ref().map_or(0, |chains| chains.len()) > 1 {
545                         return Err(Bolt12SemanticError::UnexpectedChain);
546                 }
547
548                 Ok(InvoiceContents {
549                         offer: OfferContents::try_from(offer_tlv_stream)?,
550                         payment_paths,
551                         message_paths,
552                         created_at,
553                         relative_expiry,
554                         fallbacks,
555                         features,
556                         signing_pubkey,
557                 })
558         }
559 }