3 use std::fmt::{Display, Formatter};
4 use std::num::ParseIntError;
9 use bech32::{u5, FromBase32};
11 use bitcoin_hashes::Hash;
12 use bitcoin_hashes::sha256;
13 use lightning::routing::network_graph::RoutingFees;
14 use lightning::routing::router::RouteHintHop;
16 use num_traits::{CheckedAdd, CheckedMul};
19 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
20 use secp256k1::key::PublicKey;
24 use self::hrp_sm::parse_hrp;
26 /// State machine to parse the hrp
30 #[derive(PartialEq, Eq, Debug)]
41 fn next_state(&self, read_symbol: char) -> Result<States, super::ParseError> {
44 if read_symbol == 'l' {
47 Err(super::ParseError::MalformedHRP)
51 if read_symbol == 'n' {
54 Err(super::ParseError::MalformedHRP)
58 if !read_symbol.is_numeric() {
59 Ok(States::ParseCurrencyPrefix)
61 Ok(States::ParseAmountNumber)
64 States::ParseCurrencyPrefix => {
65 if !read_symbol.is_numeric() {
66 Ok(States::ParseCurrencyPrefix)
68 Ok(States::ParseAmountNumber)
71 States::ParseAmountNumber => {
72 if read_symbol.is_numeric() {
73 Ok(States::ParseAmountNumber)
74 } else if ['m', 'u', 'n', 'p'].contains(&read_symbol) {
75 Ok(States::ParseAmountSiPrefix)
77 Err(super::ParseError::MalformedHRP)
80 States::ParseAmountSiPrefix => Err(super::ParseError::MalformedHRP),
84 fn is_final(&self) -> bool {
85 !(*self == States::ParseL || *self == States::ParseN)
93 currency_prefix: Option<Range<usize>>,
94 amount_number: Option<Range<usize>>,
95 amount_si_prefix: Option<Range<usize>>,
99 fn new() -> StateMachine {
101 state: States::Start,
103 currency_prefix: None,
105 amount_si_prefix: None,
109 fn update_range(range: &mut Option<Range<usize>>, position: usize) {
110 let new_range = match *range {
111 None => Range {start: position, end: position + 1},
112 Some(ref r) => Range {start: r.start, end: r.end + 1},
114 *range = Some(new_range);
117 fn step(&mut self, c: char) -> Result<(), super::ParseError> {
118 let next_state = self.state.next_state(c)?;
120 States::ParseCurrencyPrefix => {
121 StateMachine::update_range(&mut self.currency_prefix, self.position)
123 States::ParseAmountNumber => {
124 StateMachine::update_range(&mut self.amount_number, self.position)
126 States::ParseAmountSiPrefix => {
127 StateMachine::update_range(&mut self.amount_si_prefix, self.position)
133 self.state = next_state;
137 fn is_final(&self) -> bool {
138 self.state.is_final()
141 fn currency_prefix(&self) -> &Option<Range<usize>> {
142 &self.currency_prefix
145 fn amount_number(&self) -> &Option<Range<usize>> {
149 fn amount_si_prefix(&self) -> &Option<Range<usize>> {
150 &self.amount_si_prefix
154 pub fn parse_hrp(input: &str) -> Result<(&str, &str, &str), super::ParseError> {
155 let mut sm = StateMachine::new();
156 for c in input.chars() {
161 return Err(super::ParseError::MalformedHRP);
164 let currency = sm.currency_prefix().clone()
165 .map(|r| &input[r]).unwrap_or("");
166 let amount = sm.amount_number().clone()
167 .map(|r| &input[r]).unwrap_or("");
168 let si = sm.amount_si_prefix().clone()
169 .map(|r| &input[r]).unwrap_or("");
171 Ok((currency, amount, si))
176 impl FromStr for super::Currency {
177 type Err = ParseError;
179 fn from_str(currency_prefix: &str) -> Result<Self, ParseError> {
180 match currency_prefix {
181 "bc" => Ok(Currency::Bitcoin),
182 "tb" => Ok(Currency::BitcoinTestnet),
183 "bcrt" => Ok(Currency::Regtest),
184 "sb" => Ok(Currency::Simnet),
185 _ => Err(ParseError::UnknownCurrency)
190 impl FromStr for SiPrefix {
191 type Err = ParseError;
193 fn from_str(currency_prefix: &str) -> Result<Self, ParseError> {
195 match currency_prefix {
200 _ => Err(ParseError::UnknownSiPrefix)
206 /// use lightning_invoice::Invoice;
208 /// let invoice = "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp\
209 /// l2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d7\
210 /// 3gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ec\
213 /// assert!(invoice.parse::<Invoice>().is_ok());
215 impl FromStr for Invoice {
216 type Err = ParseOrSemanticError;
218 fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
219 let signed = s.parse::<SignedRawInvoice>()?;
220 Ok(Invoice::from_signed(signed)?)
225 /// use lightning_invoice::*;
227 /// let invoice = "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp\
228 /// l2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d7\
229 /// 3gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ec\
232 /// let parsed_1 = invoice.parse::<Invoice>();
234 /// let parsed_2 = match invoice.parse::<SignedRawInvoice>() {
235 /// Ok(signed) => match Invoice::from_signed(signed) {
236 /// Ok(invoice) => Ok(invoice),
237 /// Err(e) => Err(ParseOrSemanticError::SemanticError(e)),
239 /// Err(e) => Err(ParseOrSemanticError::ParseError(e)),
242 /// assert!(parsed_1.is_ok());
243 /// assert_eq!(parsed_1, parsed_2);
245 impl FromStr for SignedRawInvoice {
246 type Err = ParseError;
248 fn from_str(s: &str) -> Result<Self, Self::Err> {
249 let (hrp, data) = bech32::decode(s)?;
251 if data.len() < 104 {
252 return Err(ParseError::TooShortDataPart);
255 let raw_hrp: RawHrp = hrp.parse()?;
256 let data_part = RawDataPart::from_base32(&data[..data.len()-104])?;
258 Ok(SignedRawInvoice {
259 raw_invoice: RawInvoice {
263 hash: RawInvoice::hash_from_parts(
265 &data[..data.len()-104]
267 signature: Signature::from_base32(&data[data.len()-104..])?,
272 impl FromStr for RawHrp {
273 type Err = ParseError;
275 fn from_str(hrp: &str) -> Result<Self, <Self as FromStr>::Err> {
276 let parts = parse_hrp(hrp)?;
278 let currency = parts.0.parse::<Currency>()?;
280 let amount = if !parts.1.is_empty() {
281 Some(parts.1.parse::<u64>()?)
286 let si_prefix: Option<SiPrefix> = if parts.2.is_empty() {
289 let si: SiPrefix = parts.2.parse()?;
290 if let Some(amt) = amount {
291 if amt.checked_mul(si.multiplier()).is_none() {
292 return Err(ParseError::IntegerOverflowError);
301 si_prefix: si_prefix,
306 impl FromBase32 for RawDataPart {
307 type Err = ParseError;
309 fn from_base32(data: &[u5]) -> Result<Self, Self::Err> {
310 if data.len() < 7 { // timestamp length
311 return Err(ParseError::TooShortDataPart);
314 let timestamp = PositiveTimestamp::from_base32(&data[0..7])?;
315 let tagged = parse_tagged_parts(&data[7..])?;
318 timestamp: timestamp,
319 tagged_fields: tagged,
324 impl FromBase32 for PositiveTimestamp {
325 type Err = ParseError;
327 fn from_base32(b32: &[u5]) -> Result<Self, Self::Err> {
329 return Err(ParseError::InvalidSliceLength("PositiveTimestamp::from_base32()".into()));
331 let timestamp: u64 = parse_int_be(b32, 32)
332 .expect("7*5bit < 64bit, no overflow possible");
333 match PositiveTimestamp::from_unix_timestamp(timestamp) {
335 Err(CreationError::TimestampOutOfBounds) => Err(ParseError::TimestampOverflow),
336 Err(_) => unreachable!(),
341 impl FromBase32 for Signature {
342 type Err = ParseError;
343 fn from_base32(signature: &[u5]) -> Result<Self, Self::Err> {
344 if signature.len() != 104 {
345 return Err(ParseError::InvalidSliceLength("Signature::from_base32()".into()));
347 let recoverable_signature_bytes = Vec::<u8>::from_base32(signature)?;
348 let signature = &recoverable_signature_bytes[0..64];
349 let recovery_id = RecoveryId::from_i32(recoverable_signature_bytes[64] as i32)?;
351 Ok(Signature(RecoverableSignature::from_compact(
358 pub(crate) fn parse_int_be<T, U>(digits: &[U], base: T) -> Option<T>
359 where T: CheckedAdd + CheckedMul + From<u8> + Default,
362 digits.iter().fold(Some(Default::default()), |acc, b|
364 .and_then(|x| x.checked_mul(&base))
365 .and_then(|x| x.checked_add(&(Into::<u8>::into(*b)).into()))
369 fn parse_tagged_parts(data: &[u5]) -> Result<Vec<RawTaggedField>, ParseError> {
370 let mut parts = Vec::<RawTaggedField>::new();
373 while !data.is_empty() {
375 return Err(ParseError::UnexpectedEndOfTaggedFields);
378 // Ignore tag at data[0], it will be handled in the TaggedField parsers and
379 // parse the length to find the end of the tagged field's data
380 let len = parse_int_be(&data[1..3], 32).expect("can't overflow");
381 let last_element = 3 + len;
383 if data.len() < last_element {
384 return Err(ParseError::UnexpectedEndOfTaggedFields);
387 // Get the tagged field's data slice
388 let field = &data[0..last_element];
390 // Set data slice to remaining data
391 data = &data[last_element..];
393 match TaggedField::from_base32(field) {
395 parts.push(RawTaggedField::KnownSemantics(field))
397 Err(ParseError::Skip) => {
398 parts.push(RawTaggedField::UnknownSemantics(field.into()))
400 Err(e) => {return Err(e)}
406 impl FromBase32 for TaggedField {
407 type Err = ParseError;
409 fn from_base32(field: &[u5]) -> Result<TaggedField, ParseError> {
411 return Err(ParseError::UnexpectedEndOfTaggedFields);
415 let field_data = &field[3..];
418 constants::TAG_PAYMENT_HASH =>
419 Ok(TaggedField::PaymentHash(Sha256::from_base32(field_data)?)),
420 constants::TAG_DESCRIPTION =>
421 Ok(TaggedField::Description(Description::from_base32(field_data)?)),
422 constants::TAG_PAYEE_PUB_KEY =>
423 Ok(TaggedField::PayeePubKey(PayeePubKey::from_base32(field_data)?)),
424 constants::TAG_DESCRIPTION_HASH =>
425 Ok(TaggedField::DescriptionHash(Sha256::from_base32(field_data)?)),
426 constants::TAG_EXPIRY_TIME =>
427 Ok(TaggedField::ExpiryTime(ExpiryTime::from_base32(field_data)?)),
428 constants::TAG_MIN_FINAL_CLTV_EXPIRY =>
429 Ok(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry::from_base32(field_data)?)),
430 constants::TAG_FALLBACK =>
431 Ok(TaggedField::Fallback(Fallback::from_base32(field_data)?)),
432 constants::TAG_ROUTE =>
433 Ok(TaggedField::Route(Route::from_base32(field_data)?)),
434 constants::TAG_PAYMENT_SECRET =>
435 Ok(TaggedField::PaymentSecret(PaymentSecret::from_base32(field_data)?)),
437 // "A reader MUST skip over unknown fields"
438 Err(ParseError::Skip)
444 impl FromBase32 for Sha256 {
445 type Err = ParseError;
447 fn from_base32(field_data: &[u5]) -> Result<Sha256, ParseError> {
448 if field_data.len() != 52 {
449 // "A reader MUST skip over […] a p, [or] h […] field that does not have data_length 52 […]."
450 Err(ParseError::Skip)
452 Ok(Sha256(sha256::Hash::from_slice(&Vec::<u8>::from_base32(field_data)?)
453 .expect("length was checked before (52 u5 -> 32 u8)")))
458 impl FromBase32 for Description {
459 type Err = ParseError;
461 fn from_base32(field_data: &[u5]) -> Result<Description, ParseError> {
462 let bytes = Vec::<u8>::from_base32(field_data)?;
463 let description = String::from(str::from_utf8(&bytes)?);
464 Ok(Description::new(description).expect(
465 "Max len is 639=floor(1023*5/8) since the len field is only 10bits long"
470 impl FromBase32 for PayeePubKey {
471 type Err = ParseError;
473 fn from_base32(field_data: &[u5]) -> Result<PayeePubKey, ParseError> {
474 if field_data.len() != 53 {
475 // "A reader MUST skip over […] a n […] field that does not have data_length 53 […]."
476 Err(ParseError::Skip)
478 let data_bytes = Vec::<u8>::from_base32(field_data)?;
479 let pub_key = PublicKey::from_slice(&data_bytes)?;
485 impl FromBase32 for PaymentSecret {
486 type Err = ParseError;
488 fn from_base32(field_data: &[u5]) -> Result<PaymentSecret, ParseError> {
489 if field_data.len() != 52 {
490 Err(ParseError::Skip)
492 let data_bytes = Vec::<u8>::from_base32(field_data)?;
493 let mut payment_secret = [0; 32];
494 payment_secret.copy_from_slice(&data_bytes);
495 Ok(PaymentSecret(payment_secret))
500 impl FromBase32 for ExpiryTime {
501 type Err = ParseError;
503 fn from_base32(field_data: &[u5]) -> Result<ExpiryTime, ParseError> {
504 match parse_int_be::<u64, u5>(field_data, 32)
505 .and_then(|t| ExpiryTime::from_seconds(t).ok()) // ok, since the only error is out of bounds
508 None => Err(ParseError::IntegerOverflowError),
513 impl FromBase32 for MinFinalCltvExpiry {
514 type Err = ParseError;
516 fn from_base32(field_data: &[u5]) -> Result<MinFinalCltvExpiry, ParseError> {
517 let expiry = parse_int_be::<u64, u5>(field_data, 32);
518 if let Some(expiry) = expiry {
519 Ok(MinFinalCltvExpiry(expiry))
521 Err(ParseError::IntegerOverflowError)
526 impl FromBase32 for Fallback {
527 type Err = ParseError;
529 fn from_base32(field_data: &[u5]) -> Result<Fallback, ParseError> {
530 if field_data.len() < 1 {
531 return Err(ParseError::UnexpectedEndOfTaggedFields);
534 let version = field_data[0];
535 let bytes = Vec::<u8>::from_base32(&field_data[1..])?;
537 match version.to_u8() {
539 if bytes.len() < 2 || bytes.len() > 40 {
540 return Err(ParseError::InvalidSegWitProgramLength);
543 Ok(Fallback::SegWitProgram {
549 if bytes.len() != 20 {
550 return Err(ParseError::InvalidPubKeyHashLength);
552 //TODO: refactor once const generics are available
553 let mut pkh = [0u8; 20];
554 pkh.copy_from_slice(&bytes);
555 Ok(Fallback::PubKeyHash(pkh))
558 if bytes.len() != 20 {
559 return Err(ParseError::InvalidScriptHashLength);
561 let mut sh = [0u8; 20];
562 sh.copy_from_slice(&bytes);
563 Ok(Fallback::ScriptHash(sh))
565 _ => Err(ParseError::Skip)
570 impl FromBase32 for Route {
571 type Err = ParseError;
573 fn from_base32(field_data: &[u5]) -> Result<Route, ParseError> {
574 let bytes = Vec::<u8>::from_base32(field_data)?;
576 if bytes.len() % 51 != 0 {
577 return Err(ParseError::UnexpectedEndOfTaggedFields);
580 let mut route_hops = Vec::<RouteHintHop>::new();
582 let mut bytes = bytes.as_slice();
583 while !bytes.is_empty() {
584 let hop_bytes = &bytes[0..51];
585 bytes = &bytes[51..];
587 let mut channel_id: [u8; 8] = Default::default();
588 channel_id.copy_from_slice(&hop_bytes[33..41]);
590 let hop = RouteHintHop {
591 src_node_id: PublicKey::from_slice(&hop_bytes[0..33])?,
592 short_channel_id: parse_int_be(&channel_id, 256).expect("short chan ID slice too big?"),
594 base_msat: parse_int_be(&hop_bytes[41..45], 256).expect("slice too big?"),
595 proportional_millionths: parse_int_be(&hop_bytes[45..49], 256).expect("slice too big?"),
597 cltv_expiry_delta: parse_int_be(&hop_bytes[49..51], 256).expect("slice too big?"),
598 htlc_minimum_msat: None,
599 htlc_maximum_msat: None,
602 route_hops.push(hop);
605 Ok(Route(route_hops))
609 /// Errors that indicate what is wrong with the invoice. They have some granularity for debug
610 /// reasons, but should generally result in an "invalid BOLT11 invoice" message for the user.
611 #[allow(missing_docs)]
612 #[derive(PartialEq, Debug, Clone)]
613 pub enum ParseError {
614 Bech32Error(bech32::Error),
615 ParseAmountError(ParseIntError),
616 MalformedSignature(secp256k1::Error),
622 UnexpectedEndOfTaggedFields,
623 DescriptionDecodeError(str::Utf8Error),
625 IntegerOverflowError,
626 InvalidSegWitProgramLength,
627 InvalidPubKeyHashLength,
628 InvalidScriptHashLength,
630 InvalidSliceLength(String),
632 /// Not an error, but used internally to signal that a part of the invoice should be ignored
633 /// according to BOLT11
638 /// Indicates that something went wrong while parsing or validating the invoice. Parsing errors
639 /// should be mostly seen as opaque and are only there for debugging reasons. Semantic errors
640 /// like wrong signatures, missing fields etc. could mean that someone tampered with the invoice.
641 #[derive(PartialEq, Debug, Clone)]
642 pub enum ParseOrSemanticError {
643 /// The invoice couldn't be decoded
644 ParseError(ParseError),
646 /// The invoice could be decoded but violates the BOLT11 standard
647 SemanticError(::SemanticError),
650 impl Display for ParseError {
651 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
653 // TODO: find a way to combine the first three arms (e as error::Error?)
654 ParseError::Bech32Error(ref e) => {
655 write!(f, "Invalid bech32: {}", e)
657 ParseError::ParseAmountError(ref e) => {
658 write!(f, "Invalid amount in hrp ({})", e)
660 ParseError::MalformedSignature(ref e) => {
661 write!(f, "Invalid secp256k1 signature: {}", e)
663 ParseError::DescriptionDecodeError(ref e) => {
664 write!(f, "Description is not a valid utf-8 string: {}", e)
666 ParseError::InvalidSliceLength(ref function) => {
667 write!(f, "Slice in function {} had the wrong length", function)
669 ParseError::BadPrefix => f.write_str("did not begin with 'ln'"),
670 ParseError::UnknownCurrency => f.write_str("currency code unknown"),
671 ParseError::UnknownSiPrefix => f.write_str("unknown SI prefix"),
672 ParseError::MalformedHRP => f.write_str("malformed human readable part"),
673 ParseError::TooShortDataPart => {
674 f.write_str("data part too short (should be at least 111 bech32 chars long)")
676 ParseError::UnexpectedEndOfTaggedFields => {
677 f.write_str("tagged fields part ended unexpectedly")
679 ParseError::PaddingError => f.write_str("some data field had bad padding"),
680 ParseError::IntegerOverflowError => {
681 f.write_str("parsed integer doesn't fit into receiving type")
683 ParseError::InvalidSegWitProgramLength => {
684 f.write_str("fallback SegWit program is too long or too short")
686 ParseError::InvalidPubKeyHashLength => {
687 f.write_str("fallback public key hash has a length unequal 20 bytes")
689 ParseError::InvalidScriptHashLength => {
690 f.write_str("fallback script hash has a length unequal 32 bytes")
692 ParseError::InvalidRecoveryId => {
693 f.write_str("recovery id is out of range (should be in [0,3])")
695 ParseError::Skip => {
696 f.write_str("the tagged field has to be skipped because of an unexpected, but allowed property")
698 ParseError::TimestampOverflow => {
699 f.write_str("the invoice's timestamp could not be represented as SystemTime")
705 impl Display for ParseOrSemanticError {
706 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
708 ParseOrSemanticError::ParseError(err) => err.fmt(f),
709 ParseOrSemanticError::SemanticError(err) => err.fmt(f),
714 impl error::Error for ParseError {}
716 impl error::Error for ParseOrSemanticError {}
718 macro_rules! from_error {
719 ($my_error:expr, $extern_error:ty) => {
720 impl From<$extern_error> for ParseError {
721 fn from(e: $extern_error) -> Self {
728 from_error!(ParseError::MalformedSignature, secp256k1::Error);
729 from_error!(ParseError::ParseAmountError, ParseIntError);
730 from_error!(ParseError::DescriptionDecodeError, str::Utf8Error);
732 impl From<bech32::Error> for ParseError {
733 fn from(e: bech32::Error) -> Self {
735 bech32::Error::InvalidPadding => ParseError::PaddingError,
736 _ => ParseError::Bech32Error(e)
741 impl From<ParseError> for ParseOrSemanticError {
742 fn from(e: ParseError) -> Self {
743 ParseOrSemanticError::ParseError(e)
747 impl From<::SemanticError> for ParseOrSemanticError {
748 fn from(e: SemanticError) -> Self {
749 ParseOrSemanticError::SemanticError(e)
756 use secp256k1::PublicKey;
758 use bitcoin_hashes::hex::FromHex;
759 use bitcoin_hashes::sha256;
761 const CHARSET_REV: [i8; 128] = [
762 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
763 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
764 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
765 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
766 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
767 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
768 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
769 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
772 fn from_bech32(bytes_5b: &[u8]) -> Vec<u5> {
775 .map(|c| u5::try_from_u8(CHARSET_REV[*c as usize] as u8).unwrap())
780 fn test_parse_currency_prefix() {
783 assert_eq!("bc".parse::<Currency>(), Ok(Currency::Bitcoin));
784 assert_eq!("tb".parse::<Currency>(), Ok(Currency::BitcoinTestnet));
785 assert_eq!("bcrt".parse::<Currency>(), Ok(Currency::Regtest));
786 assert_eq!("sb".parse::<Currency>(), Ok(Currency::Simnet));
787 assert_eq!("something_else".parse::<Currency>(), Err(ParseError::UnknownCurrency))
791 fn test_parse_int_from_bytes_be() {
792 use de::parse_int_be;
794 assert_eq!(parse_int_be::<u32, u8>(&[1, 2, 3, 4], 256), Some(16909060));
795 assert_eq!(parse_int_be::<u32, u8>(&[1, 3], 32), Some(35));
796 assert_eq!(parse_int_be::<u32, u8>(&[255, 255, 255, 255], 256), Some(4294967295));
797 assert_eq!(parse_int_be::<u32, u8>(&[1, 0, 0, 0, 0], 256), None);
801 fn test_parse_sha256_hash() {
803 use bech32::FromBase32;
805 let input = from_bech32(
806 "qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypq".as_bytes()
809 let hash = sha256::Hash::from_hex(
810 "0001020304050607080900010203040506070809000102030405060708090102"
812 let expected = Ok(Sha256(hash));
814 assert_eq!(Sha256::from_base32(&input), expected);
816 // make sure hashes of unknown length get skipped
817 let input_unexpected_length = from_bech32(
818 "qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypyq".as_bytes()
820 assert_eq!(Sha256::from_base32(&input_unexpected_length), Err(ParseError::Skip));
824 fn test_parse_description() {
826 use bech32::FromBase32;
828 let input = from_bech32("xysxxatsyp3k7enxv4js".as_bytes());
829 let expected = Ok(Description::new("1 cup coffee".to_owned()).unwrap());
830 assert_eq!(Description::from_base32(&input), expected);
834 fn test_parse_payee_pub_key() {
836 use bech32::FromBase32;
838 let input = from_bech32("q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66".as_bytes());
840 0x03, 0xe7, 0x15, 0x6a, 0xe3, 0x3b, 0x0a, 0x20, 0x8d, 0x07, 0x44, 0x19, 0x91, 0x63,
841 0x17, 0x7e, 0x90, 0x9e, 0x80, 0x17, 0x6e, 0x55, 0xd9, 0x7a, 0x2f, 0x22, 0x1e, 0xde,
842 0x0f, 0x93, 0x4d, 0xd9, 0xad
844 let expected = Ok(PayeePubKey(
845 PublicKey::from_slice(&pk_bytes[..]).unwrap()
848 assert_eq!(PayeePubKey::from_base32(&input), expected);
851 let input_unexpected_length = from_bech32(
852 "q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhvq".as_bytes()
854 assert_eq!(PayeePubKey::from_base32(&input_unexpected_length), Err(ParseError::Skip));
858 fn test_parse_expiry_time() {
860 use bech32::FromBase32;
862 let input = from_bech32("pu".as_bytes());
863 let expected = Ok(ExpiryTime::from_seconds(60).unwrap());
864 assert_eq!(ExpiryTime::from_base32(&input), expected);
866 let input_too_large = from_bech32("sqqqqqqqqqqqq".as_bytes());
867 assert_eq!(ExpiryTime::from_base32(&input_too_large), Err(ParseError::IntegerOverflowError));
871 fn test_parse_min_final_cltv_expiry() {
872 use ::MinFinalCltvExpiry;
873 use bech32::FromBase32;
875 let input = from_bech32("pr".as_bytes());
876 let expected = Ok(MinFinalCltvExpiry(35));
878 assert_eq!(MinFinalCltvExpiry::from_base32(&input), expected);
882 fn test_parse_fallback() {
884 use bech32::FromBase32;
888 from_bech32("3x9et2e20v6pu37c5d9vax37wxq72un98".as_bytes()),
889 Ok(Fallback::PubKeyHash([
890 0x31, 0x72, 0xb5, 0x65, 0x4f, 0x66, 0x83, 0xc8, 0xfb, 0x14, 0x69, 0x59, 0xd3,
891 0x47, 0xce, 0x30, 0x3c, 0xae, 0x4c, 0xa7
895 from_bech32("j3a24vwu6r8ejrss3axul8rxldph2q7z9".as_bytes()),
896 Ok(Fallback::ScriptHash([
897 0x8f, 0x55, 0x56, 0x3b, 0x9a, 0x19, 0xf3, 0x21, 0xc2, 0x11, 0xe9, 0xb9, 0xf3,
898 0x8c, 0xdf, 0x68, 0x6e, 0xa0, 0x78, 0x45
902 from_bech32("qw508d6qejxtdg4y5r3zarvary0c5xw7k".as_bytes()),
903 Ok(Fallback::SegWitProgram {
904 version: u5::try_from_u8(0).unwrap(),
905 program: Vec::from(&[
906 0x75u8, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, 0x45,
907 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
912 vec![u5::try_from_u8(21).unwrap(); 41],
913 Err(ParseError::Skip)
917 Err(ParseError::UnexpectedEndOfTaggedFields)
920 vec![u5::try_from_u8(1).unwrap(); 81],
921 Err(ParseError::InvalidSegWitProgramLength)
924 vec![u5::try_from_u8(17).unwrap(); 1],
925 Err(ParseError::InvalidPubKeyHashLength)
928 vec![u5::try_from_u8(18).unwrap(); 1],
929 Err(ParseError::InvalidScriptHashLength)
933 for (input, expected) in cases.into_iter() {
934 assert_eq!(Fallback::from_base32(&input), expected);
939 fn test_parse_route() {
940 use lightning::routing::network_graph::RoutingFees;
941 use lightning::routing::router::RouteHintHop;
943 use bech32::FromBase32;
944 use de::parse_int_be;
946 let input = from_bech32(
947 "q20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqa\
948 fqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzq".as_bytes()
951 let mut expected = Vec::<RouteHintHop>::new();
952 expected.push(RouteHintHop {
953 src_node_id: PublicKey::from_slice(
955 0x02u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
956 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
957 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
960 short_channel_id: parse_int_be(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08], 256).expect("short chan ID slice too big?"),
963 proportional_millionths: 20,
965 cltv_expiry_delta: 3,
966 htlc_minimum_msat: None,
967 htlc_maximum_msat: None
969 expected.push(RouteHintHop {
970 src_node_id: PublicKey::from_slice(
972 0x03u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
973 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
974 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
977 short_channel_id: parse_int_be(&[0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a], 256).expect("short chan ID slice too big?"),
980 proportional_millionths: 30,
982 cltv_expiry_delta: 4,
983 htlc_minimum_msat: None,
984 htlc_maximum_msat: None
987 assert_eq!(Route::from_base32(&input), Ok(Route(expected)));
990 Route::from_base32(&[u5::try_from_u8(0).unwrap(); 40][..]),
991 Err(ParseError::UnexpectedEndOfTaggedFields)
996 fn test_payment_secret_deserialization() {
997 use bech32::CheckBase32;
998 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
1000 use {SiPrefix, SignedRawInvoice, Signature, RawInvoice, RawTaggedField, RawHrp, RawDataPart,
1001 Currency, Sha256, PositiveTimestamp};
1003 assert_eq!( // BOLT 11 payment secret invoice. The unknown fields are invoice features.
1004 "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqsq67gye39hfg3zd8rgc80k32tvy9xk2xunwm5lzexnvpx6fd77en8qaq424dxgt56cag2dpt359k3ssyhetktkpqh24jqnjyw6uqd08sgptq44qu".parse(),
1005 Ok(SignedRawInvoice {
1006 raw_invoice: RawInvoice {
1008 currency: Currency::Bitcoin,
1009 raw_amount: Some(25),
1010 si_prefix: Some(SiPrefix::Milli)
1013 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1014 tagged_fields: vec ! [
1015 PaymentHash(Sha256(sha256::Hash::from_hex(
1016 "0001020304050607080900010203040506070809000102030405060708090102"
1017 ).unwrap())).into(),
1018 Description(::Description::new("coffee beans".to_owned()).unwrap()).into(),
1019 PaymentSecret(::PaymentSecret([17; 32])).into(),
1020 RawTaggedField::UnknownSemantics(vec![5, 0, 20, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1021 0, 0, 0, 0, 1, 0, 16,
1022 0].check_base32().unwrap())],
1025 hash: [0xb1, 0x96, 0x46, 0xc3, 0xbc, 0x56, 0x76, 0x1d, 0x20, 0x65, 0x6e, 0x0e, 0x32,
1026 0xec, 0xd2, 0x69, 0x27, 0xb7, 0x62, 0x6e, 0x2a, 0x8b, 0xe6, 0x97, 0x71, 0x9f,
1027 0xf8, 0x7e, 0x44, 0x54, 0x55, 0xb9],
1028 signature: Signature(RecoverableSignature::from_compact(
1029 &[0xd7, 0x90, 0x4c, 0xc4, 0xb7, 0x4a, 0x22, 0x26, 0x9c, 0x68, 0xc1, 0xdf, 0x68,
1030 0xa9, 0x6c, 0x21, 0x4d, 0x65, 0x1b, 0x93, 0x76, 0xe9, 0xf1, 0x64, 0xd3, 0x60,
1031 0x4d, 0xa4, 0xb7, 0xde, 0xcc, 0xce, 0x0e, 0x82, 0xaa, 0xab, 0x4c, 0x85, 0xd3,
1032 0x58, 0xea, 0x14, 0xd0, 0xae, 0x34, 0x2d, 0xa3, 0x08, 0x12, 0xf9, 0x5d, 0x97,
1033 0x60, 0x82, 0xea, 0xac, 0x81, 0x39, 0x11, 0xda, 0xe0, 0x1a, 0xf3, 0xc1],
1034 RecoveryId::from_i32(1).unwrap()
1041 fn test_raw_signed_invoice_deserialization() {
1043 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
1044 use {SignedRawInvoice, Signature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256,
1048 "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmw\
1049 wd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9\
1050 ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w".parse(),
1051 Ok(SignedRawInvoice {
1052 raw_invoice: RawInvoice {
1054 currency: Currency::Bitcoin,
1059 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1060 tagged_fields: vec ! [
1061 PaymentHash(Sha256(sha256::Hash::from_hex(
1062 "0001020304050607080900010203040506070809000102030405060708090102"
1063 ).unwrap())).into(),
1066 "Please consider supporting this project".to_owned()
1073 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27,
1074 0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
1075 0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
1077 signature: Signature(RecoverableSignature::from_compact(
1079 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
1080 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
1081 0x4e, 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f,
1082 0x42, 0x5f, 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad,
1083 0x0d, 0x6e, 0x35, 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9,
1084 0xaa, 0xb1, 0x5e, 0x57, 0x38, 0xb1, 0x1f, 0x12, 0x7f
1086 RecoveryId::from_i32(0).unwrap()