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::RouteHintHop;
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),
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 RouteHint(Vec<RouteHintHop>);
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_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 route(mut self, route: Vec<RouteHintHop>) -> Self {
513 match RouteHint::new(route) {
514 Ok(r) => self.tagged_fields.push(TaggedField::Route(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 routes(&self) -> Vec<&RouteHint> {
917 find_all_extract!(self.known_tagged_fields(), TaggedField::Route(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 routes(&self) -> Vec<&RouteHint> {
1167 self.signed_invoice.routes()
1170 /// Returns the currency for which the invoice was issued
1171 pub fn currency(&self) -> Currency {
1172 self.signed_invoice.currency()
1175 /// Returns the amount if specified in the invoice as pico <currency>.
1176 pub fn amount_pico_btc(&self) -> Option<u64> {
1177 self.signed_invoice.amount_pico_btc()
1181 impl From<TaggedField> for RawTaggedField {
1182 fn from(tf: TaggedField) -> Self {
1183 RawTaggedField::KnownSemantics(tf)
1188 /// Numeric representation of the field's tag
1189 pub fn tag(&self) -> u5 {
1190 let tag = match *self {
1191 TaggedField::PaymentHash(_) => constants::TAG_PAYMENT_HASH,
1192 TaggedField::Description(_) => constants::TAG_DESCRIPTION,
1193 TaggedField::PayeePubKey(_) => constants::TAG_PAYEE_PUB_KEY,
1194 TaggedField::DescriptionHash(_) => constants::TAG_DESCRIPTION_HASH,
1195 TaggedField::ExpiryTime(_) => constants::TAG_EXPIRY_TIME,
1196 TaggedField::MinFinalCltvExpiry(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY,
1197 TaggedField::Fallback(_) => constants::TAG_FALLBACK,
1198 TaggedField::Route(_) => constants::TAG_ROUTE,
1199 TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
1200 TaggedField::Features(_) => constants::TAG_FEATURES,
1203 u5::try_from_u8(tag).expect("all tags defined are <32")
1209 /// Creates a new `Description` if `description` is at most 1023 __bytes__ long,
1210 /// returns `CreationError::DescriptionTooLong` otherwise
1212 /// Please note that single characters may use more than one byte due to UTF8 encoding.
1213 pub fn new(description: String) -> Result<Description, CreationError> {
1214 if description.len() > 639 {
1215 Err(CreationError::DescriptionTooLong)
1217 Ok(Description(description))
1221 /// Returns the underlying description `String`
1222 pub fn into_inner(self) -> String {
1227 impl Into<String> for Description {
1228 fn into(self) -> String {
1233 impl Deref for Description {
1236 fn deref(&self) -> &str {
1241 impl From<PublicKey> for PayeePubKey {
1242 fn from(pk: PublicKey) -> Self {
1247 impl Deref for PayeePubKey {
1248 type Target = PublicKey;
1250 fn deref(&self) -> &PublicKey {
1256 /// Construct an `ExpiryTime` from seconds. If there exists a `PositiveTimestamp` which would
1257 /// overflow on adding the `EpiryTime` to it then this function will return a
1258 /// `CreationError::ExpiryTimeOutOfBounds`.
1259 pub fn from_seconds(seconds: u64) -> Result<ExpiryTime, CreationError> {
1260 if seconds <= MAX_EXPIRY_TIME {
1261 Ok(ExpiryTime(Duration::from_secs(seconds)))
1263 Err(CreationError::ExpiryTimeOutOfBounds)
1267 /// Construct an `ExpiryTime` from a `Duration`. If there exists a `PositiveTimestamp` which
1268 /// would overflow on adding the `EpiryTime` to it then this function will return a
1269 /// `CreationError::ExpiryTimeOutOfBounds`.
1270 pub fn from_duration(duration: Duration) -> Result<ExpiryTime, CreationError> {
1271 if duration.as_secs() <= MAX_EXPIRY_TIME {
1272 Ok(ExpiryTime(duration))
1274 Err(CreationError::ExpiryTimeOutOfBounds)
1278 /// Returns the expiry time in seconds
1279 pub fn as_seconds(&self) -> u64 {
1283 /// Returns a reference to the underlying `Duration` (=expiry time)
1284 pub fn as_duration(&self) -> &Duration {
1290 /// Create a new (partial) route from a list of hops
1291 pub fn new(hops: Vec<RouteHintHop>) -> Result<RouteHint, CreationError> {
1292 if hops.len() <= 12 {
1295 Err(CreationError::RouteTooLong)
1299 /// Returrn the underlying vector of hops
1300 pub fn into_inner(self) -> Vec<RouteHintHop> {
1305 impl Into<Vec<RouteHintHop>> for RouteHint {
1306 fn into(self) -> Vec<RouteHintHop> {
1311 impl Deref for RouteHint {
1312 type Target = Vec<RouteHintHop>;
1314 fn deref(&self) -> &Vec<RouteHintHop> {
1319 impl Deref for InvoiceSignature {
1320 type Target = RecoverableSignature;
1322 fn deref(&self) -> &RecoverableSignature {
1327 impl Deref for SignedRawInvoice {
1328 type Target = RawInvoice;
1330 fn deref(&self) -> &RawInvoice {
1335 /// Errors that may occur when constructing a new `RawInvoice` or `Invoice`
1336 #[derive(Eq, PartialEq, Debug, Clone)]
1337 pub enum CreationError {
1338 /// The supplied description string was longer than 639 __bytes__ (see [`Description::new(…)`](./struct.Description.html#method.new))
1341 /// The specified route has too many hops and can't be encoded
1344 /// The unix timestamp of the supplied date is <0 or can't be represented as `SystemTime`
1345 TimestampOutOfBounds,
1347 /// The supplied expiry time could cause an overflow if added to a `PositiveTimestamp`
1348 ExpiryTimeOutOfBounds,
1351 impl Display for CreationError {
1352 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1354 CreationError::DescriptionTooLong => f.write_str("The supplied description string was longer than 639 bytes"),
1355 CreationError::RouteTooLong => f.write_str("The specified route has too many hops and can't be encoded"),
1356 CreationError::TimestampOutOfBounds => f.write_str("The unix timestamp of the supplied date is <0 or can't be represented as `SystemTime`"),
1357 CreationError::ExpiryTimeOutOfBounds => f.write_str("The supplied expiry time could cause an overflow if added to a `PositiveTimestamp`"),
1362 impl std::error::Error for CreationError { }
1364 /// Errors that may occur when converting a `RawInvoice` to an `Invoice`. They relate to the
1365 /// requirements sections in BOLT #11
1366 #[derive(Eq, PartialEq, Debug, Clone)]
1367 pub enum SemanticError {
1368 /// The invoice is missing the mandatory payment hash
1371 /// The invoice has multiple payment hashes which isn't allowed
1372 MultiplePaymentHashes,
1374 /// No description or description hash are part of the invoice
1377 /// The invoice contains multiple descriptions and/or description hashes which isn't allowed
1378 MultipleDescriptions,
1380 /// The invoice contains multiple payment secrets
1381 MultiplePaymentSecrets,
1383 /// The invoice's features are invalid
1386 /// The recovery id doesn't fit the signature/pub key
1389 /// The invoice's signature is invalid
1393 impl Display for SemanticError {
1394 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1396 SemanticError::NoPaymentHash => f.write_str("The invoice is missing the mandatory payment hash"),
1397 SemanticError::MultiplePaymentHashes => f.write_str("The invoice has multiple payment hashes which isn't allowed"),
1398 SemanticError::NoDescription => f.write_str("No description or description hash are part of the invoice"),
1399 SemanticError::MultipleDescriptions => f.write_str("The invoice contains multiple descriptions and/or description hashes which isn't allowed"),
1400 SemanticError::MultiplePaymentSecrets => f.write_str("The invoice contains multiple payment secrets"),
1401 SemanticError::InvalidFeatures => f.write_str("The invoice's features are invalid"),
1402 SemanticError::InvalidRecoveryId => f.write_str("The recovery id doesn't fit the signature/pub key"),
1403 SemanticError::InvalidSignature => f.write_str("The invoice's signature is invalid"),
1408 impl std::error::Error for SemanticError { }
1410 /// When signing using a fallible method either an user-supplied `SignError` or a `CreationError`
1412 #[derive(Eq, PartialEq, Debug, Clone)]
1413 pub enum SignOrCreationError<S = ()> {
1414 /// An error occurred during signing
1417 /// An error occurred while building the transaction
1418 CreationError(CreationError),
1421 impl<S> Display for SignOrCreationError<S> {
1422 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1424 SignOrCreationError::SignError(_) => f.write_str("An error occurred during signing"),
1425 SignOrCreationError::CreationError(err) => err.fmt(f),
1432 use bitcoin_hashes::hex::FromHex;
1433 use bitcoin_hashes::sha256;
1436 fn test_system_time_bounds_assumptions() {
1440 ::PositiveTimestamp::from_unix_timestamp(::SYSTEM_TIME_MAX_UNIX_TIMESTAMP + 1),
1441 Err(::CreationError::TimestampOutOfBounds)
1445 ::ExpiryTime::from_seconds(::MAX_EXPIRY_TIME + 1),
1446 Err(::CreationError::ExpiryTimeOutOfBounds)
1451 fn test_calc_invoice_hash() {
1452 use ::{RawInvoice, RawHrp, RawDataPart, Currency, PositiveTimestamp};
1453 use ::TaggedField::*;
1455 let invoice = RawInvoice {
1457 currency: Currency::Bitcoin,
1462 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1463 tagged_fields: vec![
1464 PaymentHash(::Sha256(sha256::Hash::from_hex(
1465 "0001020304050607080900010203040506070809000102030405060708090102"
1466 ).unwrap())).into(),
1467 Description(::Description::new(
1468 "Please consider supporting this project".to_owned()
1474 let expected_hash = [
1475 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27, 0x7b, 0x1d,
1476 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7, 0x83, 0x5d, 0xb2, 0xec,
1477 0xd5, 0x18, 0xe1, 0xc9
1480 assert_eq!(invoice.hash(), expected_hash)
1484 fn test_check_signature() {
1486 use secp256k1::Secp256k1;
1487 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
1488 use secp256k1::key::{SecretKey, PublicKey};
1489 use {SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256,
1492 let invoice = SignedRawInvoice {
1493 raw_invoice: RawInvoice {
1495 currency: Currency::Bitcoin,
1500 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1501 tagged_fields: vec ! [
1502 PaymentHash(Sha256(sha256::Hash::from_hex(
1503 "0001020304050607080900010203040506070809000102030405060708090102"
1504 ).unwrap())).into(),
1507 "Please consider supporting this project".to_owned()
1514 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27,
1515 0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
1516 0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
1518 signature: InvoiceSignature(RecoverableSignature::from_compact(
1520 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
1521 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
1522 0x4e, 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f,
1523 0x42, 0x5f, 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad,
1524 0x0d, 0x6e, 0x35, 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9,
1525 0xaa, 0xb1, 0x5e, 0x57, 0x38, 0xb1, 0x1f, 0x12, 0x7f
1527 RecoveryId::from_i32(0).unwrap()
1531 assert!(invoice.check_signature());
1533 let private_key = SecretKey::from_slice(
1535 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
1536 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
1537 0x3b, 0x2d, 0xb7, 0x34
1540 let public_key = PublicKey::from_secret_key(&Secp256k1::new(), &private_key);
1542 assert_eq!(invoice.recover_payee_pub_key(), Ok(::PayeePubKey(public_key)));
1544 let (raw_invoice, _, _) = invoice.into_parts();
1545 let new_signed = raw_invoice.sign::<_, ()>(|hash| {
1546 Ok(Secp256k1::new().sign_recoverable(hash, &private_key))
1549 assert!(new_signed.check_signature());
1553 fn test_check_feature_bits() {
1555 use lightning::ln::features::InvoiceFeatures;
1556 use secp256k1::Secp256k1;
1557 use secp256k1::key::SecretKey;
1558 use {RawInvoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp, Invoice,
1561 let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
1562 let payment_secret = lightning::ln::PaymentSecret([21; 32]);
1563 let invoice_template = RawInvoice {
1565 currency: Currency::Bitcoin,
1570 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1571 tagged_fields: vec ! [
1572 PaymentHash(Sha256(sha256::Hash::from_hex(
1573 "0001020304050607080900010203040506070809000102030405060708090102"
1574 ).unwrap())).into(),
1577 "Please consider supporting this project".to_owned()
1586 let mut invoice = invoice_template.clone();
1587 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1588 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1590 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures));
1592 // Missing feature bits
1594 let mut invoice = invoice_template.clone();
1595 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1596 invoice.data.tagged_fields.push(Features(InvoiceFeatures::empty()).into());
1597 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1599 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures));
1601 // Including payment secret and feature bits
1603 let mut invoice = invoice_template.clone();
1604 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1605 invoice.data.tagged_fields.push(Features(InvoiceFeatures::known()).into());
1606 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1608 assert!(Invoice::from_signed(invoice).is_ok());
1610 // No payment secret or features
1612 let invoice = invoice_template.clone();
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 feature bits
1619 let mut invoice = invoice_template.clone();
1620 invoice.data.tagged_fields.push(Features(InvoiceFeatures::empty()).into());
1621 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1623 assert!(Invoice::from_signed(invoice).is_ok());
1625 // Missing payment secret
1627 let mut invoice = invoice_template.clone();
1628 invoice.data.tagged_fields.push(Features(InvoiceFeatures::known()).into());
1629 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1631 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures));
1633 // Multiple payment secrets
1635 let mut invoice = invoice_template.clone();
1636 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1637 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1638 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1640 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::MultiplePaymentSecrets));
1644 fn test_builder_amount() {
1647 let builder = InvoiceBuilder::new(Currency::Bitcoin)
1648 .description("Test".into())
1649 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1650 .current_timestamp();
1652 let invoice = builder.clone()
1653 .amount_pico_btc(15000)
1657 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Nano));
1658 assert_eq!(invoice.hrp.raw_amount, Some(15));
1661 let invoice = builder.clone()
1662 .amount_pico_btc(1500)
1666 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Pico));
1667 assert_eq!(invoice.hrp.raw_amount, Some(1500));
1671 fn test_builder_fail() {
1673 use std::iter::FromIterator;
1674 use secp256k1::key::PublicKey;
1676 let builder = InvoiceBuilder::new(Currency::Bitcoin)
1677 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1678 .current_timestamp()
1679 .min_final_cltv_expiry(144);
1681 let too_long_string = String::from_iter(
1682 (0..1024).map(|_| '?')
1685 let long_desc_res = builder.clone()
1686 .description(too_long_string)
1688 assert_eq!(long_desc_res, Err(CreationError::DescriptionTooLong));
1690 let route_hop = RouteHintHop {
1691 src_node_id: PublicKey::from_slice(
1693 0x03, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4,
1694 0x3c, 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a,
1695 0x95, 0xc3, 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
1698 short_channel_id: 0,
1701 proportional_millionths: 0,
1703 cltv_expiry_delta: 0,
1704 htlc_minimum_msat: None,
1705 htlc_maximum_msat: None,
1707 let too_long_route = vec![route_hop; 13];
1708 let long_route_res = builder.clone()
1709 .description("Test".into())
1710 .route(too_long_route)
1712 assert_eq!(long_route_res, Err(CreationError::RouteTooLong));
1714 let sign_error_res = builder.clone()
1715 .description("Test".into())
1716 .try_build_signed(|_| {
1717 Err("ImaginaryError")
1719 assert_eq!(sign_error_res, Err(SignOrCreationError::SignError("ImaginaryError")));
1723 fn test_builder_ok() {
1725 use secp256k1::Secp256k1;
1726 use secp256k1::key::{SecretKey, PublicKey};
1727 use std::time::{UNIX_EPOCH, Duration};
1729 let secp_ctx = Secp256k1::new();
1731 let private_key = SecretKey::from_slice(
1733 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
1734 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
1735 0x3b, 0x2d, 0xb7, 0x34
1738 let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key);
1742 src_node_id: public_key.clone(),
1743 short_channel_id: de::parse_int_be(&[123; 8], 256).expect("short chan ID slice too big?"),
1746 proportional_millionths: 1,
1748 cltv_expiry_delta: 145,
1749 htlc_minimum_msat: None,
1750 htlc_maximum_msat: None,
1753 src_node_id: public_key.clone(),
1754 short_channel_id: de::parse_int_be(&[42; 8], 256).expect("short chan ID slice too big?"),
1757 proportional_millionths: 2,
1759 cltv_expiry_delta: 146,
1760 htlc_minimum_msat: None,
1761 htlc_maximum_msat: None,
1767 src_node_id: public_key.clone(),
1768 short_channel_id: 0,
1771 proportional_millionths: 3,
1773 cltv_expiry_delta: 147,
1774 htlc_minimum_msat: None,
1775 htlc_maximum_msat: None,
1778 src_node_id: public_key.clone(),
1779 short_channel_id: de::parse_int_be(&[1; 8], 256).expect("short chan ID slice too big?"),
1782 proportional_millionths: 4,
1784 cltv_expiry_delta: 148,
1785 htlc_minimum_msat: None,
1786 htlc_maximum_msat: None,
1790 let builder = InvoiceBuilder::new(Currency::BitcoinTestnet)
1791 .amount_pico_btc(123)
1792 .timestamp(UNIX_EPOCH + Duration::from_secs(1234567))
1793 .payee_pub_key(public_key.clone())
1794 .expiry_time(Duration::from_secs(54321))
1795 .min_final_cltv_expiry(144)
1796 .fallback(Fallback::PubKeyHash([0;20]))
1797 .route(route_1.clone())
1798 .route(route_2.clone())
1799 .description_hash(sha256::Hash::from_slice(&[3;32][..]).unwrap())
1800 .payment_hash(sha256::Hash::from_slice(&[21;32][..]).unwrap())
1801 .payment_secret(PaymentSecret([42; 32]))
1804 let invoice = builder.clone().build_signed(|hash| {
1805 secp_ctx.sign_recoverable(hash, &private_key)
1808 assert!(invoice.check_signature().is_ok());
1809 assert_eq!(invoice.tagged_fields().count(), 10);
1811 assert_eq!(invoice.amount_pico_btc(), Some(123));
1812 assert_eq!(invoice.currency(), Currency::BitcoinTestnet);
1814 invoice.timestamp().duration_since(UNIX_EPOCH).unwrap().as_secs(),
1817 assert_eq!(invoice.payee_pub_key(), Some(&public_key));
1818 assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
1819 assert_eq!(invoice.min_final_cltv_expiry(), 144);
1820 assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash([0;20])]);
1821 assert_eq!(invoice.routes(), vec![&RouteHint(route_1), &RouteHint(route_2)]);
1823 invoice.description(),
1824 InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap()))
1826 assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&[21;32][..]).unwrap());
1827 assert_eq!(invoice.payment_secret(), Some(&PaymentSecret([42; 32])));
1828 assert_eq!(invoice.features(), Some(&InvoiceFeatures::known()));
1830 let raw_invoice = builder.build_raw().unwrap();
1831 assert_eq!(raw_invoice, *invoice.into_signed_raw().raw_invoice())
1835 fn test_default_values() {
1837 use secp256k1::Secp256k1;
1838 use secp256k1::key::SecretKey;
1840 let signed_invoice = InvoiceBuilder::new(Currency::Bitcoin)
1841 .description("Test".into())
1842 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1843 .current_timestamp()
1846 .sign::<_, ()>(|hash| {
1847 let privkey = SecretKey::from_slice(&[41; 32]).unwrap();
1848 let secp_ctx = Secp256k1::new();
1849 Ok(secp_ctx.sign_recoverable(hash, &privkey))
1852 let invoice = Invoice::from_signed(signed_invoice).unwrap();
1854 assert_eq!(invoice.min_final_cltv_expiry(), DEFAULT_MIN_FINAL_CLTV_EXPIRY);
1855 assert_eq!(invoice.expiry_time(), Duration::from_secs(DEFAULT_EXPIRY_TIME));