2 #![deny(non_upper_case_globals)]
3 #![deny(non_camel_case_types)]
4 #![deny(non_snake_case)]
6 #![deny(broken_intra_doc_links)]
8 #![cfg_attr(feature = "strict", deny(warnings))]
10 //! This crate provides data structures to represent
11 //! [lightning BOLT11](https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md)
12 //! invoices and functions to create, encode and decode these. If you just want to use the standard
13 //! en-/decoding functionality this should get you started:
15 //! * For parsing use `str::parse::<Invoice>(&self)` (see the docs of `impl FromStr for Invoice`)
16 //! * For constructing invoices use the `InvoiceBuilder`
17 //! * For serializing invoices use the `Display`/`ToString` traits
21 extern crate bitcoin_hashes;
22 extern crate lightning;
23 extern crate num_traits;
24 extern crate secp256k1;
27 use bitcoin_hashes::Hash;
28 use bitcoin_hashes::sha256;
29 use lightning::ln::PaymentSecret;
30 use lightning::ln::features::InvoiceFeatures;
31 #[cfg(any(doc, test))]
32 use lightning::routing::network_graph::RoutingFees;
33 use lightning::routing::router::RouteHint;
35 use secp256k1::key::PublicKey;
36 use secp256k1::{Message, Secp256k1};
37 use secp256k1::recovery::RecoverableSignature;
39 use std::fmt::{Display, Formatter, self};
40 use std::iter::FilterMap;
43 use std::time::{SystemTime, Duration, UNIX_EPOCH};
49 pub use de::{ParseError, ParseOrSemanticError};
51 // TODO: fix before 2037 (see rust PR #55527)
52 /// Defines the maximum UNIX timestamp that can be represented as `SystemTime`. This is checked by
53 /// one of the unit tests, please run them.
54 const SYSTEM_TIME_MAX_UNIX_TIMESTAMP: u64 = std::i32::MAX as u64;
56 /// Allow the expiry time to be up to one year. Since this reduces the range of possible timestamps
57 /// it should be rather low as long as we still have to support 32bit time representations
58 const MAX_EXPIRY_TIME: u64 = 60 * 60 * 24 * 356;
60 /// Default expiry time as defined by [BOLT 11].
62 /// [BOLT 11]: https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md
63 const DEFAULT_EXPIRY_TIME: u64 = 3600;
65 /// Default minimum final CLTV expiry as defined by [BOLT 11].
67 /// [BOLT 11]: https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md
68 const DEFAULT_MIN_FINAL_CLTV_EXPIRY: u64 = 18;
70 /// This function is used as a static assert for the size of `SystemTime`. If the crate fails to
71 /// compile due to it this indicates that your system uses unexpected bounds for `SystemTime`. You
72 /// can remove this functions and run the test `test_system_time_bounds_assumptions`. In any case,
73 /// please open an issue. If all tests pass you should be able to use this library safely by just
74 /// removing this function till we patch it accordingly.
75 fn __system_time_size_check() {
76 // Use 2 * sizeof(u64) as expected size since the expected underlying implementation is storing
77 // a `Duration` since `SystemTime::UNIX_EPOCH`.
78 unsafe { std::mem::transmute_copy::<SystemTime, [u8; 16]>(&UNIX_EPOCH); }
82 /// **Call this function on startup to ensure that all assumptions about the platform are valid.**
84 /// Unfortunately we have to make assumptions about the upper bounds of the `SystemTime` type on
85 /// your platform which we can't fully verify at compile time and which isn't part of it's contract.
86 /// To our best knowledge our assumptions hold for all platforms officially supported by rust, but
87 /// since this check is fast we recommend to do it anyway.
89 /// If this function fails this is considered a bug. Please open an issue describing your
90 /// platform and stating your current system time.
93 /// If the check fails this function panics. By calling this function on startup you ensure that
94 /// this wont happen at an arbitrary later point in time.
95 pub fn check_platform() {
96 // The upper and lower bounds of `SystemTime` are not part of its public contract and are
97 // platform specific. That's why we have to test if our assumptions regarding these bounds
98 // hold on the target platform.
100 // If this test fails on your platform, please don't use the library and open an issue
101 // instead so we can resolve the situation. Currently this library is tested on:
103 let fail_date = UNIX_EPOCH + Duration::from_secs(SYSTEM_TIME_MAX_UNIX_TIMESTAMP);
104 let year = Duration::from_secs(60 * 60 * 24 * 365);
106 // Make sure that the library will keep working for another year
107 assert!(fail_date.duration_since(SystemTime::now()).unwrap() > year);
109 let max_ts = PositiveTimestamp::from_unix_timestamp(
110 SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME
112 let max_exp = ::ExpiryTime::from_seconds(MAX_EXPIRY_TIME).unwrap();
115 (*max_ts.as_time() + *max_exp.as_duration()).duration_since(UNIX_EPOCH).unwrap().as_secs(),
116 SYSTEM_TIME_MAX_UNIX_TIMESTAMP
121 /// Builder for `Invoice`s. It's the most convenient and advised way to use this library. It ensures
122 /// that only a semantically and syntactically correct Invoice can be built using it.
125 /// extern crate secp256k1;
126 /// extern crate lightning_invoice;
127 /// extern crate bitcoin_hashes;
129 /// use bitcoin_hashes::Hash;
130 /// use bitcoin_hashes::sha256;
132 /// use secp256k1::Secp256k1;
133 /// use secp256k1::key::SecretKey;
135 /// use lightning_invoice::{Currency, InvoiceBuilder};
138 /// let private_key = SecretKey::from_slice(
140 /// 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f,
141 /// 0xe2, 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04,
142 /// 0xa8, 0xca, 0x3b, 0x2d, 0xb7, 0x34
146 /// let payment_hash = sha256::Hash::from_slice(&[0; 32][..]).unwrap();
148 /// let invoice = InvoiceBuilder::new(Currency::Bitcoin)
149 /// .description("Coins pls!".into())
150 /// .payment_hash(payment_hash)
151 /// .current_timestamp()
152 /// .min_final_cltv_expiry(144)
153 /// .build_signed(|hash| {
154 /// Secp256k1::new().sign_recoverable(hash, &private_key)
158 /// assert!(invoice.to_string().starts_with("lnbc1"));
162 /// # Type parameters
163 /// The two parameters `D` and `H` signal if the builder already contains the correct amount of the
165 /// * `D`: exactly one `Description` or `DescriptionHash`
166 /// * `H`: exactly one `PaymentHash`
167 /// * `T`: the timestamp is set
169 /// (C-not exported) as we likely need to manually select one set of boolean type parameters.
170 #[derive(Eq, PartialEq, Debug, Clone)]
171 pub struct InvoiceBuilder<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> {
174 si_prefix: Option<SiPrefix>,
175 timestamp: Option<PositiveTimestamp>,
176 tagged_fields: Vec<TaggedField>,
177 error: Option<CreationError>,
179 phantom_d: std::marker::PhantomData<D>,
180 phantom_h: std::marker::PhantomData<H>,
181 phantom_t: std::marker::PhantomData<T>,
182 phantom_c: std::marker::PhantomData<C>,
183 phantom_s: std::marker::PhantomData<S>,
186 /// Represents a syntactically and semantically correct lightning BOLT11 invoice.
188 /// There are three ways to construct an `Invoice`:
189 /// 1. using `InvoiceBuilder`
190 /// 2. using `Invoice::from_signed(SignedRawInvoice)`
191 /// 3. using `str::parse::<Invoice>(&str)`
192 #[derive(Eq, PartialEq, Debug, Clone)]
194 signed_invoice: SignedRawInvoice,
197 /// Represents the description of an invoice which has to be either a directly included string or
198 /// a hash of a description provided out of band.
200 /// (C-not exported) As we don't have a good way to map the reference lifetimes making this
201 /// practically impossible to use safely in languages like C.
202 #[derive(Eq, PartialEq, Debug, Clone)]
203 pub enum InvoiceDescription<'f> {
204 /// Reference to the directly supplied description in the invoice
205 Direct(&'f Description),
207 /// Reference to the description's hash included in the invoice
211 /// Represents a signed `RawInvoice` with cached hash. The signature is not checked and may be
215 /// The hash has to be either from the deserialized invoice or from the serialized `raw_invoice`.
216 #[derive(Eq, PartialEq, Debug, Clone)]
217 pub struct SignedRawInvoice {
218 /// The rawInvoice that the signature belongs to
219 raw_invoice: RawInvoice,
221 /// Hash of the `RawInvoice` that will be used to check the signature.
223 /// * if the `SignedRawInvoice` was deserialized the hash is of from the original encoded form,
224 /// since it's not guaranteed that encoding it again will lead to the same result since integers
225 /// could have been encoded with leading zeroes etc.
226 /// * if the `SignedRawInvoice` was constructed manually the hash will be the calculated hash
227 /// from the `RawInvoice`
230 /// signature of the payment request
231 signature: InvoiceSignature,
234 /// Represents an syntactically correct Invoice for a payment on the lightning network,
235 /// but without the signature information.
236 /// De- and encoding should not lead to information loss but may lead to different hashes.
238 /// For methods without docs see the corresponding methods in `Invoice`.
239 #[derive(Eq, PartialEq, Debug, Clone)]
240 pub struct RawInvoice {
241 /// human readable part
245 pub data: RawDataPart,
248 /// Data of the `RawInvoice` that is encoded in the human readable part
250 /// (C-not exported) As we don't yet support Option<Enum>
251 #[derive(Eq, PartialEq, Debug, Clone)]
253 /// The currency deferred from the 3rd and 4th character of the bech32 transaction
254 pub currency: Currency,
256 /// The amount that, multiplied by the SI prefix, has to be payed
257 pub raw_amount: Option<u64>,
259 /// SI prefix that gets multiplied with the `raw_amount`
260 pub si_prefix: Option<SiPrefix>,
263 /// Data of the `RawInvoice` that is encoded in the data part
264 #[derive(Eq, PartialEq, Debug, Clone)]
265 pub struct RawDataPart {
266 /// generation time of the invoice
267 pub timestamp: PositiveTimestamp,
269 /// tagged fields of the payment request
270 pub tagged_fields: Vec<RawTaggedField>,
273 /// A timestamp that refers to a date after 1 January 1970 which means its representation as UNIX
274 /// timestamp is positive.
277 /// The UNIX timestamp representing the stored time has to be positive and small enough so that
278 /// a `EpiryTime` can be added to it without an overflow.
279 #[derive(Eq, PartialEq, Debug, Clone)]
280 pub struct PositiveTimestamp(SystemTime);
282 /// SI prefixes for the human readable part
283 #[derive(Eq, PartialEq, Debug, Clone, Copy)]
296 /// Returns the multiplier to go from a BTC value to picoBTC implied by this SiPrefix.
297 /// This is effectively 10^12 * the prefix multiplier
298 pub fn multiplier(&self) -> u64 {
300 SiPrefix::Milli => 1_000_000_000,
301 SiPrefix::Micro => 1_000_000,
302 SiPrefix::Nano => 1_000,
307 /// Returns all enum variants of `SiPrefix` sorted in descending order of their associated
310 /// (C-not exported) As we don't yet support a slice of enums, and also because this function
311 /// isn't the most critical to expose.
312 pub fn values_desc() -> &'static [SiPrefix] {
314 static VALUES: [SiPrefix; 4] = [Milli, Micro, Nano, Pico];
319 /// Enum representing the crypto currencies (or networks) supported by this library
320 #[derive(Eq, PartialEq, Debug, Clone)]
338 /// Tagged field which may have an unknown tag
340 /// (C-not exported) as we don't currently support TaggedField
341 #[derive(Eq, PartialEq, Debug, Clone)]
342 pub enum RawTaggedField {
343 /// Parsed tagged field with known tag
344 KnownSemantics(TaggedField),
345 /// tagged field which was not parsed due to an unknown tag or undefined field semantics
346 UnknownSemantics(Vec<u5>),
349 /// Tagged field with known tag
351 /// For descriptions of the enum values please refer to the enclosed type's docs.
353 /// (C-not exported) As we don't yet support enum variants with the same name the struct contained
355 #[allow(missing_docs)]
356 #[derive(Eq, PartialEq, Debug, Clone)]
357 pub enum TaggedField {
359 Description(Description),
360 PayeePubKey(PayeePubKey),
361 DescriptionHash(Sha256),
362 ExpiryTime(ExpiryTime),
363 MinFinalCltvExpiry(MinFinalCltvExpiry),
365 PrivateRoute(PrivateRoute),
366 PaymentSecret(PaymentSecret),
367 Features(InvoiceFeatures),
371 #[derive(Eq, PartialEq, Debug, Clone)]
372 pub struct Sha256(pub sha256::Hash);
374 /// Description string
377 /// The description can be at most 639 __bytes__ long
378 #[derive(Eq, PartialEq, Debug, Clone)]
379 pub struct Description(String);
382 #[derive(Eq, PartialEq, Debug, Clone)]
383 pub struct PayeePubKey(pub PublicKey);
385 /// Positive duration that defines when (relatively to the timestamp) in the future the invoice
389 /// The number of seconds this expiry time represents has to be in the range
390 /// `0...(SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME)` to avoid overflows when adding it to a
392 #[derive(Eq, PartialEq, Debug, Clone)]
393 pub struct ExpiryTime(Duration);
395 /// `min_final_cltv_expiry` to use for the last HTLC in the route
396 #[derive(Eq, PartialEq, Debug, Clone)]
397 pub struct MinFinalCltvExpiry(pub u64);
399 // TODO: better types instead onf byte arrays
400 /// Fallback address in case no LN payment is possible
401 #[allow(missing_docs)]
402 #[derive(Eq, PartialEq, Debug, Clone)]
408 PubKeyHash([u8; 20]),
409 ScriptHash([u8; 20]),
412 /// Recoverable signature
413 #[derive(Eq, PartialEq, Debug, Clone)]
414 pub struct InvoiceSignature(pub RecoverableSignature);
416 /// Private routing information
419 /// The encoded route has to be <1024 5bit characters long (<=639 bytes or <=12 hops)
421 #[derive(Eq, PartialEq, Debug, Clone)]
422 pub struct PrivateRoute(RouteHint);
424 /// Tag constants as specified in BOLT11
425 #[allow(missing_docs)]
427 pub const TAG_PAYMENT_HASH: u8 = 1;
428 pub const TAG_DESCRIPTION: u8 = 13;
429 pub const TAG_PAYEE_PUB_KEY: u8 = 19;
430 pub const TAG_DESCRIPTION_HASH: u8 = 23;
431 pub const TAG_EXPIRY_TIME: u8 = 6;
432 pub const TAG_MIN_FINAL_CLTV_EXPIRY: u8 = 24;
433 pub const TAG_FALLBACK: u8 = 9;
434 pub const TAG_PRIVATE_ROUTE: u8 = 3;
435 pub const TAG_PAYMENT_SECRET: u8 = 16;
436 pub const TAG_FEATURES: u8 = 5;
439 impl InvoiceBuilder<tb::False, tb::False, tb::False, tb::False, tb::False> {
440 /// Construct new, empty `InvoiceBuilder`. All necessary fields have to be filled first before
441 /// `InvoiceBuilder::build(self)` becomes available.
442 pub fn new(currrency: Currency) -> Self {
448 tagged_fields: Vec::new(),
451 phantom_d: std::marker::PhantomData,
452 phantom_h: std::marker::PhantomData,
453 phantom_t: std::marker::PhantomData,
454 phantom_c: std::marker::PhantomData,
455 phantom_s: std::marker::PhantomData,
460 impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<D, H, T, C, S> {
461 /// Helper function to set the completeness flags.
462 fn set_flags<DN: tb::Bool, HN: tb::Bool, TN: tb::Bool, CN: tb::Bool, SN: tb::Bool>(self) -> InvoiceBuilder<DN, HN, TN, CN, SN> {
463 InvoiceBuilder::<DN, HN, TN, CN, SN> {
464 currency: self.currency,
466 si_prefix: self.si_prefix,
467 timestamp: self.timestamp,
468 tagged_fields: self.tagged_fields,
471 phantom_d: std::marker::PhantomData,
472 phantom_h: std::marker::PhantomData,
473 phantom_t: std::marker::PhantomData,
474 phantom_c: std::marker::PhantomData,
475 phantom_s: std::marker::PhantomData,
479 /// Sets the amount in pico BTC. The optimal SI prefix is choosen automatically.
480 pub fn amount_pico_btc(mut self, amount: u64) -> Self {
481 let biggest_possible_si_prefix = SiPrefix::values_desc()
483 .find(|prefix| amount % prefix.multiplier() == 0)
484 .expect("Pico should always match");
485 self.amount = Some(amount / biggest_possible_si_prefix.multiplier());
486 self.si_prefix = Some(*biggest_possible_si_prefix);
490 /// Sets the payee's public key.
491 pub fn payee_pub_key(mut self, pub_key: PublicKey) -> Self {
492 self.tagged_fields.push(TaggedField::PayeePubKey(PayeePubKey(pub_key)));
496 /// Sets the expiry time
497 pub fn expiry_time(mut self, expiry_time: Duration) -> Self {
498 match ExpiryTime::from_duration(expiry_time) {
499 Ok(t) => self.tagged_fields.push(TaggedField::ExpiryTime(t)),
500 Err(e) => self.error = Some(e),
505 /// Adds a fallback address.
506 pub fn fallback(mut self, fallback: Fallback) -> Self {
507 self.tagged_fields.push(TaggedField::Fallback(fallback));
511 /// Adds a private route.
512 pub fn private_route(mut self, hint: RouteHint) -> Self {
513 match PrivateRoute::new(hint) {
514 Ok(r) => self.tagged_fields.push(TaggedField::PrivateRoute(r)),
515 Err(e) => self.error = Some(e),
521 impl<D: tb::Bool, H: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<D, H, tb::True, C, S> {
522 /// Builds a `RawInvoice` if no `CreationError` occurred while construction any of the fields.
523 pub fn build_raw(self) -> Result<RawInvoice, CreationError> {
525 // If an error occurred at any time before, return it now
526 if let Some(e) = self.error {
531 currency: self.currency,
532 raw_amount: self.amount,
533 si_prefix: self.si_prefix,
536 let timestamp = self.timestamp.expect("ensured to be Some(t) by type T");
538 let tagged_fields = self.tagged_fields.into_iter().map(|tf| {
539 RawTaggedField::KnownSemantics(tf)
540 }).collect::<Vec<_>>();
542 let data = RawDataPart {
543 timestamp: timestamp,
544 tagged_fields: tagged_fields,
554 impl<H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<tb::False, H, T, C, S> {
555 /// Set the description. This function is only available if no description (hash) was set.
556 pub fn description(mut self, description: String) -> InvoiceBuilder<tb::True, H, T, C, S> {
557 match Description::new(description) {
558 Ok(d) => self.tagged_fields.push(TaggedField::Description(d)),
559 Err(e) => self.error = Some(e),
564 /// Set the description hash. This function is only available if no description (hash) was set.
565 pub fn description_hash(mut self, description_hash: sha256::Hash) -> InvoiceBuilder<tb::True, H, T, C, S> {
566 self.tagged_fields.push(TaggedField::DescriptionHash(Sha256(description_hash)));
571 impl<D: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<D, tb::False, T, C, S> {
572 /// Set the payment hash. This function is only available if no payment hash was set.
573 pub fn payment_hash(mut self, hash: sha256::Hash) -> InvoiceBuilder<D, tb::True, T, C, S> {
574 self.tagged_fields.push(TaggedField::PaymentHash(Sha256(hash)));
579 impl<D: tb::Bool, H: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<D, H, tb::False, C, S> {
580 /// Sets the timestamp.
581 pub fn timestamp(mut self, time: SystemTime) -> InvoiceBuilder<D, H, tb::True, C, S> {
582 match PositiveTimestamp::from_system_time(time) {
583 Ok(t) => self.timestamp = Some(t),
584 Err(e) => self.error = Some(e),
590 /// Sets the timestamp to the current UNIX timestamp.
591 pub fn current_timestamp(mut self) -> InvoiceBuilder<D, H, tb::True, C, S> {
592 let now = PositiveTimestamp::from_system_time(SystemTime::now());
593 self.timestamp = Some(now.expect("for the foreseeable future this shouldn't happen"));
598 impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, S: tb::Bool> InvoiceBuilder<D, H, T, tb::False, S> {
599 /// Sets `min_final_cltv_expiry`.
600 pub fn min_final_cltv_expiry(mut self, min_final_cltv_expiry: u64) -> InvoiceBuilder<D, H, T, tb::True, S> {
601 self.tagged_fields.push(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry(min_final_cltv_expiry)));
606 impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool> InvoiceBuilder<D, H, T, C, tb::False> {
607 /// Sets the payment secret and relevant features.
608 pub fn payment_secret(mut self, payment_secret: PaymentSecret) -> InvoiceBuilder<D, H, T, C, tb::True> {
609 let features = InvoiceFeatures::empty()
610 .set_variable_length_onion_required()
611 .set_payment_secret_required();
612 self.tagged_fields.push(TaggedField::PaymentSecret(payment_secret));
613 self.tagged_fields.push(TaggedField::Features(features));
618 impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool> InvoiceBuilder<D, H, T, C, tb::True> {
619 /// Sets the `basic_mpp` feature as optional.
620 pub fn basic_mpp(mut self) -> Self {
621 self.tagged_fields = self.tagged_fields
623 .map(|field| match field {
624 TaggedField::Features(f) => TaggedField::Features(f.set_basic_mpp_optional()),
632 impl<S: tb::Bool> InvoiceBuilder<tb::True, tb::True, tb::True, tb::True, S> {
633 /// Builds and signs an invoice using the supplied `sign_function`. This function MAY NOT fail
634 /// and MUST produce a recoverable signature valid for the given hash and if applicable also for
635 /// the included payee public key.
636 pub fn build_signed<F>(self, sign_function: F) -> Result<Invoice, CreationError>
637 where F: FnOnce(&Message) -> RecoverableSignature
639 let invoice = self.try_build_signed::<_, ()>(|hash| {
640 Ok(sign_function(hash))
645 Err(SignOrCreationError::CreationError(e)) => Err(e),
646 Err(SignOrCreationError::SignError(())) => unreachable!(),
650 /// Builds and signs an invoice using the supplied `sign_function`. This function MAY fail with
651 /// an error of type `E` and MUST produce a recoverable signature valid for the given hash and
652 /// if applicable also for the included payee public key.
653 pub fn try_build_signed<F, E>(self, sign_function: F) -> Result<Invoice, SignOrCreationError<E>>
654 where F: FnOnce(&Message) -> Result<RecoverableSignature, E>
656 let raw = match self.build_raw() {
658 Err(e) => return Err(SignOrCreationError::CreationError(e)),
661 let signed = match raw.sign(sign_function) {
663 Err(e) => return Err(SignOrCreationError::SignError(e)),
666 let invoice = Invoice {
667 signed_invoice: signed,
670 invoice.check_field_counts().expect("should be ensured by type signature of builder");
671 invoice.check_feature_bits().expect("should be ensured by type signature of builder");
678 impl SignedRawInvoice {
679 /// Disassembles the `SignedRawInvoice` into its three parts:
681 /// 2. hash of the raw invoice
683 pub fn into_parts(self) -> (RawInvoice, [u8; 32], InvoiceSignature) {
684 (self.raw_invoice, self.hash, self.signature)
687 /// The `RawInvoice` which was signed.
688 pub fn raw_invoice(&self) -> &RawInvoice {
692 /// The hash of the `RawInvoice` that was signed.
693 pub fn hash(&self) -> &[u8; 32] {
697 /// InvoiceSignature for the invoice.
698 pub fn signature(&self) -> &InvoiceSignature {
702 /// Recovers the public key used for signing the invoice from the recoverable signature.
703 pub fn recover_payee_pub_key(&self) -> Result<PayeePubKey, secp256k1::Error> {
704 let hash = Message::from_slice(&self.hash[..])
705 .expect("Hash is 32 bytes long, same as MESSAGE_SIZE");
707 Ok(PayeePubKey(Secp256k1::new().recover(
713 /// Checks if the signature is valid for the included payee public key or if none exists if it's
714 /// valid for the recovered signature (which should always be true?).
715 pub fn check_signature(&self) -> bool {
716 let included_pub_key = self.raw_invoice.payee_pub_key();
718 let mut recovered_pub_key = Option::None;
719 if recovered_pub_key.is_none() {
720 let recovered = match self.recover_payee_pub_key() {
722 Err(_) => return false,
724 recovered_pub_key = Some(recovered);
727 let pub_key = included_pub_key.or_else(|| recovered_pub_key.as_ref())
728 .expect("One is always present");
730 let hash = Message::from_slice(&self.hash[..])
731 .expect("Hash is 32 bytes long, same as MESSAGE_SIZE");
733 let secp_context = Secp256k1::new();
734 let verification_result = secp_context.verify(
736 &self.signature.to_standard(),
740 match verification_result {
747 /// Finds the first element of an enum stream of a given variant and extracts one member of the
748 /// variant. If no element was found `None` gets returned.
750 /// The following example would extract the first B.
759 /// let elements = vec![A(1), A(2), B(3), A(4)]
761 /// assert_eq!(find_extract!(elements.iter(), Enum::B(ref x), x), Some(3u16))
763 macro_rules! find_extract {
764 ($iter:expr, $enm:pat, $enm_var:ident) => {
765 find_all_extract!($iter, $enm, $enm_var).next()
769 /// Finds the all elements of an enum stream of a given variant and extracts one member of the
770 /// variant through an iterator.
772 /// The following example would extract all A.
781 /// let elements = vec![A(1), A(2), B(3), A(4)]
784 /// find_all_extract!(elements.iter(), Enum::A(ref x), x).collect::<Vec<u8>>(),
785 /// vec![1u8, 2u8, 4u8])
787 macro_rules! find_all_extract {
788 ($iter:expr, $enm:pat, $enm_var:ident) => {
789 $iter.filter_map(|tf| match *tf {
790 $enm => Some($enm_var),
796 #[allow(missing_docs)]
798 /// Construct the invoice's HRP and signatureless data into a preimage to be hashed.
799 pub(crate) fn construct_invoice_preimage(hrp_bytes: &[u8], data_without_signature: &[u5]) -> Vec<u8> {
800 use bech32::FromBase32;
802 let mut preimage = Vec::<u8>::from(hrp_bytes);
804 let mut data_part = Vec::from(data_without_signature);
805 let overhang = (data_part.len() * 5) % 8;
807 // add padding if data does not end at a byte boundary
808 data_part.push(u5::try_from_u8(0).unwrap());
810 // if overhang is in (1..3) we need to add u5(0) padding two times
812 data_part.push(u5::try_from_u8(0).unwrap());
816 preimage.extend_from_slice(&Vec::<u8>::from_base32(&data_part)
817 .expect("No padding error may occur due to appended zero above."));
821 /// Hash the HRP as bytes and signatureless data part.
822 fn hash_from_parts(hrp_bytes: &[u8], data_without_signature: &[u5]) -> [u8; 32] {
823 let preimage = RawInvoice::construct_invoice_preimage(hrp_bytes, data_without_signature);
824 let mut hash: [u8; 32] = Default::default();
825 hash.copy_from_slice(&sha256::Hash::hash(&preimage)[..]);
829 /// Calculate the hash of the encoded `RawInvoice`
830 pub fn hash(&self) -> [u8; 32] {
831 use bech32::ToBase32;
833 RawInvoice::hash_from_parts(
834 self.hrp.to_string().as_bytes(),
835 &self.data.to_base32()
839 /// Signs the invoice using the supplied `sign_function`. This function MAY fail with an error
840 /// of type `E`. Since the signature of a `SignedRawInvoice` is not required to be valid there
841 /// are no constraints regarding the validity of the produced signature.
843 /// (C-not exported) As we don't currently support passing function pointers into methods
845 pub fn sign<F, E>(self, sign_method: F) -> Result<SignedRawInvoice, E>
846 where F: FnOnce(&Message) -> Result<RecoverableSignature, E>
848 let raw_hash = self.hash();
849 let hash = Message::from_slice(&raw_hash[..])
850 .expect("Hash is 32 bytes long, same as MESSAGE_SIZE");
851 let signature = sign_method(&hash)?;
853 Ok(SignedRawInvoice {
856 signature: InvoiceSignature(signature),
860 /// Returns an iterator over all tagged fields with known semantics.
862 /// (C-not exported) As there is not yet a manual mapping for a FilterMap
863 pub fn known_tagged_fields(&self)
864 -> FilterMap<Iter<RawTaggedField>, fn(&RawTaggedField) -> Option<&TaggedField>>
866 // For 1.14.0 compatibility: closures' types can't be written an fn()->() in the
867 // function's type signature.
868 // TODO: refactor once impl Trait is available
869 fn match_raw(raw: &RawTaggedField) -> Option<&TaggedField> {
871 RawTaggedField::KnownSemantics(ref tf) => Some(tf),
876 self.data.tagged_fields.iter().filter_map(match_raw )
879 pub fn payment_hash(&self) -> Option<&Sha256> {
880 find_extract!(self.known_tagged_fields(), TaggedField::PaymentHash(ref x), x)
883 pub fn description(&self) -> Option<&Description> {
884 find_extract!(self.known_tagged_fields(), TaggedField::Description(ref x), x)
887 pub fn payee_pub_key(&self) -> Option<&PayeePubKey> {
888 find_extract!(self.known_tagged_fields(), TaggedField::PayeePubKey(ref x), x)
891 pub fn description_hash(&self) -> Option<&Sha256> {
892 find_extract!(self.known_tagged_fields(), TaggedField::DescriptionHash(ref x), x)
895 pub fn expiry_time(&self) -> Option<&ExpiryTime> {
896 find_extract!(self.known_tagged_fields(), TaggedField::ExpiryTime(ref x), x)
899 pub fn min_final_cltv_expiry(&self) -> Option<&MinFinalCltvExpiry> {
900 find_extract!(self.known_tagged_fields(), TaggedField::MinFinalCltvExpiry(ref x), x)
903 pub fn payment_secret(&self) -> Option<&PaymentSecret> {
904 find_extract!(self.known_tagged_fields(), TaggedField::PaymentSecret(ref x), x)
907 pub fn features(&self) -> Option<&InvoiceFeatures> {
908 find_extract!(self.known_tagged_fields(), TaggedField::Features(ref x), x)
911 /// (C-not exported) as we don't support Vec<&NonOpaqueType>
912 pub fn fallbacks(&self) -> Vec<&Fallback> {
913 find_all_extract!(self.known_tagged_fields(), TaggedField::Fallback(ref x), x).collect()
916 pub fn private_routes(&self) -> Vec<&PrivateRoute> {
917 find_all_extract!(self.known_tagged_fields(), TaggedField::PrivateRoute(ref x), x).collect()
920 pub fn amount_pico_btc(&self) -> Option<u64> {
921 self.hrp.raw_amount.map(|v| {
922 v * self.hrp.si_prefix.as_ref().map_or(1_000_000_000_000, |si| { si.multiplier() })
926 pub fn currency(&self) -> Currency {
927 self.hrp.currency.clone()
931 impl PositiveTimestamp {
932 /// Create a new `PositiveTimestamp` from a unix timestamp in the Range
933 /// `0...SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME`, otherwise return a
934 /// `CreationError::TimestampOutOfBounds`.
935 pub fn from_unix_timestamp(unix_seconds: u64) -> Result<Self, CreationError> {
936 if unix_seconds > SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME {
937 Err(CreationError::TimestampOutOfBounds)
939 Ok(PositiveTimestamp(UNIX_EPOCH + Duration::from_secs(unix_seconds)))
943 /// Create a new `PositiveTimestamp` from a `SystemTime` with a corresponding unix timestamp in
944 /// the Range `0...SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME`, otherwise return a
945 /// `CreationError::TimestampOutOfBounds`.
946 pub fn from_system_time(time: SystemTime) -> Result<Self, CreationError> {
948 .duration_since(UNIX_EPOCH)
949 .map(|t| t.as_secs() <= SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME)
952 Ok(PositiveTimestamp(time))
954 Err(CreationError::TimestampOutOfBounds)
958 /// Returns the UNIX timestamp representing the stored time
959 pub fn as_unix_timestamp(&self) -> u64 {
960 self.0.duration_since(UNIX_EPOCH)
961 .expect("ensured by type contract/constructors")
965 /// Returns a reference to the internal `SystemTime` time representation
966 pub fn as_time(&self) -> &SystemTime {
971 impl Into<SystemTime> for PositiveTimestamp {
972 fn into(self) -> SystemTime {
977 impl Deref for PositiveTimestamp {
978 type Target = SystemTime;
980 fn deref(&self) -> &Self::Target {
986 /// Transform the `Invoice` into it's unchecked version
987 pub fn into_signed_raw(self) -> SignedRawInvoice {
991 /// Check that all mandatory fields are present
992 fn check_field_counts(&self) -> Result<(), SemanticError> {
993 // "A writer MUST include exactly one p field […]."
994 let payment_hash_cnt = self.tagged_fields().filter(|&tf| match *tf {
995 TaggedField::PaymentHash(_) => true,
998 if payment_hash_cnt < 1 {
999 return Err(SemanticError::NoPaymentHash);
1000 } else if payment_hash_cnt > 1 {
1001 return Err(SemanticError::MultiplePaymentHashes);
1004 // "A writer MUST include either exactly one d or exactly one h field."
1005 let description_cnt = self.tagged_fields().filter(|&tf| match *tf {
1006 TaggedField::Description(_) | TaggedField::DescriptionHash(_) => true,
1009 if description_cnt < 1 {
1010 return Err(SemanticError::NoDescription);
1011 } else if description_cnt > 1 {
1012 return Err(SemanticError::MultipleDescriptions);
1018 /// Check that feature bits are set as required
1019 fn check_feature_bits(&self) -> Result<(), SemanticError> {
1020 // "If the payment_secret feature is set, MUST include exactly one s field."
1021 let payment_secret_count = self.tagged_fields().filter(|&tf| match *tf {
1022 TaggedField::PaymentSecret(_) => true,
1025 if payment_secret_count > 1 {
1026 return Err(SemanticError::MultiplePaymentSecrets);
1029 // "A writer MUST set an s field if and only if the payment_secret feature is set."
1030 let has_payment_secret = payment_secret_count == 1;
1031 let features = self.tagged_fields().find(|&tf| match *tf {
1032 TaggedField::Features(_) => true,
1036 None if has_payment_secret => Err(SemanticError::InvalidFeatures),
1038 Some(TaggedField::Features(features)) => {
1039 if features.supports_payment_secret() && has_payment_secret {
1041 } else if has_payment_secret {
1042 Err(SemanticError::InvalidFeatures)
1043 } else if features.supports_payment_secret() {
1044 Err(SemanticError::InvalidFeatures)
1049 Some(_) => unreachable!(),
1053 /// Check that the invoice is signed correctly and that key recovery works
1054 pub fn check_signature(&self) -> Result<(), SemanticError> {
1055 match self.signed_invoice.recover_payee_pub_key() {
1056 Err(secp256k1::Error::InvalidRecoveryId) =>
1057 return Err(SemanticError::InvalidRecoveryId),
1058 Err(_) => panic!("no other error may occur"),
1062 if !self.signed_invoice.check_signature() {
1063 return Err(SemanticError::InvalidSignature);
1069 /// Constructs an `Invoice` from a `SignedInvoice` by checking all its invariants.
1071 /// use lightning_invoice::*;
1073 /// let invoice = "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp\
1074 /// l2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d7\
1075 /// 3gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ec\
1076 /// ky03ylcqca784w";
1078 /// let signed = invoice.parse::<SignedRawInvoice>().unwrap();
1080 /// assert!(Invoice::from_signed(signed).is_ok());
1082 pub fn from_signed(signed_invoice: SignedRawInvoice) -> Result<Self, SemanticError> {
1083 let invoice = Invoice {
1084 signed_invoice: signed_invoice,
1086 invoice.check_field_counts()?;
1087 invoice.check_feature_bits()?;
1088 invoice.check_signature()?;
1093 /// Returns the `Invoice`'s timestamp (should equal it's creation time)
1094 pub fn timestamp(&self) -> &SystemTime {
1095 self.signed_invoice.raw_invoice().data.timestamp.as_time()
1098 /// Returns an iterator over all tagged fields of this Invoice.
1100 /// (C-not exported) As there is not yet a manual mapping for a FilterMap
1101 pub fn tagged_fields(&self)
1102 -> FilterMap<Iter<RawTaggedField>, fn(&RawTaggedField) -> Option<&TaggedField>> {
1103 self.signed_invoice.raw_invoice().known_tagged_fields()
1106 /// Returns the hash to which we will receive the preimage on completion of the payment
1107 pub fn payment_hash(&self) -> &sha256::Hash {
1108 &self.signed_invoice.payment_hash().expect("checked by constructor").0
1111 /// Return the description or a hash of it for longer ones
1113 /// (C-not exported) because we don't yet export InvoiceDescription
1114 pub fn description(&self) -> InvoiceDescription {
1115 if let Some(ref direct) = self.signed_invoice.description() {
1116 return InvoiceDescription::Direct(direct);
1117 } else if let Some(ref hash) = self.signed_invoice.description_hash() {
1118 return InvoiceDescription::Hash(hash);
1120 unreachable!("ensured by constructor");
1123 /// Get the payee's public key if one was included in the invoice
1124 pub fn payee_pub_key(&self) -> Option<&PublicKey> {
1125 self.signed_invoice.payee_pub_key().map(|x| &x.0)
1128 /// Get the payment secret if one was included in the invoice
1129 pub fn payment_secret(&self) -> Option<&PaymentSecret> {
1130 self.signed_invoice.payment_secret()
1133 /// Get the invoice features if they were included in the invoice
1134 pub fn features(&self) -> Option<&InvoiceFeatures> {
1135 self.signed_invoice.features()
1138 /// Recover the payee's public key (only to be used if none was included in the invoice)
1139 pub fn recover_payee_pub_key(&self) -> PublicKey {
1140 self.signed_invoice.recover_payee_pub_key().expect("was checked by constructor").0
1143 /// Returns the invoice's expiry time, if present, otherwise [`DEFAULT_EXPIRY_TIME`].
1144 pub fn expiry_time(&self) -> Duration {
1145 self.signed_invoice.expiry_time()
1147 .unwrap_or(Duration::from_secs(DEFAULT_EXPIRY_TIME))
1150 /// Returns the invoice's `min_final_cltv_expiry` time, if present, otherwise
1151 /// [`DEFAULT_MIN_FINAL_CLTV_EXPIRY`].
1152 pub fn min_final_cltv_expiry(&self) -> u64 {
1153 self.signed_invoice.min_final_cltv_expiry()
1155 .unwrap_or(DEFAULT_MIN_FINAL_CLTV_EXPIRY)
1158 /// Returns a list of all fallback addresses
1160 /// (C-not exported) as we don't support Vec<&NonOpaqueType>
1161 pub fn fallbacks(&self) -> Vec<&Fallback> {
1162 self.signed_invoice.fallbacks()
1165 /// Returns a list of all routes included in the invoice
1166 pub fn private_routes(&self) -> Vec<&PrivateRoute> {
1167 self.signed_invoice.private_routes()
1170 /// Returns a list of all routes included in the invoice as the underlying hints
1171 pub fn route_hints(&self) -> Vec<&RouteHint> {
1173 self.signed_invoice.known_tagged_fields(), TaggedField::PrivateRoute(ref x), x
1174 ).map(|route| &**route).collect()
1177 /// Returns the currency for which the invoice was issued
1178 pub fn currency(&self) -> Currency {
1179 self.signed_invoice.currency()
1182 /// Returns the amount if specified in the invoice as pico <currency>.
1183 pub fn amount_pico_btc(&self) -> Option<u64> {
1184 self.signed_invoice.amount_pico_btc()
1188 impl From<TaggedField> for RawTaggedField {
1189 fn from(tf: TaggedField) -> Self {
1190 RawTaggedField::KnownSemantics(tf)
1195 /// Numeric representation of the field's tag
1196 pub fn tag(&self) -> u5 {
1197 let tag = match *self {
1198 TaggedField::PaymentHash(_) => constants::TAG_PAYMENT_HASH,
1199 TaggedField::Description(_) => constants::TAG_DESCRIPTION,
1200 TaggedField::PayeePubKey(_) => constants::TAG_PAYEE_PUB_KEY,
1201 TaggedField::DescriptionHash(_) => constants::TAG_DESCRIPTION_HASH,
1202 TaggedField::ExpiryTime(_) => constants::TAG_EXPIRY_TIME,
1203 TaggedField::MinFinalCltvExpiry(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY,
1204 TaggedField::Fallback(_) => constants::TAG_FALLBACK,
1205 TaggedField::PrivateRoute(_) => constants::TAG_PRIVATE_ROUTE,
1206 TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
1207 TaggedField::Features(_) => constants::TAG_FEATURES,
1210 u5::try_from_u8(tag).expect("all tags defined are <32")
1216 /// Creates a new `Description` if `description` is at most 1023 __bytes__ long,
1217 /// returns `CreationError::DescriptionTooLong` otherwise
1219 /// Please note that single characters may use more than one byte due to UTF8 encoding.
1220 pub fn new(description: String) -> Result<Description, CreationError> {
1221 if description.len() > 639 {
1222 Err(CreationError::DescriptionTooLong)
1224 Ok(Description(description))
1228 /// Returns the underlying description `String`
1229 pub fn into_inner(self) -> String {
1234 impl Into<String> for Description {
1235 fn into(self) -> String {
1240 impl Deref for Description {
1243 fn deref(&self) -> &str {
1248 impl From<PublicKey> for PayeePubKey {
1249 fn from(pk: PublicKey) -> Self {
1254 impl Deref for PayeePubKey {
1255 type Target = PublicKey;
1257 fn deref(&self) -> &PublicKey {
1263 /// Construct an `ExpiryTime` from seconds. If there exists a `PositiveTimestamp` which would
1264 /// overflow on adding the `EpiryTime` to it then this function will return a
1265 /// `CreationError::ExpiryTimeOutOfBounds`.
1266 pub fn from_seconds(seconds: u64) -> Result<ExpiryTime, CreationError> {
1267 if seconds <= MAX_EXPIRY_TIME {
1268 Ok(ExpiryTime(Duration::from_secs(seconds)))
1270 Err(CreationError::ExpiryTimeOutOfBounds)
1274 /// Construct an `ExpiryTime` from a `Duration`. If there exists a `PositiveTimestamp` which
1275 /// would overflow on adding the `EpiryTime` to it then this function will return a
1276 /// `CreationError::ExpiryTimeOutOfBounds`.
1277 pub fn from_duration(duration: Duration) -> Result<ExpiryTime, CreationError> {
1278 if duration.as_secs() <= MAX_EXPIRY_TIME {
1279 Ok(ExpiryTime(duration))
1281 Err(CreationError::ExpiryTimeOutOfBounds)
1285 /// Returns the expiry time in seconds
1286 pub fn as_seconds(&self) -> u64 {
1290 /// Returns a reference to the underlying `Duration` (=expiry time)
1291 pub fn as_duration(&self) -> &Duration {
1297 /// Creates a new (partial) route from a list of hops
1298 pub fn new(hops: RouteHint) -> Result<PrivateRoute, CreationError> {
1299 if hops.0.len() <= 12 {
1300 Ok(PrivateRoute(hops))
1302 Err(CreationError::RouteTooLong)
1306 /// Returns the underlying list of hops
1307 pub fn into_inner(self) -> RouteHint {
1312 impl Into<RouteHint> for PrivateRoute {
1313 fn into(self) -> RouteHint {
1318 impl Deref for PrivateRoute {
1319 type Target = RouteHint;
1321 fn deref(&self) -> &RouteHint {
1326 impl Deref for InvoiceSignature {
1327 type Target = RecoverableSignature;
1329 fn deref(&self) -> &RecoverableSignature {
1334 impl Deref for SignedRawInvoice {
1335 type Target = RawInvoice;
1337 fn deref(&self) -> &RawInvoice {
1342 /// Errors that may occur when constructing a new `RawInvoice` or `Invoice`
1343 #[derive(Eq, PartialEq, Debug, Clone)]
1344 pub enum CreationError {
1345 /// The supplied description string was longer than 639 __bytes__ (see [`Description::new(…)`](./struct.Description.html#method.new))
1348 /// The specified route has too many hops and can't be encoded
1351 /// The unix timestamp of the supplied date is <0 or can't be represented as `SystemTime`
1352 TimestampOutOfBounds,
1354 /// The supplied expiry time could cause an overflow if added to a `PositiveTimestamp`
1355 ExpiryTimeOutOfBounds,
1358 impl Display for CreationError {
1359 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1361 CreationError::DescriptionTooLong => f.write_str("The supplied description string was longer than 639 bytes"),
1362 CreationError::RouteTooLong => f.write_str("The specified route has too many hops and can't be encoded"),
1363 CreationError::TimestampOutOfBounds => f.write_str("The unix timestamp of the supplied date is <0 or can't be represented as `SystemTime`"),
1364 CreationError::ExpiryTimeOutOfBounds => f.write_str("The supplied expiry time could cause an overflow if added to a `PositiveTimestamp`"),
1369 impl std::error::Error for CreationError { }
1371 /// Errors that may occur when converting a `RawInvoice` to an `Invoice`. They relate to the
1372 /// requirements sections in BOLT #11
1373 #[derive(Eq, PartialEq, Debug, Clone)]
1374 pub enum SemanticError {
1375 /// The invoice is missing the mandatory payment hash
1378 /// The invoice has multiple payment hashes which isn't allowed
1379 MultiplePaymentHashes,
1381 /// No description or description hash are part of the invoice
1384 /// The invoice contains multiple descriptions and/or description hashes which isn't allowed
1385 MultipleDescriptions,
1387 /// The invoice contains multiple payment secrets
1388 MultiplePaymentSecrets,
1390 /// The invoice's features are invalid
1393 /// The recovery id doesn't fit the signature/pub key
1396 /// The invoice's signature is invalid
1400 impl Display for SemanticError {
1401 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1403 SemanticError::NoPaymentHash => f.write_str("The invoice is missing the mandatory payment hash"),
1404 SemanticError::MultiplePaymentHashes => f.write_str("The invoice has multiple payment hashes which isn't allowed"),
1405 SemanticError::NoDescription => f.write_str("No description or description hash are part of the invoice"),
1406 SemanticError::MultipleDescriptions => f.write_str("The invoice contains multiple descriptions and/or description hashes which isn't allowed"),
1407 SemanticError::MultiplePaymentSecrets => f.write_str("The invoice contains multiple payment secrets"),
1408 SemanticError::InvalidFeatures => f.write_str("The invoice's features are invalid"),
1409 SemanticError::InvalidRecoveryId => f.write_str("The recovery id doesn't fit the signature/pub key"),
1410 SemanticError::InvalidSignature => f.write_str("The invoice's signature is invalid"),
1415 impl std::error::Error for SemanticError { }
1417 /// When signing using a fallible method either an user-supplied `SignError` or a `CreationError`
1419 #[derive(Eq, PartialEq, Debug, Clone)]
1420 pub enum SignOrCreationError<S = ()> {
1421 /// An error occurred during signing
1424 /// An error occurred while building the transaction
1425 CreationError(CreationError),
1428 impl<S> Display for SignOrCreationError<S> {
1429 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1431 SignOrCreationError::SignError(_) => f.write_str("An error occurred during signing"),
1432 SignOrCreationError::CreationError(err) => err.fmt(f),
1439 use bitcoin_hashes::hex::FromHex;
1440 use bitcoin_hashes::sha256;
1443 fn test_system_time_bounds_assumptions() {
1447 ::PositiveTimestamp::from_unix_timestamp(::SYSTEM_TIME_MAX_UNIX_TIMESTAMP + 1),
1448 Err(::CreationError::TimestampOutOfBounds)
1452 ::ExpiryTime::from_seconds(::MAX_EXPIRY_TIME + 1),
1453 Err(::CreationError::ExpiryTimeOutOfBounds)
1458 fn test_calc_invoice_hash() {
1459 use ::{RawInvoice, RawHrp, RawDataPart, Currency, PositiveTimestamp};
1460 use ::TaggedField::*;
1462 let invoice = RawInvoice {
1464 currency: Currency::Bitcoin,
1469 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1470 tagged_fields: vec![
1471 PaymentHash(::Sha256(sha256::Hash::from_hex(
1472 "0001020304050607080900010203040506070809000102030405060708090102"
1473 ).unwrap())).into(),
1474 Description(::Description::new(
1475 "Please consider supporting this project".to_owned()
1481 let expected_hash = [
1482 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27, 0x7b, 0x1d,
1483 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7, 0x83, 0x5d, 0xb2, 0xec,
1484 0xd5, 0x18, 0xe1, 0xc9
1487 assert_eq!(invoice.hash(), expected_hash)
1491 fn test_check_signature() {
1493 use secp256k1::Secp256k1;
1494 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
1495 use secp256k1::key::{SecretKey, PublicKey};
1496 use {SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256,
1499 let invoice = SignedRawInvoice {
1500 raw_invoice: RawInvoice {
1502 currency: Currency::Bitcoin,
1507 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1508 tagged_fields: vec ! [
1509 PaymentHash(Sha256(sha256::Hash::from_hex(
1510 "0001020304050607080900010203040506070809000102030405060708090102"
1511 ).unwrap())).into(),
1514 "Please consider supporting this project".to_owned()
1521 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27,
1522 0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
1523 0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
1525 signature: InvoiceSignature(RecoverableSignature::from_compact(
1527 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
1528 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
1529 0x4e, 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f,
1530 0x42, 0x5f, 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad,
1531 0x0d, 0x6e, 0x35, 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9,
1532 0xaa, 0xb1, 0x5e, 0x57, 0x38, 0xb1, 0x1f, 0x12, 0x7f
1534 RecoveryId::from_i32(0).unwrap()
1538 assert!(invoice.check_signature());
1540 let private_key = SecretKey::from_slice(
1542 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
1543 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
1544 0x3b, 0x2d, 0xb7, 0x34
1547 let public_key = PublicKey::from_secret_key(&Secp256k1::new(), &private_key);
1549 assert_eq!(invoice.recover_payee_pub_key(), Ok(::PayeePubKey(public_key)));
1551 let (raw_invoice, _, _) = invoice.into_parts();
1552 let new_signed = raw_invoice.sign::<_, ()>(|hash| {
1553 Ok(Secp256k1::new().sign_recoverable(hash, &private_key))
1556 assert!(new_signed.check_signature());
1560 fn test_check_feature_bits() {
1562 use lightning::ln::features::InvoiceFeatures;
1563 use secp256k1::Secp256k1;
1564 use secp256k1::key::SecretKey;
1565 use {RawInvoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp, Invoice,
1568 let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
1569 let payment_secret = lightning::ln::PaymentSecret([21; 32]);
1570 let invoice_template = RawInvoice {
1572 currency: Currency::Bitcoin,
1577 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1578 tagged_fields: vec ! [
1579 PaymentHash(Sha256(sha256::Hash::from_hex(
1580 "0001020304050607080900010203040506070809000102030405060708090102"
1581 ).unwrap())).into(),
1584 "Please consider supporting this project".to_owned()
1593 let mut invoice = invoice_template.clone();
1594 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1595 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1597 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures));
1599 // Missing feature bits
1601 let mut invoice = invoice_template.clone();
1602 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1603 invoice.data.tagged_fields.push(Features(InvoiceFeatures::empty()).into());
1604 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1606 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures));
1608 // Including payment secret and feature bits
1610 let mut invoice = invoice_template.clone();
1611 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1612 invoice.data.tagged_fields.push(Features(InvoiceFeatures::known()).into());
1613 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1615 assert!(Invoice::from_signed(invoice).is_ok());
1617 // No payment secret or features
1619 let invoice = invoice_template.clone();
1620 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1622 assert!(Invoice::from_signed(invoice).is_ok());
1624 // No payment secret or feature bits
1626 let mut invoice = invoice_template.clone();
1627 invoice.data.tagged_fields.push(Features(InvoiceFeatures::empty()).into());
1628 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1630 assert!(Invoice::from_signed(invoice).is_ok());
1632 // Missing payment secret
1634 let mut invoice = invoice_template.clone();
1635 invoice.data.tagged_fields.push(Features(InvoiceFeatures::known()).into());
1636 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1638 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures));
1640 // Multiple payment secrets
1642 let mut invoice = invoice_template.clone();
1643 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1644 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1645 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1647 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::MultiplePaymentSecrets));
1651 fn test_builder_amount() {
1654 let builder = InvoiceBuilder::new(Currency::Bitcoin)
1655 .description("Test".into())
1656 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1657 .current_timestamp();
1659 let invoice = builder.clone()
1660 .amount_pico_btc(15000)
1664 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Nano));
1665 assert_eq!(invoice.hrp.raw_amount, Some(15));
1668 let invoice = builder.clone()
1669 .amount_pico_btc(1500)
1673 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Pico));
1674 assert_eq!(invoice.hrp.raw_amount, Some(1500));
1678 fn test_builder_fail() {
1680 use lightning::routing::router::RouteHintHop;
1681 use std::iter::FromIterator;
1682 use secp256k1::key::PublicKey;
1684 let builder = InvoiceBuilder::new(Currency::Bitcoin)
1685 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1686 .current_timestamp()
1687 .min_final_cltv_expiry(144);
1689 let too_long_string = String::from_iter(
1690 (0..1024).map(|_| '?')
1693 let long_desc_res = builder.clone()
1694 .description(too_long_string)
1696 assert_eq!(long_desc_res, Err(CreationError::DescriptionTooLong));
1698 let route_hop = RouteHintHop {
1699 src_node_id: PublicKey::from_slice(
1701 0x03, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4,
1702 0x3c, 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a,
1703 0x95, 0xc3, 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
1706 short_channel_id: 0,
1709 proportional_millionths: 0,
1711 cltv_expiry_delta: 0,
1712 htlc_minimum_msat: None,
1713 htlc_maximum_msat: None,
1715 let too_long_route = RouteHint(vec![route_hop; 13]);
1716 let long_route_res = builder.clone()
1717 .description("Test".into())
1718 .private_route(too_long_route)
1720 assert_eq!(long_route_res, Err(CreationError::RouteTooLong));
1722 let sign_error_res = builder.clone()
1723 .description("Test".into())
1724 .try_build_signed(|_| {
1725 Err("ImaginaryError")
1727 assert_eq!(sign_error_res, Err(SignOrCreationError::SignError("ImaginaryError")));
1731 fn test_builder_ok() {
1733 use lightning::routing::router::RouteHintHop;
1734 use secp256k1::Secp256k1;
1735 use secp256k1::key::{SecretKey, PublicKey};
1736 use std::time::{UNIX_EPOCH, Duration};
1738 let secp_ctx = Secp256k1::new();
1740 let private_key = SecretKey::from_slice(
1742 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
1743 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
1744 0x3b, 0x2d, 0xb7, 0x34
1747 let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key);
1749 let route_1 = RouteHint(vec![
1751 src_node_id: public_key.clone(),
1752 short_channel_id: de::parse_int_be(&[123; 8], 256).expect("short chan ID slice too big?"),
1755 proportional_millionths: 1,
1757 cltv_expiry_delta: 145,
1758 htlc_minimum_msat: None,
1759 htlc_maximum_msat: None,
1762 src_node_id: public_key.clone(),
1763 short_channel_id: de::parse_int_be(&[42; 8], 256).expect("short chan ID slice too big?"),
1766 proportional_millionths: 2,
1768 cltv_expiry_delta: 146,
1769 htlc_minimum_msat: None,
1770 htlc_maximum_msat: None,
1774 let route_2 = RouteHint(vec![
1776 src_node_id: public_key.clone(),
1777 short_channel_id: 0,
1780 proportional_millionths: 3,
1782 cltv_expiry_delta: 147,
1783 htlc_minimum_msat: None,
1784 htlc_maximum_msat: None,
1787 src_node_id: public_key.clone(),
1788 short_channel_id: de::parse_int_be(&[1; 8], 256).expect("short chan ID slice too big?"),
1791 proportional_millionths: 4,
1793 cltv_expiry_delta: 148,
1794 htlc_minimum_msat: None,
1795 htlc_maximum_msat: None,
1799 let builder = InvoiceBuilder::new(Currency::BitcoinTestnet)
1800 .amount_pico_btc(123)
1801 .timestamp(UNIX_EPOCH + Duration::from_secs(1234567))
1802 .payee_pub_key(public_key.clone())
1803 .expiry_time(Duration::from_secs(54321))
1804 .min_final_cltv_expiry(144)
1805 .fallback(Fallback::PubKeyHash([0;20]))
1806 .private_route(route_1.clone())
1807 .private_route(route_2.clone())
1808 .description_hash(sha256::Hash::from_slice(&[3;32][..]).unwrap())
1809 .payment_hash(sha256::Hash::from_slice(&[21;32][..]).unwrap())
1810 .payment_secret(PaymentSecret([42; 32]))
1813 let invoice = builder.clone().build_signed(|hash| {
1814 secp_ctx.sign_recoverable(hash, &private_key)
1817 assert!(invoice.check_signature().is_ok());
1818 assert_eq!(invoice.tagged_fields().count(), 10);
1820 assert_eq!(invoice.amount_pico_btc(), Some(123));
1821 assert_eq!(invoice.currency(), Currency::BitcoinTestnet);
1823 invoice.timestamp().duration_since(UNIX_EPOCH).unwrap().as_secs(),
1826 assert_eq!(invoice.payee_pub_key(), Some(&public_key));
1827 assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
1828 assert_eq!(invoice.min_final_cltv_expiry(), 144);
1829 assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash([0;20])]);
1830 assert_eq!(invoice.private_routes(), vec![&PrivateRoute(route_1), &PrivateRoute(route_2)]);
1832 invoice.description(),
1833 InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap()))
1835 assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&[21;32][..]).unwrap());
1836 assert_eq!(invoice.payment_secret(), Some(&PaymentSecret([42; 32])));
1837 assert_eq!(invoice.features(), Some(&InvoiceFeatures::known()));
1839 let raw_invoice = builder.build_raw().unwrap();
1840 assert_eq!(raw_invoice, *invoice.into_signed_raw().raw_invoice())
1844 fn test_default_values() {
1846 use secp256k1::Secp256k1;
1847 use secp256k1::key::SecretKey;
1849 let signed_invoice = InvoiceBuilder::new(Currency::Bitcoin)
1850 .description("Test".into())
1851 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1852 .current_timestamp()
1855 .sign::<_, ()>(|hash| {
1856 let privkey = SecretKey::from_slice(&[41; 32]).unwrap();
1857 let secp_ctx = Secp256k1::new();
1858 Ok(secp_ctx.sign_recoverable(hash, &privkey))
1861 let invoice = Invoice::from_signed(signed_invoice).unwrap();
1863 assert_eq!(invoice.min_final_cltv_expiry(), DEFAULT_MIN_FINAL_CLTV_EXPIRY);
1864 assert_eq!(invoice.expiry_time(), Duration::from_secs(DEFAULT_EXPIRY_TIME));