2 #![deny(non_upper_case_globals)]
3 #![deny(non_camel_case_types)]
4 #![deny(non_snake_case)]
7 #![cfg_attr(feature = "strict", deny(warnings))]
9 //! This crate provides data structures to represent
10 //! [lightning BOLT11](https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md)
11 //! invoices and functions to create, encode and decode these. If you just want to use the standard
12 //! en-/decoding functionality this should get you started:
14 //! * For parsing use `str::parse::<Invoice>(&self)` (see the docs of `impl FromStr for Invoice`)
15 //! * For constructing invoices use the `InvoiceBuilder`
16 //! * For serializing invoices use the `Display`/`ToString` traits
20 extern crate bitcoin_hashes;
21 extern crate lightning;
22 extern crate num_traits;
23 extern crate secp256k1;
26 use bitcoin_hashes::Hash;
27 use bitcoin_hashes::sha256;
28 use lightning::ln::PaymentSecret;
29 use lightning::ln::features::InvoiceFeatures;
30 #[cfg(any(doc, test))]
31 use lightning::routing::network_graph::RoutingFees;
32 use lightning::routing::router::RouteHintHop;
34 use secp256k1::key::PublicKey;
35 use secp256k1::{Message, Secp256k1};
36 use secp256k1::recovery::RecoverableSignature;
38 use std::fmt::{Display, Formatter, self};
39 use std::iter::FilterMap;
42 use std::time::{SystemTime, Duration, UNIX_EPOCH};
48 pub use de::{ParseError, ParseOrSemanticError};
50 // TODO: fix before 2037 (see rust PR #55527)
51 /// Defines the maximum UNIX timestamp that can be represented as `SystemTime`. This is checked by
52 /// one of the unit tests, please run them.
53 const SYSTEM_TIME_MAX_UNIX_TIMESTAMP: u64 = std::i32::MAX as u64;
55 /// Allow the expiry time to be up to one year. Since this reduces the range of possible timestamps
56 /// it should be rather low as long as we still have to support 32bit time representations
57 const MAX_EXPIRY_TIME: u64 = 60 * 60 * 24 * 356;
59 /// This function is used as a static assert for the size of `SystemTime`. If the crate fails to
60 /// compile due to it this indicates that your system uses unexpected bounds for `SystemTime`. You
61 /// can remove this functions and run the test `test_system_time_bounds_assumptions`. In any case,
62 /// please open an issue. If all tests pass you should be able to use this library safely by just
63 /// removing this function till we patch it accordingly.
64 fn __system_time_size_check() {
65 // Use 2 * sizeof(u64) as expected size since the expected underlying implementation is storing
66 // a `Duration` since `SystemTime::UNIX_EPOCH`.
67 unsafe { std::mem::transmute_copy::<SystemTime, [u8; 16]>(&UNIX_EPOCH); }
71 /// **Call this function on startup to ensure that all assumptions about the platform are valid.**
73 /// Unfortunately we have to make assumptions about the upper bounds of the `SystemTime` type on
74 /// your platform which we can't fully verify at compile time and which isn't part of it's contract.
75 /// To our best knowledge our assumptions hold for all platforms officially supported by rust, but
76 /// since this check is fast we recommend to do it anyway.
78 /// If this function fails this is considered a bug. Please open an issue describing your
79 /// platform and stating your current system time.
82 /// If the check fails this function panics. By calling this function on startup you ensure that
83 /// this wont happen at an arbitrary later point in time.
84 pub fn check_platform() {
85 // The upper and lower bounds of `SystemTime` are not part of its public contract and are
86 // platform specific. That's why we have to test if our assumptions regarding these bounds
87 // hold on the target platform.
89 // If this test fails on your platform, please don't use the library and open an issue
90 // instead so we can resolve the situation. Currently this library is tested on:
92 let fail_date = UNIX_EPOCH + Duration::from_secs(SYSTEM_TIME_MAX_UNIX_TIMESTAMP);
93 let year = Duration::from_secs(60 * 60 * 24 * 365);
95 // Make sure that the library will keep working for another year
96 assert!(fail_date.duration_since(SystemTime::now()).unwrap() > year);
98 let max_ts = PositiveTimestamp::from_unix_timestamp(
99 SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME
101 let max_exp = ::ExpiryTime::from_seconds(MAX_EXPIRY_TIME).unwrap();
104 (*max_ts.as_time() + *max_exp.as_duration()).duration_since(UNIX_EPOCH).unwrap().as_secs(),
105 SYSTEM_TIME_MAX_UNIX_TIMESTAMP
110 /// Builder for `Invoice`s. It's the most convenient and advised way to use this library. It ensures
111 /// that only a semantically and syntactically correct Invoice can be built using it.
114 /// extern crate secp256k1;
115 /// extern crate lightning_invoice;
116 /// extern crate bitcoin_hashes;
118 /// use bitcoin_hashes::Hash;
119 /// use bitcoin_hashes::sha256;
121 /// use secp256k1::Secp256k1;
122 /// use secp256k1::key::SecretKey;
124 /// use lightning_invoice::{Currency, InvoiceBuilder};
127 /// let private_key = SecretKey::from_slice(
129 /// 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f,
130 /// 0xe2, 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04,
131 /// 0xa8, 0xca, 0x3b, 0x2d, 0xb7, 0x34
135 /// let payment_hash = sha256::Hash::from_slice(&[0; 32][..]).unwrap();
137 /// let invoice = InvoiceBuilder::new(Currency::Bitcoin)
138 /// .description("Coins pls!".into())
139 /// .payment_hash(payment_hash)
140 /// .current_timestamp()
141 /// .build_signed(|hash| {
142 /// Secp256k1::new().sign_recoverable(hash, &private_key)
146 /// assert!(invoice.to_string().starts_with("lnbc1"));
150 /// # Type parameters
151 /// The two parameters `D` and `H` signal if the builder already contains the correct amount of the
153 /// * `D`: exactly one `Description` or `DescriptionHash`
154 /// * `H`: exactly one `PaymentHash`
155 /// * `T`: the timestamp is set
157 /// (C-not exported) as we likely need to manually select one set of boolean type parameters.
158 #[derive(Eq, PartialEq, Debug, Clone)]
159 pub struct InvoiceBuilder<D: tb::Bool, H: tb::Bool, T: tb::Bool> {
162 si_prefix: Option<SiPrefix>,
163 timestamp: Option<PositiveTimestamp>,
164 tagged_fields: Vec<TaggedField>,
165 error: Option<CreationError>,
167 phantom_d: std::marker::PhantomData<D>,
168 phantom_h: std::marker::PhantomData<H>,
169 phantom_t: std::marker::PhantomData<T>,
172 /// Represents a syntactically and semantically correct lightning BOLT11 invoice.
174 /// There are three ways to construct an `Invoice`:
175 /// 1. using `InvoiceBuilder`
176 /// 2. using `Invoice::from_signed(SignedRawInvoice)`
177 /// 3. using `str::parse::<Invoice>(&str)`
178 #[derive(Eq, PartialEq, Debug, Clone)]
180 signed_invoice: SignedRawInvoice,
183 /// Represents the description of an invoice which has to be either a directly included string or
184 /// a hash of a description provided out of band.
186 /// (C-not exported) As we don't have a good way to map the reference lifetimes making this
187 /// practically impossible to use safely in languages like C.
188 #[derive(Eq, PartialEq, Debug, Clone)]
189 pub enum InvoiceDescription<'f> {
190 /// Reference to the directly supplied description in the invoice
191 Direct(&'f Description),
193 /// Reference to the description's hash included in the invoice
197 /// Represents a signed `RawInvoice` with cached hash. The signature is not checked and may be
201 /// The hash has to be either from the deserialized invoice or from the serialized `raw_invoice`.
202 #[derive(Eq, PartialEq, Debug, Clone)]
203 pub struct SignedRawInvoice {
204 /// The rawInvoice that the signature belongs to
205 raw_invoice: RawInvoice,
207 /// Hash of the `RawInvoice` that will be used to check the signature.
209 /// * if the `SignedRawInvoice` was deserialized the hash is of from the original encoded form,
210 /// since it's not guaranteed that encoding it again will lead to the same result since integers
211 /// could have been encoded with leading zeroes etc.
212 /// * if the `SignedRawInvoice` was constructed manually the hash will be the calculated hash
213 /// from the `RawInvoice`
216 /// signature of the payment request
217 signature: InvoiceSignature,
220 /// Represents an syntactically correct Invoice for a payment on the lightning network,
221 /// but without the signature information.
222 /// De- and encoding should not lead to information loss but may lead to different hashes.
224 /// For methods without docs see the corresponding methods in `Invoice`.
225 #[derive(Eq, PartialEq, Debug, Clone)]
226 pub struct RawInvoice {
227 /// human readable part
231 pub data: RawDataPart,
234 /// Data of the `RawInvoice` that is encoded in the human readable part
236 /// (C-not exported) As we don't yet support Option<Enum>
237 #[derive(Eq, PartialEq, Debug, Clone)]
239 /// The currency deferred from the 3rd and 4th character of the bech32 transaction
240 pub currency: Currency,
242 /// The amount that, multiplied by the SI prefix, has to be payed
243 pub raw_amount: Option<u64>,
245 /// SI prefix that gets multiplied with the `raw_amount`
246 pub si_prefix: Option<SiPrefix>,
249 /// Data of the `RawInvoice` that is encoded in the data part
250 #[derive(Eq, PartialEq, Debug, Clone)]
251 pub struct RawDataPart {
252 /// generation time of the invoice
253 pub timestamp: PositiveTimestamp,
255 /// tagged fields of the payment request
256 pub tagged_fields: Vec<RawTaggedField>,
259 /// A timestamp that refers to a date after 1 January 1970 which means its representation as UNIX
260 /// timestamp is positive.
263 /// The UNIX timestamp representing the stored time has to be positive and small enough so that
264 /// a `EpiryTime` can be added to it without an overflow.
265 #[derive(Eq, PartialEq, Debug, Clone)]
266 pub struct PositiveTimestamp(SystemTime);
268 /// SI prefixes for the human readable part
269 #[derive(Eq, PartialEq, Debug, Clone, Copy)]
282 /// Returns the multiplier to go from a BTC value to picoBTC implied by this SiPrefix.
283 /// This is effectively 10^12 * the prefix multiplier
284 pub fn multiplier(&self) -> u64 {
286 SiPrefix::Milli => 1_000_000_000,
287 SiPrefix::Micro => 1_000_000,
288 SiPrefix::Nano => 1_000,
293 /// Returns all enum variants of `SiPrefix` sorted in descending order of their associated
296 /// (C-not exported) As we don't yet support a slice of enums, and also because this function
297 /// isn't the most critical to expose.
298 pub fn values_desc() -> &'static [SiPrefix] {
300 static VALUES: [SiPrefix; 4] = [Milli, Micro, Nano, Pico];
305 /// Enum representing the crypto currencies (or networks) supported by this library
306 #[derive(Eq, PartialEq, Debug, Clone)]
317 /// Bitcoin simnet/signet
321 /// Tagged field which may have an unknown tag
322 #[derive(Eq, PartialEq, Debug, Clone)]
323 pub enum RawTaggedField {
324 /// Parsed tagged field with known tag
325 KnownSemantics(TaggedField),
326 /// tagged field which was not parsed due to an unknown tag or undefined field semantics
327 UnknownSemantics(Vec<u5>),
330 /// Tagged field with known tag
332 /// For descriptions of the enum values please refer to the enclosed type's docs.
333 #[allow(missing_docs)]
334 #[derive(Eq, PartialEq, Debug, Clone)]
335 pub enum TaggedField {
337 Description(Description),
338 PayeePubKey(PayeePubKey),
339 DescriptionHash(Sha256),
340 ExpiryTime(ExpiryTime),
341 MinFinalCltvExpiry(MinFinalCltvExpiry),
344 PaymentSecret(PaymentSecret),
345 Features(InvoiceFeatures),
349 #[derive(Eq, PartialEq, Debug, Clone)]
350 pub struct Sha256(pub sha256::Hash);
352 /// Description string
355 /// The description can be at most 639 __bytes__ long
356 #[derive(Eq, PartialEq, Debug, Clone)]
357 pub struct Description(String);
360 #[derive(Eq, PartialEq, Debug, Clone)]
361 pub struct PayeePubKey(pub PublicKey);
363 /// Positive duration that defines when (relatively to the timestamp) in the future the invoice
367 /// The number of seconds this expiry time represents has to be in the range
368 /// `0...(SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME)` to avoid overflows when adding it to a
370 #[derive(Eq, PartialEq, Debug, Clone)]
371 pub struct ExpiryTime(Duration);
373 /// `min_final_cltv_expiry` to use for the last HTLC in the route
374 #[derive(Eq, PartialEq, Debug, Clone)]
375 pub struct MinFinalCltvExpiry(pub u64);
377 // TODO: better types instead onf byte arrays
378 /// Fallback address in case no LN payment is possible
379 #[allow(missing_docs)]
380 #[derive(Eq, PartialEq, Debug, Clone)]
386 PubKeyHash([u8; 20]),
387 ScriptHash([u8; 20]),
390 /// Recoverable signature
391 #[derive(Eq, PartialEq, Debug, Clone)]
392 pub struct InvoiceSignature(pub RecoverableSignature);
394 /// Private routing information
397 /// The encoded route has to be <1024 5bit characters long (<=639 bytes or <=12 hops)
399 #[derive(Eq, PartialEq, Debug, Clone)]
400 pub struct RouteHint(Vec<RouteHintHop>);
402 /// Tag constants as specified in BOLT11
403 #[allow(missing_docs)]
405 pub const TAG_PAYMENT_HASH: u8 = 1;
406 pub const TAG_DESCRIPTION: u8 = 13;
407 pub const TAG_PAYEE_PUB_KEY: u8 = 19;
408 pub const TAG_DESCRIPTION_HASH: u8 = 23;
409 pub const TAG_EXPIRY_TIME: u8 = 6;
410 pub const TAG_MIN_FINAL_CLTV_EXPIRY: u8 = 24;
411 pub const TAG_FALLBACK: u8 = 9;
412 pub const TAG_ROUTE: u8 = 3;
413 pub const TAG_PAYMENT_SECRET: u8 = 16;
414 pub const TAG_FEATURES: u8 = 5;
417 impl InvoiceBuilder<tb::False, tb::False, tb::False> {
418 /// Construct new, empty `InvoiceBuilder`. All necessary fields have to be filled first before
419 /// `InvoiceBuilder::build(self)` becomes available.
420 pub fn new(currrency: Currency) -> Self {
426 tagged_fields: Vec::new(),
429 phantom_d: std::marker::PhantomData,
430 phantom_h: std::marker::PhantomData,
431 phantom_t: std::marker::PhantomData,
436 impl<D: tb::Bool, H: tb::Bool, T: tb::Bool> InvoiceBuilder<D, H, T> {
437 /// Helper function to set the completeness flags.
438 fn set_flags<DN: tb::Bool, HN: tb::Bool, TN: tb::Bool>(self) -> InvoiceBuilder<DN, HN, TN> {
439 InvoiceBuilder::<DN, HN, TN> {
440 currency: self.currency,
442 si_prefix: self.si_prefix,
443 timestamp: self.timestamp,
444 tagged_fields: self.tagged_fields,
447 phantom_d: std::marker::PhantomData,
448 phantom_h: std::marker::PhantomData,
449 phantom_t: std::marker::PhantomData,
453 /// Sets the amount in pico BTC. The optimal SI prefix is choosen automatically.
454 pub fn amount_pico_btc(mut self, amount: u64) -> Self {
455 let biggest_possible_si_prefix = SiPrefix::values_desc()
457 .find(|prefix| amount % prefix.multiplier() == 0)
458 .expect("Pico should always match");
459 self.amount = Some(amount / biggest_possible_si_prefix.multiplier());
460 self.si_prefix = Some(*biggest_possible_si_prefix);
464 /// Sets the payee's public key.
465 pub fn payee_pub_key(mut self, pub_key: PublicKey) -> Self {
466 self.tagged_fields.push(TaggedField::PayeePubKey(PayeePubKey(pub_key)));
470 /// Sets the payment secret
471 pub fn payment_secret(mut self, payment_secret: PaymentSecret) -> Self {
472 self.tagged_fields.push(TaggedField::PaymentSecret(payment_secret));
476 /// Sets the expiry time
477 pub fn expiry_time(mut self, expiry_time: Duration) -> Self {
478 match ExpiryTime::from_duration(expiry_time) {
479 Ok(t) => self.tagged_fields.push(TaggedField::ExpiryTime(t)),
480 Err(e) => self.error = Some(e),
485 /// Sets `min_final_cltv_expiry`.
486 pub fn min_final_cltv_expiry(mut self, min_final_cltv_expiry: u64) -> Self {
487 self.tagged_fields.push(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry(min_final_cltv_expiry)));
491 /// Adds a fallback address.
492 pub fn fallback(mut self, fallback: Fallback) -> Self {
493 self.tagged_fields.push(TaggedField::Fallback(fallback));
497 /// Adds a private route.
498 pub fn route(mut self, route: Vec<RouteHintHop>) -> Self {
499 match RouteHint::new(route) {
500 Ok(r) => self.tagged_fields.push(TaggedField::Route(r)),
501 Err(e) => self.error = Some(e),
506 /// Adds a features field which indicates the set of supported protocol extensions which the
507 /// origin node supports.
508 pub fn features(mut self, features: InvoiceFeatures) -> Self {
509 self.tagged_fields.push(TaggedField::Features(features));
514 impl<D: tb::Bool, H: tb::Bool> InvoiceBuilder<D, H, tb::True> {
515 /// Builds a `RawInvoice` if no `CreationError` occurred while construction any of the fields.
516 pub fn build_raw(self) -> Result<RawInvoice, CreationError> {
518 // If an error occurred at any time before, return it now
519 if let Some(e) = self.error {
524 currency: self.currency,
525 raw_amount: self.amount,
526 si_prefix: self.si_prefix,
529 let timestamp = self.timestamp.expect("ensured to be Some(t) by type T");
531 let tagged_fields = self.tagged_fields.into_iter().map(|tf| {
532 RawTaggedField::KnownSemantics(tf)
533 }).collect::<Vec<_>>();
535 let data = RawDataPart {
536 timestamp: timestamp,
537 tagged_fields: tagged_fields,
547 impl<H: tb::Bool, T: tb::Bool> InvoiceBuilder<tb::False, H, T> {
548 /// Set the description. This function is only available if no description (hash) was set.
549 pub fn description(mut self, description: String) -> InvoiceBuilder<tb::True, H, T> {
550 match Description::new(description) {
551 Ok(d) => self.tagged_fields.push(TaggedField::Description(d)),
552 Err(e) => self.error = Some(e),
557 /// Set the description hash. This function is only available if no description (hash) was set.
558 pub fn description_hash(mut self, description_hash: sha256::Hash) -> InvoiceBuilder<tb::True, H, T> {
559 self.tagged_fields.push(TaggedField::DescriptionHash(Sha256(description_hash)));
564 impl<D: tb::Bool, T: tb::Bool> InvoiceBuilder<D, tb::False, T> {
565 /// Set the payment hash. This function is only available if no payment hash was set.
566 pub fn payment_hash(mut self, hash: sha256::Hash) -> InvoiceBuilder<D, tb::True, T> {
567 self.tagged_fields.push(TaggedField::PaymentHash(Sha256(hash)));
572 impl<D: tb::Bool, H: tb::Bool> InvoiceBuilder<D, H, tb::False> {
573 /// Sets the timestamp.
574 pub fn timestamp(mut self, time: SystemTime) -> InvoiceBuilder<D, H, tb::True> {
575 match PositiveTimestamp::from_system_time(time) {
576 Ok(t) => self.timestamp = Some(t),
577 Err(e) => self.error = Some(e),
583 /// Sets the timestamp to the current UNIX timestamp.
584 pub fn current_timestamp(mut self) -> InvoiceBuilder<D, H, tb::True> {
585 let now = PositiveTimestamp::from_system_time(SystemTime::now());
586 self.timestamp = Some(now.expect("for the foreseeable future this shouldn't happen"));
591 impl InvoiceBuilder<tb::True, tb::True, tb::True> {
592 /// Builds and signs an invoice using the supplied `sign_function`. This function MAY NOT fail
593 /// and MUST produce a recoverable signature valid for the given hash and if applicable also for
594 /// the included payee public key.
595 pub fn build_signed<F>(self, sign_function: F) -> Result<Invoice, CreationError>
596 where F: FnOnce(&Message) -> RecoverableSignature
598 let invoice = self.try_build_signed::<_, ()>(|hash| {
599 Ok(sign_function(hash))
604 Err(SignOrCreationError::CreationError(e)) => Err(e),
605 Err(SignOrCreationError::SignError(())) => unreachable!(),
609 /// Builds and signs an invoice using the supplied `sign_function`. This function MAY fail with
610 /// an error of type `E` and MUST produce a recoverable signature valid for the given hash and
611 /// if applicable also for the included payee public key.
612 pub fn try_build_signed<F, E>(self, sign_function: F) -> Result<Invoice, SignOrCreationError<E>>
613 where F: FnOnce(&Message) -> Result<RecoverableSignature, E>
615 let raw = match self.build_raw() {
617 Err(e) => return Err(SignOrCreationError::CreationError(e)),
620 let signed = match raw.sign(sign_function) {
622 Err(e) => return Err(SignOrCreationError::SignError(e)),
625 let invoice = Invoice {
626 signed_invoice: signed,
629 invoice.check_field_counts().expect("should be ensured by type signature of builder");
636 impl SignedRawInvoice {
637 /// Disassembles the `SignedRawInvoice` into its three parts:
639 /// 2. hash of the raw invoice
641 pub fn into_parts(self) -> (RawInvoice, [u8; 32], InvoiceSignature) {
642 (self.raw_invoice, self.hash, self.signature)
645 /// The `RawInvoice` which was signed.
646 pub fn raw_invoice(&self) -> &RawInvoice {
650 /// The hash of the `RawInvoice` that was signed.
651 pub fn hash(&self) -> &[u8; 32] {
655 /// InvoiceSignature for the invoice.
656 pub fn signature(&self) -> &InvoiceSignature {
660 /// Recovers the public key used for signing the invoice from the recoverable signature.
661 pub fn recover_payee_pub_key(&self) -> Result<PayeePubKey, secp256k1::Error> {
662 let hash = Message::from_slice(&self.hash[..])
663 .expect("Hash is 32 bytes long, same as MESSAGE_SIZE");
665 Ok(PayeePubKey(Secp256k1::new().recover(
671 /// Checks if the signature is valid for the included payee public key or if none exists if it's
672 /// valid for the recovered signature (which should always be true?).
673 pub fn check_signature(&self) -> bool {
674 let included_pub_key = self.raw_invoice.payee_pub_key();
676 let mut recovered_pub_key = Option::None;
677 if recovered_pub_key.is_none() {
678 let recovered = match self.recover_payee_pub_key() {
680 Err(_) => return false,
682 recovered_pub_key = Some(recovered);
685 let pub_key = included_pub_key.or_else(|| recovered_pub_key.as_ref())
686 .expect("One is always present");
688 let hash = Message::from_slice(&self.hash[..])
689 .expect("Hash is 32 bytes long, same as MESSAGE_SIZE");
691 let secp_context = Secp256k1::new();
692 let verification_result = secp_context.verify(
694 &self.signature.to_standard(),
698 match verification_result {
705 /// Finds the first element of an enum stream of a given variant and extracts one member of the
706 /// variant. If no element was found `None` gets returned.
708 /// The following example would extract the first
717 /// let elements = vec![A(1), A(2), B(3), A(4)]
719 /// assert_eq!(find_extract!(elements.iter(), Enum::B(ref x), x), Some(3u16))
721 macro_rules! find_extract {
722 ($iter:expr, $enm:pat, $enm_var:ident) => {
723 $iter.filter_map(|tf| match *tf {
724 $enm => Some($enm_var),
730 #[allow(missing_docs)]
732 /// Construct the invoice's HRP and signatureless data into a preimage to be hashed.
733 pub(crate) fn construct_invoice_preimage(hrp_bytes: &[u8], data_without_signature: &[u5]) -> Vec<u8> {
734 use bech32::FromBase32;
736 let mut preimage = Vec::<u8>::from(hrp_bytes);
738 let mut data_part = Vec::from(data_without_signature);
739 let overhang = (data_part.len() * 5) % 8;
741 // add padding if data does not end at a byte boundary
742 data_part.push(u5::try_from_u8(0).unwrap());
744 // if overhang is in (1..3) we need to add u5(0) padding two times
746 data_part.push(u5::try_from_u8(0).unwrap());
750 preimage.extend_from_slice(&Vec::<u8>::from_base32(&data_part)
751 .expect("No padding error may occur due to appended zero above."));
755 /// Hash the HRP as bytes and signatureless data part.
756 fn hash_from_parts(hrp_bytes: &[u8], data_without_signature: &[u5]) -> [u8; 32] {
757 let preimage = RawInvoice::construct_invoice_preimage(hrp_bytes, data_without_signature);
758 let mut hash: [u8; 32] = Default::default();
759 hash.copy_from_slice(&sha256::Hash::hash(&preimage)[..]);
763 /// Calculate the hash of the encoded `RawInvoice`
764 pub fn hash(&self) -> [u8; 32] {
765 use bech32::ToBase32;
767 RawInvoice::hash_from_parts(
768 self.hrp.to_string().as_bytes(),
769 &self.data.to_base32()
773 /// Signs the invoice using the supplied `sign_function`. This function MAY fail with an error
774 /// of type `E`. Since the signature of a `SignedRawInvoice` is not required to be valid there
775 /// are no constraints regarding the validity of the produced signature.
777 /// (C-not exported) As we don't currently support passing function pointers into methods
779 pub fn sign<F, E>(self, sign_method: F) -> Result<SignedRawInvoice, E>
780 where F: FnOnce(&Message) -> Result<RecoverableSignature, E>
782 let raw_hash = self.hash();
783 let hash = Message::from_slice(&raw_hash[..])
784 .expect("Hash is 32 bytes long, same as MESSAGE_SIZE");
785 let signature = sign_method(&hash)?;
787 Ok(SignedRawInvoice {
790 signature: InvoiceSignature(signature),
794 /// Returns an iterator over all tagged fields with known semantics.
796 /// (C-not exported) As there is not yet a manual mapping for a FilterMap
797 pub fn known_tagged_fields(&self)
798 -> FilterMap<Iter<RawTaggedField>, fn(&RawTaggedField) -> Option<&TaggedField>>
800 // For 1.14.0 compatibility: closures' types can't be written an fn()->() in the
801 // function's type signature.
802 // TODO: refactor once impl Trait is available
803 fn match_raw(raw: &RawTaggedField) -> Option<&TaggedField> {
805 RawTaggedField::KnownSemantics(ref tf) => Some(tf),
810 self.data.tagged_fields.iter().filter_map(match_raw )
813 pub fn payment_hash(&self) -> Option<&Sha256> {
814 find_extract!(self.known_tagged_fields(), TaggedField::PaymentHash(ref x), x)
817 pub fn description(&self) -> Option<&Description> {
818 find_extract!(self.known_tagged_fields(), TaggedField::Description(ref x), x)
821 pub fn payee_pub_key(&self) -> Option<&PayeePubKey> {
822 find_extract!(self.known_tagged_fields(), TaggedField::PayeePubKey(ref x), x)
825 pub fn description_hash(&self) -> Option<&Sha256> {
826 find_extract!(self.known_tagged_fields(), TaggedField::DescriptionHash(ref x), x)
829 pub fn expiry_time(&self) -> Option<&ExpiryTime> {
830 find_extract!(self.known_tagged_fields(), TaggedField::ExpiryTime(ref x), x)
833 pub fn min_final_cltv_expiry(&self) -> Option<&MinFinalCltvExpiry> {
834 find_extract!(self.known_tagged_fields(), TaggedField::MinFinalCltvExpiry(ref x), x)
837 pub fn payment_secret(&self) -> Option<&PaymentSecret> {
838 find_extract!(self.known_tagged_fields(), TaggedField::PaymentSecret(ref x), x)
841 pub fn features(&self) -> Option<&InvoiceFeatures> {
842 find_extract!(self.known_tagged_fields(), TaggedField::Features(ref x), x)
845 /// (C-not exported) as we don't support Vec<&NonOpaqueType>
846 pub fn fallbacks(&self) -> Vec<&Fallback> {
847 self.known_tagged_fields().filter_map(|tf| match tf {
848 &TaggedField::Fallback(ref f) => Some(f),
850 }).collect::<Vec<&Fallback>>()
853 pub fn routes(&self) -> Vec<&RouteHint> {
854 self.known_tagged_fields().filter_map(|tf| match tf {
855 &TaggedField::Route(ref r) => Some(r),
857 }).collect::<Vec<&RouteHint>>()
860 pub fn amount_pico_btc(&self) -> Option<u64> {
861 self.hrp.raw_amount.map(|v| {
862 v * self.hrp.si_prefix.as_ref().map_or(1_000_000_000_000, |si| { si.multiplier() })
866 pub fn currency(&self) -> Currency {
867 self.hrp.currency.clone()
871 impl PositiveTimestamp {
872 /// Create a new `PositiveTimestamp` from a unix timestamp in the Range
873 /// `0...SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME`, otherwise return a
874 /// `CreationError::TimestampOutOfBounds`.
875 pub fn from_unix_timestamp(unix_seconds: u64) -> Result<Self, CreationError> {
876 if unix_seconds > SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME {
877 Err(CreationError::TimestampOutOfBounds)
879 Ok(PositiveTimestamp(UNIX_EPOCH + Duration::from_secs(unix_seconds)))
883 /// Create a new `PositiveTimestamp` from a `SystemTime` with a corresponding unix timestamp in
884 /// the Range `0...SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME`, otherwise return a
885 /// `CreationError::TimestampOutOfBounds`.
886 pub fn from_system_time(time: SystemTime) -> Result<Self, CreationError> {
888 .duration_since(UNIX_EPOCH)
889 .map(|t| t.as_secs() <= SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME)
892 Ok(PositiveTimestamp(time))
894 Err(CreationError::TimestampOutOfBounds)
898 /// Returns the UNIX timestamp representing the stored time
899 pub fn as_unix_timestamp(&self) -> u64 {
900 self.0.duration_since(UNIX_EPOCH)
901 .expect("ensured by type contract/constructors")
905 /// Returns a reference to the internal `SystemTime` time representation
906 pub fn as_time(&self) -> &SystemTime {
911 impl Into<SystemTime> for PositiveTimestamp {
912 fn into(self) -> SystemTime {
917 impl Deref for PositiveTimestamp {
918 type Target = SystemTime;
920 fn deref(&self) -> &Self::Target {
926 /// Transform the `Invoice` into it's unchecked version
927 pub fn into_signed_raw(self) -> SignedRawInvoice {
931 /// Check that all mandatory fields are present
932 fn check_field_counts(&self) -> Result<(), SemanticError> {
933 // "A writer MUST include exactly one p field […]."
934 let payment_hash_cnt = self.tagged_fields().filter(|&tf| match *tf {
935 TaggedField::PaymentHash(_) => true,
938 if payment_hash_cnt < 1 {
939 return Err(SemanticError::NoPaymentHash);
940 } else if payment_hash_cnt > 1 {
941 return Err(SemanticError::MultiplePaymentHashes);
944 // "A writer MUST include either exactly one d or exactly one h field."
945 let description_cnt = self.tagged_fields().filter(|&tf| match *tf {
946 TaggedField::Description(_) | TaggedField::DescriptionHash(_) => true,
949 if description_cnt < 1 {
950 return Err(SemanticError::NoDescription);
951 } else if description_cnt > 1 {
952 return Err(SemanticError::MultipleDescriptions);
958 /// Check that the invoice is signed correctly and that key recovery works
959 pub fn check_signature(&self) -> Result<(), SemanticError> {
960 match self.signed_invoice.recover_payee_pub_key() {
961 Err(secp256k1::Error::InvalidRecoveryId) =>
962 return Err(SemanticError::InvalidRecoveryId),
963 Err(_) => panic!("no other error may occur"),
967 if !self.signed_invoice.check_signature() {
968 return Err(SemanticError::InvalidSignature);
974 /// Constructs an `Invoice` from a `SignedInvoice` by checking all its invariants.
976 /// use lightning_invoice::*;
978 /// let invoice = "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp\
979 /// l2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d7\
980 /// 3gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ec\
983 /// let signed = invoice.parse::<SignedRawInvoice>().unwrap();
985 /// assert!(Invoice::from_signed(signed).is_ok());
987 pub fn from_signed(signed_invoice: SignedRawInvoice) -> Result<Self, SemanticError> {
988 let invoice = Invoice {
989 signed_invoice: signed_invoice,
991 invoice.check_field_counts()?;
992 invoice.check_signature()?;
997 /// Returns the `Invoice`'s timestamp (should equal it's creation time)
998 pub fn timestamp(&self) -> &SystemTime {
999 self.signed_invoice.raw_invoice().data.timestamp.as_time()
1002 /// Returns an iterator over all tagged fields of this Invoice.
1004 /// (C-not exported) As there is not yet a manual mapping for a FilterMap
1005 pub fn tagged_fields(&self)
1006 -> FilterMap<Iter<RawTaggedField>, fn(&RawTaggedField) -> Option<&TaggedField>> {
1007 self.signed_invoice.raw_invoice().known_tagged_fields()
1010 /// Returns the hash to which we will receive the preimage on completion of the payment
1011 pub fn payment_hash(&self) -> &sha256::Hash {
1012 &self.signed_invoice.payment_hash().expect("checked by constructor").0
1015 /// Return the description or a hash of it for longer ones
1017 /// (C-not exported) because we don't yet export InvoiceDescription
1018 pub fn description(&self) -> InvoiceDescription {
1019 if let Some(ref direct) = self.signed_invoice.description() {
1020 return InvoiceDescription::Direct(direct);
1021 } else if let Some(ref hash) = self.signed_invoice.description_hash() {
1022 return InvoiceDescription::Hash(hash);
1024 unreachable!("ensured by constructor");
1027 /// Get the payee's public key if one was included in the invoice
1028 pub fn payee_pub_key(&self) -> Option<&PublicKey> {
1029 self.signed_invoice.payee_pub_key().map(|x| &x.0)
1032 /// Get the payment secret if one was included in the invoice
1033 pub fn payment_secret(&self) -> Option<&PaymentSecret> {
1034 self.signed_invoice.payment_secret()
1037 /// Get the invoice features if they were included in the invoice
1038 pub fn features(&self) -> Option<&InvoiceFeatures> {
1039 self.signed_invoice.features()
1042 /// Recover the payee's public key (only to be used if none was included in the invoice)
1043 pub fn recover_payee_pub_key(&self) -> PublicKey {
1044 self.signed_invoice.recover_payee_pub_key().expect("was checked by constructor").0
1047 /// Returns the invoice's expiry time if present
1048 pub fn expiry_time(&self) -> Duration {
1049 self.signed_invoice.expiry_time()
1051 .unwrap_or(Duration::from_secs(3600))
1054 /// Returns the invoice's `min_cltv_expiry` time if present
1055 pub fn min_final_cltv_expiry(&self) -> Option<u64> {
1056 self.signed_invoice.min_final_cltv_expiry().map(|x| x.0)
1059 /// Returns a list of all fallback addresses
1061 /// (C-not exported) as we don't support Vec<&NonOpaqueType>
1062 pub fn fallbacks(&self) -> Vec<&Fallback> {
1063 self.signed_invoice.fallbacks()
1066 /// Returns a list of all routes included in the invoice
1067 pub fn routes(&self) -> Vec<&RouteHint> {
1068 self.signed_invoice.routes()
1071 /// Returns the currency for which the invoice was issued
1072 pub fn currency(&self) -> Currency {
1073 self.signed_invoice.currency()
1076 /// Returns the amount if specified in the invoice as pico <currency>.
1077 pub fn amount_pico_btc(&self) -> Option<u64> {
1078 self.signed_invoice.amount_pico_btc()
1082 impl From<TaggedField> for RawTaggedField {
1083 fn from(tf: TaggedField) -> Self {
1084 RawTaggedField::KnownSemantics(tf)
1089 /// Numeric representation of the field's tag
1090 pub fn tag(&self) -> u5 {
1091 let tag = match *self {
1092 TaggedField::PaymentHash(_) => constants::TAG_PAYMENT_HASH,
1093 TaggedField::Description(_) => constants::TAG_DESCRIPTION,
1094 TaggedField::PayeePubKey(_) => constants::TAG_PAYEE_PUB_KEY,
1095 TaggedField::DescriptionHash(_) => constants::TAG_DESCRIPTION_HASH,
1096 TaggedField::ExpiryTime(_) => constants::TAG_EXPIRY_TIME,
1097 TaggedField::MinFinalCltvExpiry(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY,
1098 TaggedField::Fallback(_) => constants::TAG_FALLBACK,
1099 TaggedField::Route(_) => constants::TAG_ROUTE,
1100 TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
1101 TaggedField::Features(_) => constants::TAG_FEATURES,
1104 u5::try_from_u8(tag).expect("all tags defined are <32")
1110 /// Creates a new `Description` if `description` is at most 1023 __bytes__ long,
1111 /// returns `CreationError::DescriptionTooLong` otherwise
1113 /// Please note that single characters may use more than one byte due to UTF8 encoding.
1114 pub fn new(description: String) -> Result<Description, CreationError> {
1115 if description.len() > 639 {
1116 Err(CreationError::DescriptionTooLong)
1118 Ok(Description(description))
1122 /// Returns the underlying description `String`
1123 pub fn into_inner(self) -> String {
1128 impl Into<String> for Description {
1129 fn into(self) -> String {
1134 impl Deref for Description {
1137 fn deref(&self) -> &str {
1142 impl From<PublicKey> for PayeePubKey {
1143 fn from(pk: PublicKey) -> Self {
1148 impl Deref for PayeePubKey {
1149 type Target = PublicKey;
1151 fn deref(&self) -> &PublicKey {
1157 /// Construct an `ExpiryTime` from seconds. If there exists a `PositiveTimestamp` which would
1158 /// overflow on adding the `EpiryTime` to it then this function will return a
1159 /// `CreationError::ExpiryTimeOutOfBounds`.
1160 pub fn from_seconds(seconds: u64) -> Result<ExpiryTime, CreationError> {
1161 if seconds <= MAX_EXPIRY_TIME {
1162 Ok(ExpiryTime(Duration::from_secs(seconds)))
1164 Err(CreationError::ExpiryTimeOutOfBounds)
1168 /// Construct an `ExpiryTime` from a `Duration`. If there exists a `PositiveTimestamp` which
1169 /// would overflow on adding the `EpiryTime` to it then this function will return a
1170 /// `CreationError::ExpiryTimeOutOfBounds`.
1171 pub fn from_duration(duration: Duration) -> Result<ExpiryTime, CreationError> {
1172 if duration.as_secs() <= MAX_EXPIRY_TIME {
1173 Ok(ExpiryTime(duration))
1175 Err(CreationError::ExpiryTimeOutOfBounds)
1179 /// Returns the expiry time in seconds
1180 pub fn as_seconds(&self) -> u64 {
1184 /// Returns a reference to the underlying `Duration` (=expiry time)
1185 pub fn as_duration(&self) -> &Duration {
1191 /// Create a new (partial) route from a list of hops
1192 pub fn new(hops: Vec<RouteHintHop>) -> Result<RouteHint, CreationError> {
1193 if hops.len() <= 12 {
1196 Err(CreationError::RouteTooLong)
1200 /// Returrn the underlying vector of hops
1201 pub fn into_inner(self) -> Vec<RouteHintHop> {
1206 impl Into<Vec<RouteHintHop>> for RouteHint {
1207 fn into(self) -> Vec<RouteHintHop> {
1212 impl Deref for RouteHint {
1213 type Target = Vec<RouteHintHop>;
1215 fn deref(&self) -> &Vec<RouteHintHop> {
1220 impl Deref for InvoiceSignature {
1221 type Target = RecoverableSignature;
1223 fn deref(&self) -> &RecoverableSignature {
1228 impl Deref for SignedRawInvoice {
1229 type Target = RawInvoice;
1231 fn deref(&self) -> &RawInvoice {
1236 /// Errors that may occur when constructing a new `RawInvoice` or `Invoice`
1237 #[derive(Eq, PartialEq, Debug, Clone)]
1238 pub enum CreationError {
1239 /// The supplied description string was longer than 639 __bytes__ (see [`Description::new(…)`](./struct.Description.html#method.new))
1242 /// The specified route has too many hops and can't be encoded
1245 /// The unix timestamp of the supplied date is <0 or can't be represented as `SystemTime`
1246 TimestampOutOfBounds,
1248 /// The supplied expiry time could cause an overflow if added to a `PositiveTimestamp`
1249 ExpiryTimeOutOfBounds,
1252 impl Display for CreationError {
1253 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1255 CreationError::DescriptionTooLong => f.write_str("The supplied description string was longer than 639 bytes"),
1256 CreationError::RouteTooLong => f.write_str("The specified route has too many hops and can't be encoded"),
1257 CreationError::TimestampOutOfBounds => f.write_str("The unix timestamp of the supplied date is <0 or can't be represented as `SystemTime`"),
1258 CreationError::ExpiryTimeOutOfBounds => f.write_str("The supplied expiry time could cause an overflow if added to a `PositiveTimestamp`"),
1263 impl std::error::Error for CreationError { }
1265 /// Errors that may occur when converting a `RawInvoice` to an `Invoice`. They relate to the
1266 /// requirements sections in BOLT #11
1267 #[derive(Eq, PartialEq, Debug, Clone)]
1268 pub enum SemanticError {
1269 /// The invoice is missing the mandatory payment hash
1272 /// The invoice has multiple payment hashes which isn't allowed
1273 MultiplePaymentHashes,
1275 /// No description or description hash are part of the invoice
1278 /// The invoice contains multiple descriptions and/or description hashes which isn't allowed
1279 MultipleDescriptions,
1281 /// The recovery id doesn't fit the signature/pub key
1284 /// The invoice's signature is invalid
1288 impl Display for SemanticError {
1289 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1291 SemanticError::NoPaymentHash => f.write_str("The invoice is missing the mandatory payment hash"),
1292 SemanticError::MultiplePaymentHashes => f.write_str("The invoice has multiple payment hashes which isn't allowed"),
1293 SemanticError::NoDescription => f.write_str("No description or description hash are part of the invoice"),
1294 SemanticError::MultipleDescriptions => f.write_str("The invoice contains multiple descriptions and/or description hashes which isn't allowed"),
1295 SemanticError::InvalidRecoveryId => f.write_str("The recovery id doesn't fit the signature/pub key"),
1296 SemanticError::InvalidSignature => f.write_str("The invoice's signature is invalid"),
1301 impl std::error::Error for SemanticError { }
1303 /// When signing using a fallible method either an user-supplied `SignError` or a `CreationError`
1306 /// (C-not exported) As we don't support unbounded generics
1307 #[derive(Eq, PartialEq, Debug, Clone)]
1308 pub enum SignOrCreationError<S> {
1309 /// An error occurred during signing
1312 /// An error occurred while building the transaction
1313 CreationError(CreationError),
1316 impl<S> Display for SignOrCreationError<S> {
1317 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1319 SignOrCreationError::SignError(_) => f.write_str("An error occurred during signing"),
1320 SignOrCreationError::CreationError(err) => err.fmt(f),
1327 use bitcoin_hashes::hex::FromHex;
1328 use bitcoin_hashes::sha256;
1331 fn test_system_time_bounds_assumptions() {
1335 ::PositiveTimestamp::from_unix_timestamp(::SYSTEM_TIME_MAX_UNIX_TIMESTAMP + 1),
1336 Err(::CreationError::TimestampOutOfBounds)
1340 ::ExpiryTime::from_seconds(::MAX_EXPIRY_TIME + 1),
1341 Err(::CreationError::ExpiryTimeOutOfBounds)
1346 fn test_calc_invoice_hash() {
1347 use ::{RawInvoice, RawHrp, RawDataPart, Currency, PositiveTimestamp};
1348 use ::TaggedField::*;
1350 let invoice = RawInvoice {
1352 currency: Currency::Bitcoin,
1357 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1358 tagged_fields: vec![
1359 PaymentHash(::Sha256(sha256::Hash::from_hex(
1360 "0001020304050607080900010203040506070809000102030405060708090102"
1361 ).unwrap())).into(),
1362 Description(::Description::new(
1363 "Please consider supporting this project".to_owned()
1369 let expected_hash = [
1370 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27, 0x7b, 0x1d,
1371 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7, 0x83, 0x5d, 0xb2, 0xec,
1372 0xd5, 0x18, 0xe1, 0xc9
1375 assert_eq!(invoice.hash(), expected_hash)
1379 fn test_check_signature() {
1381 use secp256k1::Secp256k1;
1382 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
1383 use secp256k1::key::{SecretKey, PublicKey};
1384 use {SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256,
1387 let invoice = SignedRawInvoice {
1388 raw_invoice: RawInvoice {
1390 currency: Currency::Bitcoin,
1395 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1396 tagged_fields: vec ! [
1397 PaymentHash(Sha256(sha256::Hash::from_hex(
1398 "0001020304050607080900010203040506070809000102030405060708090102"
1399 ).unwrap())).into(),
1402 "Please consider supporting this project".to_owned()
1409 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27,
1410 0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
1411 0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
1413 signature: InvoiceSignature(RecoverableSignature::from_compact(
1415 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
1416 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
1417 0x4e, 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f,
1418 0x42, 0x5f, 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad,
1419 0x0d, 0x6e, 0x35, 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9,
1420 0xaa, 0xb1, 0x5e, 0x57, 0x38, 0xb1, 0x1f, 0x12, 0x7f
1422 RecoveryId::from_i32(0).unwrap()
1426 assert!(invoice.check_signature());
1428 let private_key = SecretKey::from_slice(
1430 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
1431 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
1432 0x3b, 0x2d, 0xb7, 0x34
1435 let public_key = PublicKey::from_secret_key(&Secp256k1::new(), &private_key);
1437 assert_eq!(invoice.recover_payee_pub_key(), Ok(::PayeePubKey(public_key)));
1439 let (raw_invoice, _, _) = invoice.into_parts();
1440 let new_signed = raw_invoice.sign::<_, ()>(|hash| {
1441 Ok(Secp256k1::new().sign_recoverable(hash, &private_key))
1444 assert!(new_signed.check_signature());
1448 fn test_builder_amount() {
1451 let builder = InvoiceBuilder::new(Currency::Bitcoin)
1452 .description("Test".into())
1453 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1454 .current_timestamp();
1456 let invoice = builder.clone()
1457 .amount_pico_btc(15000)
1461 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Nano));
1462 assert_eq!(invoice.hrp.raw_amount, Some(15));
1465 let invoice = builder.clone()
1466 .amount_pico_btc(1500)
1470 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Pico));
1471 assert_eq!(invoice.hrp.raw_amount, Some(1500));
1475 fn test_builder_fail() {
1477 use std::iter::FromIterator;
1478 use secp256k1::key::PublicKey;
1480 let builder = InvoiceBuilder::new(Currency::Bitcoin)
1481 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1482 .current_timestamp();
1484 let too_long_string = String::from_iter(
1485 (0..1024).map(|_| '?')
1488 let long_desc_res = builder.clone()
1489 .description(too_long_string)
1491 assert_eq!(long_desc_res, Err(CreationError::DescriptionTooLong));
1493 let route_hop = RouteHintHop {
1494 src_node_id: PublicKey::from_slice(
1496 0x03, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4,
1497 0x3c, 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a,
1498 0x95, 0xc3, 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
1501 short_channel_id: 0,
1504 proportional_millionths: 0,
1506 cltv_expiry_delta: 0,
1507 htlc_minimum_msat: None,
1508 htlc_maximum_msat: None,
1510 let too_long_route = vec![route_hop; 13];
1511 let long_route_res = builder.clone()
1512 .description("Test".into())
1513 .route(too_long_route)
1515 assert_eq!(long_route_res, Err(CreationError::RouteTooLong));
1517 let sign_error_res = builder.clone()
1518 .description("Test".into())
1519 .try_build_signed(|_| {
1520 Err("ImaginaryError")
1522 assert_eq!(sign_error_res, Err(SignOrCreationError::SignError("ImaginaryError")));
1526 fn test_builder_ok() {
1528 use secp256k1::Secp256k1;
1529 use secp256k1::key::{SecretKey, PublicKey};
1530 use std::time::{UNIX_EPOCH, Duration};
1532 let secp_ctx = Secp256k1::new();
1534 let private_key = SecretKey::from_slice(
1536 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
1537 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
1538 0x3b, 0x2d, 0xb7, 0x34
1541 let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key);
1545 src_node_id: public_key.clone(),
1546 short_channel_id: de::parse_int_be(&[123; 8], 256).expect("short chan ID slice too big?"),
1549 proportional_millionths: 1,
1551 cltv_expiry_delta: 145,
1552 htlc_minimum_msat: None,
1553 htlc_maximum_msat: None,
1556 src_node_id: public_key.clone(),
1557 short_channel_id: de::parse_int_be(&[42; 8], 256).expect("short chan ID slice too big?"),
1560 proportional_millionths: 2,
1562 cltv_expiry_delta: 146,
1563 htlc_minimum_msat: None,
1564 htlc_maximum_msat: None,
1570 src_node_id: public_key.clone(),
1571 short_channel_id: 0,
1574 proportional_millionths: 3,
1576 cltv_expiry_delta: 147,
1577 htlc_minimum_msat: None,
1578 htlc_maximum_msat: None,
1581 src_node_id: public_key.clone(),
1582 short_channel_id: de::parse_int_be(&[1; 8], 256).expect("short chan ID slice too big?"),
1585 proportional_millionths: 4,
1587 cltv_expiry_delta: 148,
1588 htlc_minimum_msat: None,
1589 htlc_maximum_msat: None,
1593 let builder = InvoiceBuilder::new(Currency::BitcoinTestnet)
1594 .amount_pico_btc(123)
1595 .timestamp(UNIX_EPOCH + Duration::from_secs(1234567))
1596 .payee_pub_key(public_key.clone())
1597 .expiry_time(Duration::from_secs(54321))
1598 .min_final_cltv_expiry(144)
1599 .min_final_cltv_expiry(143)
1600 .fallback(Fallback::PubKeyHash([0;20]))
1601 .route(route_1.clone())
1602 .route(route_2.clone())
1603 .description_hash(sha256::Hash::from_slice(&[3;32][..]).unwrap())
1604 .payment_hash(sha256::Hash::from_slice(&[21;32][..]).unwrap());
1606 let invoice = builder.clone().build_signed(|hash| {
1607 secp_ctx.sign_recoverable(hash, &private_key)
1610 assert!(invoice.check_signature().is_ok());
1611 assert_eq!(invoice.tagged_fields().count(), 9);
1613 assert_eq!(invoice.amount_pico_btc(), Some(123));
1614 assert_eq!(invoice.currency(), Currency::BitcoinTestnet);
1616 invoice.timestamp().duration_since(UNIX_EPOCH).unwrap().as_secs(),
1619 assert_eq!(invoice.payee_pub_key(), Some(&public_key));
1620 assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
1621 assert_eq!(invoice.min_final_cltv_expiry(), Some(144));
1622 assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash([0;20])]);
1623 assert_eq!(invoice.routes(), vec![&RouteHint(route_1), &RouteHint(route_2)]);
1625 invoice.description(),
1626 InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap()))
1628 assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&[21;32][..]).unwrap());
1630 let raw_invoice = builder.build_raw().unwrap();
1631 assert_eq!(raw_invoice, *invoice.into_signed_raw().raw_invoice())