lightning_invoice/
de.rs

1use alloc::string;
2#[cfg(not(feature = "std"))]
3use core::convert::TryFrom;
4use core::fmt;
5use core::fmt::{Display, Formatter};
6use core::num::ParseIntError;
7use core::str::FromStr;
8#[cfg(feature = "std")]
9use std::error;
10
11use bech32::primitives::decode::{CheckedHrpstring, CheckedHrpstringError};
12use bech32::{Fe32, Fe32IterExt};
13
14use crate::prelude::*;
15use crate::Bolt11Bech32;
16use bitcoin::hashes::sha256;
17use bitcoin::hashes::Hash;
18use bitcoin::{PubkeyHash, ScriptHash, WitnessVersion};
19use lightning_types::payment::PaymentSecret;
20use lightning_types::routing::{RouteHint, RouteHintHop, RoutingFees};
21
22use bitcoin::secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
23use bitcoin::secp256k1::PublicKey;
24
25use super::{
26	constants, Bolt11Invoice, Bolt11InvoiceFeatures, Bolt11InvoiceSignature, Bolt11ParseError,
27	Bolt11SemanticError, Currency, Description, ExpiryTime, Fallback, MinFinalCltvExpiryDelta,
28	ParseOrSemanticError, PayeePubKey, PositiveTimestamp, PrivateRoute, RawBolt11Invoice,
29	RawDataPart, RawHrp, RawTaggedField, Sha256, SiPrefix, SignedRawBolt11Invoice, TaggedField,
30};
31
32use self::hrp_sm::parse_hrp;
33
34/// Trait for parsing/converting base32 slice.
35pub trait FromBase32: Sized {
36	/// The associated error which can be returned from parsing (e.g. because of bad padding).
37	type Err;
38
39	/// Convert a base32 slice to `Self`.
40	fn from_base32(b32: &[Fe32]) -> Result<Self, Self::Err>;
41}
42
43// FromBase32 implementations are here, because the trait is in this module.
44
45impl FromBase32 for Vec<u8> {
46	type Err = Bolt11ParseError;
47
48	fn from_base32(data: &[Fe32]) -> Result<Self, Self::Err> {
49		Ok(data.iter().copied().fes_to_bytes().collect::<Self>())
50	}
51}
52
53impl<const N: usize> FromBase32 for [u8; N] {
54	type Err = Bolt11ParseError;
55
56	fn from_base32(data: &[Fe32]) -> Result<Self, Self::Err> {
57		let mut res_arr = [0; N];
58		// Do in a for loop to place in the array directly, not using `collect`
59		let mut count = 0;
60		for elem in data.iter().copied().fes_to_bytes() {
61			if count >= N {
62				// too many elements
63				count += 1;
64				break;
65			}
66			res_arr[count] = elem;
67			count += 1;
68		}
69		if count != N {
70			return Err(Bolt11ParseError::InvalidSliceLength(count, N, "<[u8; N]>"));
71		}
72		Ok(res_arr)
73	}
74}
75
76impl FromBase32 for PaymentSecret {
77	type Err = Bolt11ParseError;
78
79	fn from_base32(field_data: &[Fe32]) -> Result<Self, Self::Err> {
80		if field_data.len() != 52 {
81			return Err(Bolt11ParseError::InvalidSliceLength(
82				field_data.len(),
83				52,
84				"PaymentSecret",
85			));
86		}
87		let data_bytes = <[u8; 32]>::from_base32(field_data)?;
88		Ok(PaymentSecret(data_bytes))
89	}
90}
91
92impl FromBase32 for Bolt11InvoiceFeatures {
93	type Err = Bolt11ParseError;
94
95	/// Convert to byte values, by packing the 5-bit groups,
96	/// putting the 5-bit values from left to-right (reverse order),
97	/// starting from the rightmost bit,
98	/// and taking the resulting 8-bit values (right to left),
99	/// with the leading 0's skipped.
100	fn from_base32(field_data: &[Fe32]) -> Result<Self, Self::Err> {
101		// Fe32 conversion cannot be used, because this unpacks from right, right-to-left
102		// Carry bits, 0, 1, 2, 3, or 4 bits
103		let mut carry_bits = 0;
104		let mut carry = 0u8;
105		let expected_raw_length = (field_data.len() * 5 + 7) / 8;
106		let mut output = Vec::<u8>::with_capacity(expected_raw_length);
107
108		// Iterate over input in reverse
109		for curr_in in field_data.iter().rev() {
110			let curr_in_as_u8 = curr_in.to_u8();
111			if carry_bits >= 3 {
112				// we have a new full byte -- 3, 4 or 5 carry bits, plus 5 new ones
113				// For combining with carry '|', '^', or '+' can be used (disjoint bit positions)
114				let next = carry + (curr_in_as_u8 << carry_bits);
115				output.push(next);
116				carry = curr_in_as_u8 >> (8 - carry_bits);
117				carry_bits -= 3; // added 5, removed 8
118			} else {
119				// only 0, 1, or 2 carry bits,  plus 5 new ones
120				carry += curr_in_as_u8 << carry_bits;
121				carry_bits += 5;
122			}
123		}
124
125		// No more inputs, output remaining (if any)
126		if carry_bits > 0 {
127			output.push(carry);
128		}
129
130		// This is to double check the estimated length and
131		// satisfying mutation test on the capacity, which is mutatable
132		debug_assert_eq!(output.len(), expected_raw_length);
133
134		// Trim the highest feature bits
135		while !output.is_empty() && output[output.len() - 1] == 0 {
136			output.pop();
137		}
138
139		Ok(Bolt11InvoiceFeatures::from_le_bytes(output))
140	}
141}
142
143/// State machine to parse the hrp
144mod hrp_sm {
145	use core::ops::Range;
146
147	#[derive(PartialEq, Eq, Debug)]
148	enum States {
149		Start,
150		ParseL,
151		ParseN,
152		ParseCurrencyPrefix,
153		ParseAmountNumber,
154		ParseAmountSiPrefix,
155	}
156
157	impl States {
158		fn next_state(&self, read_byte: u8) -> Result<States, super::Bolt11ParseError> {
159			let read_symbol = match char::from_u32(read_byte.into()) {
160				Some(symb) if symb.is_ascii() => symb,
161				_ => return Err(super::Bolt11ParseError::MalformedHRP),
162			};
163			match *self {
164				States::Start => {
165					if read_symbol == 'l' {
166						Ok(States::ParseL)
167					} else {
168						Err(super::Bolt11ParseError::MalformedHRP)
169					}
170				},
171				States::ParseL => {
172					if read_symbol == 'n' {
173						Ok(States::ParseN)
174					} else {
175						Err(super::Bolt11ParseError::MalformedHRP)
176					}
177				},
178				States::ParseN => {
179					if !read_symbol.is_numeric() {
180						Ok(States::ParseCurrencyPrefix)
181					} else {
182						Ok(States::ParseAmountNumber)
183					}
184				},
185				States::ParseCurrencyPrefix => {
186					if !read_symbol.is_numeric() {
187						Ok(States::ParseCurrencyPrefix)
188					} else {
189						Ok(States::ParseAmountNumber)
190					}
191				},
192				States::ParseAmountNumber => {
193					if read_symbol.is_numeric() {
194						Ok(States::ParseAmountNumber)
195					} else if ['m', 'u', 'n', 'p'].contains(&read_symbol) {
196						Ok(States::ParseAmountSiPrefix)
197					} else {
198						Err(super::Bolt11ParseError::UnknownSiPrefix)
199					}
200				},
201				States::ParseAmountSiPrefix => Err(super::Bolt11ParseError::MalformedHRP),
202			}
203		}
204
205		fn is_final(&self) -> bool {
206			!(*self == States::ParseL || *self == States::ParseN)
207		}
208	}
209
210	struct StateMachine {
211		state: States,
212		position: usize,
213		currency_prefix: Option<Range<usize>>,
214		amount_number: Option<Range<usize>>,
215		amount_si_prefix: Option<Range<usize>>,
216	}
217
218	impl StateMachine {
219		fn new() -> StateMachine {
220			StateMachine {
221				state: States::Start,
222				position: 0,
223				currency_prefix: None,
224				amount_number: None,
225				amount_si_prefix: None,
226			}
227		}
228
229		fn update_range(range: &mut Option<Range<usize>>, position: usize) {
230			let new_range = match *range {
231				None => Range { start: position, end: position + 1 },
232				Some(ref r) => Range { start: r.start, end: r.end + 1 },
233			};
234			*range = Some(new_range);
235		}
236
237		fn step(&mut self, c: u8) -> Result<(), super::Bolt11ParseError> {
238			let next_state = self.state.next_state(c)?;
239			match next_state {
240				States::ParseCurrencyPrefix => {
241					StateMachine::update_range(&mut self.currency_prefix, self.position)
242				},
243				States::ParseAmountNumber => {
244					StateMachine::update_range(&mut self.amount_number, self.position)
245				},
246				States::ParseAmountSiPrefix => {
247					StateMachine::update_range(&mut self.amount_si_prefix, self.position)
248				},
249				_ => {},
250			}
251
252			self.position += 1;
253			self.state = next_state;
254			Ok(())
255		}
256
257		fn is_final(&self) -> bool {
258			self.state.is_final()
259		}
260
261		fn currency_prefix(&self) -> &Option<Range<usize>> {
262			&self.currency_prefix
263		}
264
265		fn amount_number(&self) -> &Option<Range<usize>> {
266			&self.amount_number
267		}
268
269		fn amount_si_prefix(&self) -> &Option<Range<usize>> {
270			&self.amount_si_prefix
271		}
272	}
273
274	pub fn parse_hrp(input: &str) -> Result<(&str, &str, &str), super::Bolt11ParseError> {
275		let mut sm = StateMachine::new();
276		for c in input.bytes() {
277			sm.step(c)?;
278		}
279
280		if !sm.is_final() {
281			return Err(super::Bolt11ParseError::MalformedHRP);
282		}
283
284		let currency = sm.currency_prefix().clone().map(|r| &input[r]).unwrap_or("");
285		let amount = sm.amount_number().clone().map(|r| &input[r]).unwrap_or("");
286		let si = sm.amount_si_prefix().clone().map(|r| &input[r]).unwrap_or("");
287
288		Ok((currency, amount, si))
289	}
290}
291
292impl FromStr for super::Currency {
293	type Err = Bolt11ParseError;
294
295	fn from_str(currency_prefix: &str) -> Result<Self, Bolt11ParseError> {
296		match currency_prefix {
297			"bc" => Ok(Currency::Bitcoin),
298			"tb" => Ok(Currency::BitcoinTestnet),
299			"bcrt" => Ok(Currency::Regtest),
300			"sb" => Ok(Currency::Simnet),
301			"tbs" => Ok(Currency::Signet),
302			_ => Err(Bolt11ParseError::UnknownCurrency),
303		}
304	}
305}
306
307impl FromStr for SiPrefix {
308	type Err = Bolt11ParseError;
309
310	fn from_str(currency_prefix: &str) -> Result<Self, Bolt11ParseError> {
311		use crate::SiPrefix::*;
312		match currency_prefix {
313			"m" => Ok(Milli),
314			"u" => Ok(Micro),
315			"n" => Ok(Nano),
316			"p" => Ok(Pico),
317			_ => Err(Bolt11ParseError::UnknownSiPrefix),
318		}
319	}
320}
321
322/// ```
323/// use lightning_invoice::Bolt11Invoice;
324///
325///
326/// let invoice = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\
327/// h2pu5qc7lgq0xs578ngs6s0s68ua4h7cvspp5q6rmq35js88zp5dvwrv9m459tnk2zunwj5jalqtyxqulh0l\
328/// 5gflssp5nf55ny5gcrfl30xuhzj3nphgj27rstekmr9fw3ny5989s300gyus9qyysgqcqpcrzjqw2sxwe993\
329/// h5pcm4dxzpvttgza8zhkqxpgffcrf5v25nwpr3cmfg7z54kuqq8rgqqqqqqqq2qqqqq9qq9qrzjqd0ylaqcl\
330/// j9424x9m8h2vcukcgnm6s56xfgu3j78zyqzhgs4hlpzvznlugqq9vsqqqqqqqlgqqqqqeqq9qrzjqwldmj9d\
331/// ha74df76zhx6l9we0vjdquygcdt3kssupehe64g6yyp5yz5rhuqqwccqqyqqqqlgqqqqjcqq9qrzjqf9e58a\
332/// guqr0rcun0ajlvmzq3ek63cw2w282gv3z5uupmuwvgjtq2z55qsqqg6qqqyqqqrtnqqqzq3cqygrzjqvphms\
333/// ywntrrhqjcraumvc4y6r8v4z5v593trte429v4hredj7ms5z52usqq9ngqqqqqqqlgqqqqqqgq9qrzjq2v0v\
334/// p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\
335/// 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
336/// j5r6drg6k6zcqj0fcwg";
337///
338/// assert!(invoice.parse::<Bolt11Invoice>().is_ok());
339/// ```
340impl FromStr for Bolt11Invoice {
341	type Err = ParseOrSemanticError;
342
343	fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
344		let signed = s.parse::<SignedRawBolt11Invoice>()?;
345		Ok(Bolt11Invoice::from_signed(signed)?)
346	}
347}
348
349/// ```
350/// use lightning_invoice::*;
351///
352/// let invoice = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\
353/// h2pu5qc7lgq0xs578ngs6s0s68ua4h7cvspp5q6rmq35js88zp5dvwrv9m459tnk2zunwj5jalqtyxqulh0l\
354/// 5gflssp5nf55ny5gcrfl30xuhzj3nphgj27rstekmr9fw3ny5989s300gyus9qyysgqcqpcrzjqw2sxwe993\
355/// h5pcm4dxzpvttgza8zhkqxpgffcrf5v25nwpr3cmfg7z54kuqq8rgqqqqqqqq2qqqqq9qq9qrzjqd0ylaqcl\
356/// j9424x9m8h2vcukcgnm6s56xfgu3j78zyqzhgs4hlpzvznlugqq9vsqqqqqqqlgqqqqqeqq9qrzjqwldmj9d\
357/// ha74df76zhx6l9we0vjdquygcdt3kssupehe64g6yyp5yz5rhuqqwccqqyqqqqlgqqqqjcqq9qrzjqf9e58a\
358/// guqr0rcun0ajlvmzq3ek63cw2w282gv3z5uupmuwvgjtq2z55qsqqg6qqqyqqqrtnqqqzq3cqygrzjqvphms\
359/// ywntrrhqjcraumvc4y6r8v4z5v593trte429v4hredj7ms5z52usqq9ngqqqqqqqlgqqqqqqgq9qrzjq2v0v\
360/// p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\
361/// 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
362/// j5r6drg6k6zcqj0fcwg";
363///
364/// let parsed_1 = invoice.parse::<Bolt11Invoice>();
365///
366/// let parsed_2 = match invoice.parse::<SignedRawBolt11Invoice>() {
367/// 	Ok(signed) => match Bolt11Invoice::from_signed(signed) {
368/// 		Ok(invoice) => Ok(invoice),
369/// 		Err(e) => Err(ParseOrSemanticError::SemanticError(e)),
370/// 	},
371/// 	Err(e) => Err(ParseOrSemanticError::ParseError(e)),
372/// };
373///
374/// assert!(parsed_1.is_ok());
375/// assert_eq!(parsed_1, parsed_2);
376/// ```
377impl FromStr for SignedRawBolt11Invoice {
378	type Err = Bolt11ParseError;
379
380	fn from_str(s: &str) -> Result<Self, Self::Err> {
381		let parsed = CheckedHrpstring::new::<Bolt11Bech32>(s)?;
382		let hrp = parsed.hrp();
383		// Access original non-packed 32 byte values (as Fe32s)
384		// Note: the type argument is needed due to the API peculiarities, but it's not used
385		let data: Vec<_> = parsed.fe32_iter::<&mut dyn Iterator<Item = u8>>().collect();
386
387		const SIGNATURE_LEN_5: usize = 104; // number of the 5-bit values (equals to 65 bytes)
388		if data.len() < SIGNATURE_LEN_5 {
389			return Err(Bolt11ParseError::TooShortDataPart);
390		}
391
392		let raw_hrp: RawHrp = hrp.to_string().to_lowercase().parse()?;
393		let data_part = RawDataPart::from_base32(&data[..data.len() - SIGNATURE_LEN_5])?;
394		let raw_invoice = RawBolt11Invoice { hrp: raw_hrp, data: data_part };
395		let hash = raw_invoice.signable_hash();
396
397		Ok(SignedRawBolt11Invoice {
398			raw_invoice,
399			hash,
400			signature: Bolt11InvoiceSignature::from_base32(&data[data.len() - SIGNATURE_LEN_5..])?,
401		})
402	}
403}
404
405impl FromStr for RawHrp {
406	type Err = Bolt11ParseError;
407
408	fn from_str(hrp: &str) -> Result<Self, <Self as FromStr>::Err> {
409		let parts = parse_hrp(hrp)?;
410
411		let currency = parts.0.parse::<Currency>()?;
412
413		let amount = if !parts.1.is_empty() { Some(parts.1.parse::<u64>()?) } else { None };
414
415		let si_prefix: Option<SiPrefix> = if parts.2.is_empty() {
416			None
417		} else {
418			let si: SiPrefix = parts.2.parse()?;
419			if let Some(amt) = amount {
420				if amt.checked_mul(si.multiplier()).is_none() {
421					return Err(Bolt11ParseError::IntegerOverflowError);
422				}
423			}
424			Some(si)
425		};
426
427		Ok(RawHrp { currency, raw_amount: amount, si_prefix })
428	}
429}
430
431impl FromBase32 for RawDataPart {
432	type Err = Bolt11ParseError;
433
434	fn from_base32(data: &[Fe32]) -> Result<Self, Self::Err> {
435		const TIMESTAMP_LEN: usize = 7;
436		if data.len() < TIMESTAMP_LEN {
437			return Err(Bolt11ParseError::TooShortDataPart);
438		}
439
440		let timestamp = PositiveTimestamp::from_base32(&data[0..TIMESTAMP_LEN])?;
441		let tagged = parse_tagged_parts(&data[TIMESTAMP_LEN..])?;
442
443		Ok(RawDataPart { timestamp, tagged_fields: tagged })
444	}
445}
446
447impl FromBase32 for PositiveTimestamp {
448	type Err = Bolt11ParseError;
449
450	fn from_base32(b32: &[Fe32]) -> Result<Self, Self::Err> {
451		if b32.len() != 7 {
452			return Err(Bolt11ParseError::InvalidSliceLength(b32.len(), 7, "PositiveTimestamp"));
453		}
454		let timestamp: u64 = parse_u64_be(b32).expect("7*5bit < 64bit, no overflow possible");
455		match PositiveTimestamp::from_unix_timestamp(timestamp) {
456			Ok(t) => Ok(t),
457			Err(_) => unreachable!(),
458		}
459	}
460}
461
462impl FromBase32 for Bolt11InvoiceSignature {
463	type Err = Bolt11ParseError;
464	fn from_base32(signature: &[Fe32]) -> Result<Self, Self::Err> {
465		if signature.len() != 104 {
466			return Err(Bolt11ParseError::InvalidSliceLength(
467				signature.len(),
468				104,
469				"Bolt11InvoiceSignature",
470			));
471		}
472		let recoverable_signature_bytes = <[u8; 65]>::from_base32(signature)?;
473		let signature = &recoverable_signature_bytes[0..64];
474		let recovery_id = RecoveryId::from_i32(recoverable_signature_bytes[64] as i32)?;
475
476		Ok(Bolt11InvoiceSignature(RecoverableSignature::from_compact(signature, recovery_id)?))
477	}
478}
479
480macro_rules! define_parse_int_be {
481	($name: ident, $ty: ty) => {
482		fn $name(digits: &[Fe32]) -> Option<$ty> {
483			digits.iter().fold(Some(Default::default()), |acc, b| {
484				acc.and_then(|x| x.checked_mul(32))
485					.and_then(|x| x.checked_add((Into::<u8>::into(*b)).into()))
486			})
487		}
488	};
489}
490define_parse_int_be!(parse_u16_be, u16);
491define_parse_int_be!(parse_u64_be, u64);
492
493fn parse_tagged_parts(data: &[Fe32]) -> Result<Vec<RawTaggedField>, Bolt11ParseError> {
494	let mut parts = Vec::<RawTaggedField>::new();
495	let mut data = data;
496
497	while !data.is_empty() {
498		if data.len() < 3 {
499			return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields);
500		}
501
502		// Ignore tag at data[0], it will be handled in the TaggedField parsers and
503		// parse the length to find the end of the tagged field's data
504		let len = parse_u16_be(&data[1..3]).expect("can't overflow") as usize;
505		let last_element = 3 + len;
506
507		if data.len() < last_element {
508			return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields);
509		}
510
511		// Get the tagged field's data slice
512		let field = &data[0..last_element];
513
514		// Set data slice to remaining data
515		data = &data[last_element..];
516
517		match TaggedField::from_base32(field) {
518			Ok(field) => parts.push(RawTaggedField::KnownSemantics(field)),
519			Err(Bolt11ParseError::Skip)
520			| Err(Bolt11ParseError::InvalidSliceLength(_, _, _))
521			| Err(Bolt11ParseError::Bech32Error(_)) => {
522				parts.push(RawTaggedField::UnknownSemantics(field.into()))
523			},
524			Err(e) => return Err(e),
525		}
526	}
527	Ok(parts)
528}
529
530impl FromBase32 for TaggedField {
531	type Err = Bolt11ParseError;
532
533	fn from_base32(field: &[Fe32]) -> Result<TaggedField, Bolt11ParseError> {
534		if field.len() < 3 {
535			return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields);
536		}
537
538		let tag = field[0];
539		let field_data = &field[3..];
540
541		match tag.to_u8() {
542			constants::TAG_PAYMENT_HASH => {
543				Ok(TaggedField::PaymentHash(Sha256::from_base32(field_data)?))
544			},
545			constants::TAG_DESCRIPTION => {
546				Ok(TaggedField::Description(Description::from_base32(field_data)?))
547			},
548			constants::TAG_PAYEE_PUB_KEY => {
549				Ok(TaggedField::PayeePubKey(PayeePubKey::from_base32(field_data)?))
550			},
551			constants::TAG_DESCRIPTION_HASH => {
552				Ok(TaggedField::DescriptionHash(Sha256::from_base32(field_data)?))
553			},
554			constants::TAG_EXPIRY_TIME => {
555				Ok(TaggedField::ExpiryTime(ExpiryTime::from_base32(field_data)?))
556			},
557			constants::TAG_MIN_FINAL_CLTV_EXPIRY_DELTA => Ok(TaggedField::MinFinalCltvExpiryDelta(
558				MinFinalCltvExpiryDelta::from_base32(field_data)?,
559			)),
560			constants::TAG_FALLBACK => {
561				Ok(TaggedField::Fallback(Fallback::from_base32(field_data)?))
562			},
563			constants::TAG_PRIVATE_ROUTE => {
564				Ok(TaggedField::PrivateRoute(PrivateRoute::from_base32(field_data)?))
565			},
566			constants::TAG_PAYMENT_SECRET => {
567				Ok(TaggedField::PaymentSecret(PaymentSecret::from_base32(field_data)?))
568			},
569			constants::TAG_PAYMENT_METADATA => {
570				Ok(TaggedField::PaymentMetadata(Vec::<u8>::from_base32(field_data)?))
571			},
572			constants::TAG_FEATURES => {
573				Ok(TaggedField::Features(Bolt11InvoiceFeatures::from_base32(field_data)?))
574			},
575			_ => {
576				// "A reader MUST skip over unknown fields"
577				Err(Bolt11ParseError::Skip)
578			},
579		}
580	}
581}
582
583impl FromBase32 for Sha256 {
584	type Err = Bolt11ParseError;
585
586	fn from_base32(field_data: &[Fe32]) -> Result<Sha256, Bolt11ParseError> {
587		if field_data.len() != 52 {
588			// "A reader MUST skip over […] a p, [or] h […] field that does not have data_length 52 […]."
589			Err(Bolt11ParseError::Skip)
590		} else {
591			Ok(Sha256(
592				sha256::Hash::from_slice(&<[u8; 32]>::from_base32(field_data)?)
593					.expect("length was checked before (52 u5 -> 32 u8)"),
594			))
595		}
596	}
597}
598
599impl FromBase32 for Description {
600	type Err = Bolt11ParseError;
601
602	fn from_base32(field_data: &[Fe32]) -> Result<Description, Bolt11ParseError> {
603		let bytes = Vec::<u8>::from_base32(field_data)?;
604		let description = String::from_utf8(bytes)?;
605		Ok(Description::new(description)
606			.expect("Max len is 639=floor(1023*5/8) since the len field is only 10bits long"))
607	}
608}
609
610impl FromBase32 for PayeePubKey {
611	type Err = Bolt11ParseError;
612
613	fn from_base32(field_data: &[Fe32]) -> Result<PayeePubKey, Bolt11ParseError> {
614		if field_data.len() != 53 {
615			// "A reader MUST skip over […] a n […] field that does not have data_length 53 […]."
616			Err(Bolt11ParseError::Skip)
617		} else {
618			let data_bytes = <[u8; 33]>::from_base32(field_data)?;
619			let pub_key = PublicKey::from_slice(&data_bytes)?;
620			Ok(pub_key.into())
621		}
622	}
623}
624
625impl FromBase32 for ExpiryTime {
626	type Err = Bolt11ParseError;
627
628	fn from_base32(field_data: &[Fe32]) -> Result<ExpiryTime, Bolt11ParseError> {
629		match parse_u64_be(field_data).map(ExpiryTime::from_seconds) {
630			Some(t) => Ok(t),
631			None => Err(Bolt11ParseError::IntegerOverflowError),
632		}
633	}
634}
635
636impl FromBase32 for MinFinalCltvExpiryDelta {
637	type Err = Bolt11ParseError;
638
639	fn from_base32(field_data: &[Fe32]) -> Result<MinFinalCltvExpiryDelta, Bolt11ParseError> {
640		let expiry = parse_u64_be(field_data);
641		if let Some(expiry) = expiry {
642			Ok(MinFinalCltvExpiryDelta(expiry))
643		} else {
644			Err(Bolt11ParseError::IntegerOverflowError)
645		}
646	}
647}
648
649impl FromBase32 for Fallback {
650	type Err = Bolt11ParseError;
651
652	fn from_base32(field_data: &[Fe32]) -> Result<Fallback, Bolt11ParseError> {
653		if field_data.is_empty() {
654			return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields);
655		}
656
657		let version = field_data[0].to_u8();
658		let bytes = Vec::<u8>::from_base32(&field_data[1..])?;
659
660		match version {
661			0..=16 => {
662				if bytes.len() < 2 || bytes.len() > 40 {
663					return Err(Bolt11ParseError::InvalidSegWitProgramLength);
664				}
665				let version = WitnessVersion::try_from(version)
666					.expect("0 through 16 are valid SegWit versions");
667				Ok(Fallback::SegWitProgram { version, program: bytes })
668			},
669			17 => {
670				let pkh = match PubkeyHash::from_slice(&bytes) {
671					Ok(pkh) => pkh,
672					Err(_) => return Err(Bolt11ParseError::InvalidPubKeyHashLength),
673				};
674				Ok(Fallback::PubKeyHash(pkh))
675			},
676			18 => {
677				let sh = match ScriptHash::from_slice(&bytes) {
678					Ok(sh) => sh,
679					Err(_) => return Err(Bolt11ParseError::InvalidScriptHashLength),
680				};
681				Ok(Fallback::ScriptHash(sh))
682			},
683			_ => Err(Bolt11ParseError::Skip),
684		}
685	}
686}
687
688impl FromBase32 for PrivateRoute {
689	type Err = Bolt11ParseError;
690
691	fn from_base32(field_data: &[Fe32]) -> Result<PrivateRoute, Bolt11ParseError> {
692		let bytes = Vec::<u8>::from_base32(field_data)?;
693
694		if bytes.len() % 51 != 0 {
695			return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields);
696		}
697
698		let mut route_hops = Vec::with_capacity(bytes.len() / 51);
699
700		let mut bytes = bytes.as_slice();
701		while !bytes.is_empty() {
702			let hop_bytes = &bytes[0..51];
703			bytes = &bytes[51..];
704
705			let mut channel_id: [u8; 8] = Default::default();
706			channel_id.copy_from_slice(&hop_bytes[33..41]);
707
708			let hop = RouteHintHop {
709				src_node_id: PublicKey::from_slice(&hop_bytes[0..33])?,
710				short_channel_id: u64::from_be_bytes(channel_id),
711				fees: RoutingFees {
712					base_msat: u32::from_be_bytes(
713						hop_bytes[41..45].try_into().expect("slice too big?"),
714					),
715					proportional_millionths: u32::from_be_bytes(
716						hop_bytes[45..49].try_into().expect("slice too big?"),
717					),
718				},
719				cltv_expiry_delta: u16::from_be_bytes(
720					hop_bytes[49..51].try_into().expect("slice too big?"),
721				),
722				htlc_minimum_msat: None,
723				htlc_maximum_msat: None,
724			};
725
726			route_hops.push(hop);
727		}
728
729		Ok(PrivateRoute(RouteHint(route_hops)))
730	}
731}
732
733impl Display for Bolt11ParseError {
734	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
735		match *self {
736			// TODO: find a way to combine the first three arms (e as error::Error?)
737			Bolt11ParseError::Bech32Error(ref e) => {
738				write!(f, "Invalid bech32: {}", e)
739			},
740			Bolt11ParseError::ParseAmountError(ref e) => {
741				write!(f, "Invalid amount in hrp ({})", e)
742			},
743			Bolt11ParseError::MalformedSignature(ref e) => {
744				write!(f, "Invalid secp256k1 signature: {}", e)
745			},
746			Bolt11ParseError::DescriptionDecodeError(ref e) => {
747				write!(f, "Description is not a valid utf-8 string: {}", e)
748			},
749			Bolt11ParseError::InvalidSliceLength(ref len, ref expected, ref elemen) => {
750				write!(f, "Slice had length {} instead of {} for element {}", len, expected, elemen)
751			},
752			Bolt11ParseError::BadPrefix => f.write_str("did not begin with 'ln'"),
753			Bolt11ParseError::UnknownCurrency => f.write_str("currency code unknown"),
754			Bolt11ParseError::UnknownSiPrefix => f.write_str("unknown SI prefix"),
755			Bolt11ParseError::MalformedHRP => f.write_str("malformed human readable part"),
756			Bolt11ParseError::TooShortDataPart => {
757				f.write_str("data part too short (should be at least 111 bech32 chars long)")
758			},
759			Bolt11ParseError::UnexpectedEndOfTaggedFields => {
760				f.write_str("tagged fields part ended unexpectedly")
761			},
762			Bolt11ParseError::PaddingError => f.write_str("some data field had bad padding"),
763			Bolt11ParseError::IntegerOverflowError => {
764				f.write_str("parsed integer doesn't fit into receiving type")
765			},
766			Bolt11ParseError::InvalidSegWitProgramLength => {
767				f.write_str("fallback SegWit program is too long or too short")
768			},
769			Bolt11ParseError::InvalidPubKeyHashLength => {
770				f.write_str("fallback public key hash has a length unequal 20 bytes")
771			},
772			Bolt11ParseError::InvalidScriptHashLength => {
773				f.write_str("fallback script hash has a length unequal 32 bytes")
774			},
775			Bolt11ParseError::Skip => f.write_str(
776				"the tagged field has to be skipped because of an unexpected, but allowed property",
777			),
778		}
779	}
780}
781
782impl Display for ParseOrSemanticError {
783	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
784		match self {
785			ParseOrSemanticError::ParseError(err) => err.fmt(f),
786			ParseOrSemanticError::SemanticError(err) => err.fmt(f),
787		}
788	}
789}
790
791#[cfg(feature = "std")]
792impl error::Error for Bolt11ParseError {}
793
794#[cfg(feature = "std")]
795impl error::Error for ParseOrSemanticError {}
796
797macro_rules! from_error {
798	($my_error:expr, $extern_error:ty) => {
799		impl From<$extern_error> for Bolt11ParseError {
800			fn from(e: $extern_error) -> Self {
801				$my_error(e)
802			}
803		}
804	};
805}
806
807from_error!(Bolt11ParseError::MalformedSignature, bitcoin::secp256k1::Error);
808from_error!(Bolt11ParseError::ParseAmountError, ParseIntError);
809from_error!(Bolt11ParseError::DescriptionDecodeError, string::FromUtf8Error);
810
811impl From<CheckedHrpstringError> for Bolt11ParseError {
812	fn from(e: CheckedHrpstringError) -> Self {
813		Self::Bech32Error(e)
814	}
815}
816
817impl From<Bolt11ParseError> for ParseOrSemanticError {
818	fn from(e: Bolt11ParseError) -> Self {
819		ParseOrSemanticError::ParseError(e)
820	}
821}
822
823impl From<crate::Bolt11SemanticError> for ParseOrSemanticError {
824	fn from(e: Bolt11SemanticError) -> Self {
825		ParseOrSemanticError::SemanticError(e)
826	}
827}
828
829#[cfg(test)]
830mod test {
831	use super::FromBase32;
832	use crate::de::Bolt11ParseError;
833	use bech32::Fe32;
834	use bitcoin::hashes::sha256;
835	use bitcoin::secp256k1::PublicKey;
836	use std::str::FromStr;
837
838	const CHARSET_REV: [i8; 128] = [
839		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
840		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
841		-1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13,
842		25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1,
843		-1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, 3, 16, 11, 28,
844		12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
845	];
846
847	fn from_bech32(bytes_5b: &[u8]) -> Vec<Fe32> {
848		bytes_5b.iter().map(|c| Fe32::try_from(CHARSET_REV[*c as usize] as u8).unwrap()).collect()
849	}
850
851	#[test]
852	fn test_parse_currency_prefix() {
853		use crate::Currency;
854
855		assert_eq!("bc".parse::<Currency>(), Ok(Currency::Bitcoin));
856		assert_eq!("tb".parse::<Currency>(), Ok(Currency::BitcoinTestnet));
857		assert_eq!("bcrt".parse::<Currency>(), Ok(Currency::Regtest));
858		assert_eq!("sb".parse::<Currency>(), Ok(Currency::Simnet));
859		assert_eq!("tbs".parse::<Currency>(), Ok(Currency::Signet));
860		assert_eq!("something_else".parse::<Currency>(), Err(Bolt11ParseError::UnknownCurrency))
861	}
862
863	#[test]
864	fn test_parse_int_from_bytes_be() {
865		use crate::de::parse_u16_be;
866
867		assert_eq!(
868			parse_u16_be(&[
869				Fe32::try_from(1).unwrap(),
870				Fe32::try_from(2).unwrap(),
871				Fe32::try_from(3).unwrap(),
872				Fe32::try_from(4).unwrap(),
873			]),
874			Some(34916)
875		);
876		assert_eq!(
877			parse_u16_be(&[
878				Fe32::try_from(2).unwrap(),
879				Fe32::try_from(0).unwrap(),
880				Fe32::try_from(0).unwrap(),
881				Fe32::try_from(0).unwrap(),
882			]),
883			None
884		);
885	}
886
887	#[test]
888	fn test_parse_sha256_hash() {
889		use crate::Sha256;
890
891		let input = from_bech32("qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypq".as_bytes());
892
893		let hash = sha256::Hash::from_str(
894			"0001020304050607080900010203040506070809000102030405060708090102",
895		)
896		.unwrap();
897		let expected = Ok(Sha256(hash));
898
899		assert_eq!(Sha256::from_base32(&input), expected);
900
901		// make sure hashes of unknown length get skipped
902		let input_unexpected_length =
903			from_bech32("qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypyq".as_bytes());
904		assert_eq!(Sha256::from_base32(&input_unexpected_length), Err(Bolt11ParseError::Skip));
905	}
906
907	#[test]
908	fn test_parse_description() {
909		use crate::Description;
910
911		let input = from_bech32("xysxxatsyp3k7enxv4js".as_bytes());
912		let expected = Ok(Description::new("1 cup coffee".to_owned()).unwrap());
913		assert_eq!(Description::from_base32(&input), expected);
914	}
915
916	#[test]
917	fn test_parse_payee_pub_key() {
918		use crate::PayeePubKey;
919
920		let input = from_bech32("q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66".as_bytes());
921		let pk_bytes = [
922			0x03, 0xe7, 0x15, 0x6a, 0xe3, 0x3b, 0x0a, 0x20, 0x8d, 0x07, 0x44, 0x19, 0x91, 0x63,
923			0x17, 0x7e, 0x90, 0x9e, 0x80, 0x17, 0x6e, 0x55, 0xd9, 0x7a, 0x2f, 0x22, 0x1e, 0xde,
924			0x0f, 0x93, 0x4d, 0xd9, 0xad,
925		];
926		let expected = Ok(PayeePubKey(PublicKey::from_slice(&pk_bytes[..]).unwrap()));
927
928		assert_eq!(PayeePubKey::from_base32(&input), expected);
929
930		// expects 33 bytes
931		let input_unexpected_length =
932			from_bech32("q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhvq".as_bytes());
933		assert_eq!(PayeePubKey::from_base32(&input_unexpected_length), Err(Bolt11ParseError::Skip));
934	}
935
936	#[test]
937	fn test_parse_expiry_time() {
938		use crate::ExpiryTime;
939
940		let input = from_bech32("pu".as_bytes());
941		let expected = Ok(ExpiryTime::from_seconds(60));
942		assert_eq!(ExpiryTime::from_base32(&input), expected);
943
944		let input_too_large = from_bech32("sqqqqqqqqqqqq".as_bytes());
945		assert_eq!(
946			ExpiryTime::from_base32(&input_too_large),
947			Err(Bolt11ParseError::IntegerOverflowError)
948		);
949	}
950
951	#[test]
952	fn test_parse_min_final_cltv_expiry_delta() {
953		use crate::MinFinalCltvExpiryDelta;
954
955		let input = from_bech32("pr".as_bytes());
956		let expected = Ok(MinFinalCltvExpiryDelta(35));
957
958		assert_eq!(MinFinalCltvExpiryDelta::from_base32(&input), expected);
959	}
960
961	#[test]
962	fn test_parse_fallback() {
963		use crate::Fallback;
964		use bitcoin::hashes::Hash;
965		use bitcoin::{PubkeyHash, ScriptHash, WitnessVersion};
966
967		let cases = vec![
968			(
969				from_bech32("3x9et2e20v6pu37c5d9vax37wxq72un98".as_bytes()),
970				Ok(Fallback::PubKeyHash(
971					PubkeyHash::from_slice(&[
972						0x31, 0x72, 0xb5, 0x65, 0x4f, 0x66, 0x83, 0xc8, 0xfb, 0x14, 0x69, 0x59,
973						0xd3, 0x47, 0xce, 0x30, 0x3c, 0xae, 0x4c, 0xa7,
974					])
975					.unwrap(),
976				)),
977			),
978			(
979				from_bech32("j3a24vwu6r8ejrss3axul8rxldph2q7z9".as_bytes()),
980				Ok(Fallback::ScriptHash(
981					ScriptHash::from_slice(&[
982						0x8f, 0x55, 0x56, 0x3b, 0x9a, 0x19, 0xf3, 0x21, 0xc2, 0x11, 0xe9, 0xb9,
983						0xf3, 0x8c, 0xdf, 0x68, 0x6e, 0xa0, 0x78, 0x45,
984					])
985					.unwrap(),
986				)),
987			),
988			(
989				from_bech32("qw508d6qejxtdg4y5r3zarvary0c5xw7k".as_bytes()),
990				Ok(Fallback::SegWitProgram {
991					version: WitnessVersion::V0,
992					program: Vec::from(
993						&[
994							0x75u8, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c,
995							0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6,
996						][..],
997					),
998				}),
999			),
1000			(vec![Fe32::try_from(21).unwrap(); 41], Err(Bolt11ParseError::Skip)),
1001			(vec![], Err(Bolt11ParseError::UnexpectedEndOfTaggedFields)),
1002			(
1003				vec![Fe32::try_from(1).unwrap(); 81],
1004				Err(Bolt11ParseError::InvalidSegWitProgramLength),
1005			),
1006			(vec![Fe32::try_from(17).unwrap(); 1], Err(Bolt11ParseError::InvalidPubKeyHashLength)),
1007			(vec![Fe32::try_from(18).unwrap(); 1], Err(Bolt11ParseError::InvalidScriptHashLength)),
1008		];
1009
1010		for (input, expected) in cases.into_iter() {
1011			assert_eq!(Fallback::from_base32(&input), expected);
1012		}
1013	}
1014
1015	#[test]
1016	fn test_parse_route() {
1017		use crate::PrivateRoute;
1018		use lightning_types::routing::{RouteHint, RouteHintHop, RoutingFees};
1019
1020		let input = from_bech32(
1021			"q20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqa\
1022			fqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzq".as_bytes()
1023		);
1024
1025		let expected = vec![
1026			RouteHintHop {
1027				src_node_id: PublicKey::from_slice(
1028					&[
1029						0x02u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4,
1030						0x3c, 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a,
1031						0x95, 0xc3, 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55,
1032					][..],
1033				)
1034				.unwrap(),
1035				short_channel_id: 0x0102030405060708,
1036				fees: RoutingFees { base_msat: 1, proportional_millionths: 20 },
1037				cltv_expiry_delta: 3,
1038				htlc_minimum_msat: None,
1039				htlc_maximum_msat: None,
1040			},
1041			RouteHintHop {
1042				src_node_id: PublicKey::from_slice(
1043					&[
1044						0x03u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4,
1045						0x3c, 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a,
1046						0x95, 0xc3, 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55,
1047					][..],
1048				)
1049				.unwrap(),
1050				short_channel_id: 0x030405060708090a,
1051				fees: RoutingFees { base_msat: 2, proportional_millionths: 30 },
1052				cltv_expiry_delta: 4,
1053				htlc_minimum_msat: None,
1054				htlc_maximum_msat: None,
1055			},
1056		];
1057
1058		assert_eq!(PrivateRoute::from_base32(&input), Ok(PrivateRoute(RouteHint(expected))));
1059
1060		assert_eq!(
1061			PrivateRoute::from_base32(&[Fe32::try_from(0).unwrap(); 40][..]),
1062			Err(Bolt11ParseError::UnexpectedEndOfTaggedFields)
1063		);
1064	}
1065
1066	#[test]
1067	fn test_payment_secret_and_features_de_and_ser() {
1068		use crate::TaggedField::*;
1069		use crate::{
1070			Bolt11InvoiceSignature, Currency, PositiveTimestamp, RawBolt11Invoice, RawDataPart,
1071			RawHrp, Sha256, SiPrefix, SignedRawBolt11Invoice,
1072		};
1073		use bitcoin::secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
1074		use lightning_types::features::Bolt11InvoiceFeatures;
1075
1076		// Feature bits 9, 15, and 99 are set.
1077		let expected_features =
1078			Bolt11InvoiceFeatures::from_le_bytes(vec![0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]);
1079		let invoice_str = "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqsq67gye39hfg3zd8rgc80k32tvy9xk2xunwm5lzexnvpx6fd77en8qaq424dxgt56cag2dpt359k3ssyhetktkpqh24jqnjyw6uqd08sgptq44qu";
1080		let invoice =
1081			SignedRawBolt11Invoice {
1082				raw_invoice: RawBolt11Invoice {
1083					hrp: RawHrp {
1084						currency: Currency::Bitcoin,
1085						raw_amount: Some(25),
1086						si_prefix: Some(SiPrefix::Milli),
1087					},
1088					data: RawDataPart {
1089						timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1090						tagged_fields: vec ! [
1091								PaymentHash(Sha256(sha256::Hash::from_str(
1092									"0001020304050607080900010203040506070809000102030405060708090102"
1093								).unwrap())).into(),
1094								Description(crate::Description::new("coffee beans".to_owned()).unwrap()).into(),
1095								PaymentSecret(crate::PaymentSecret([17; 32])).into(),
1096								Features(expected_features).into()],
1097					},
1098				},
1099				hash: [
1100					0xb1, 0x96, 0x46, 0xc3, 0xbc, 0x56, 0x76, 0x1d, 0x20, 0x65, 0x6e, 0x0e, 0x32,
1101					0xec, 0xd2, 0x69, 0x27, 0xb7, 0x62, 0x6e, 0x2a, 0x8b, 0xe6, 0x97, 0x71, 0x9f,
1102					0xf8, 0x7e, 0x44, 0x54, 0x55, 0xb9,
1103				],
1104				signature: Bolt11InvoiceSignature(
1105					RecoverableSignature::from_compact(
1106						&[
1107							0xd7, 0x90, 0x4c, 0xc4, 0xb7, 0x4a, 0x22, 0x26, 0x9c, 0x68, 0xc1, 0xdf,
1108							0x68, 0xa9, 0x6c, 0x21, 0x4d, 0x65, 0x1b, 0x93, 0x76, 0xe9, 0xf1, 0x64,
1109							0xd3, 0x60, 0x4d, 0xa4, 0xb7, 0xde, 0xcc, 0xce, 0x0e, 0x82, 0xaa, 0xab,
1110							0x4c, 0x85, 0xd3, 0x58, 0xea, 0x14, 0xd0, 0xae, 0x34, 0x2d, 0xa3, 0x08,
1111							0x12, 0xf9, 0x5d, 0x97, 0x60, 0x82, 0xea, 0xac, 0x81, 0x39, 0x11, 0xda,
1112							0xe0, 0x1a, 0xf3, 0xc1,
1113						],
1114						RecoveryId::from_i32(1).unwrap(),
1115					)
1116					.unwrap(),
1117				),
1118			};
1119		assert_eq!(invoice_str, invoice.to_string());
1120		assert_eq!(invoice_str.parse(), Ok(invoice));
1121	}
1122
1123	#[test]
1124	fn test_raw_signed_invoice_deserialization() {
1125		use crate::TaggedField::*;
1126		use crate::{
1127			Bolt11InvoiceSignature, Currency, PositiveTimestamp, RawBolt11Invoice, RawDataPart,
1128			RawHrp, Sha256, SignedRawBolt11Invoice,
1129		};
1130		use bitcoin::secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
1131
1132		assert_eq!(
1133			"lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmw\
1134			wd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9\
1135			ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w".parse(),
1136			Ok(SignedRawBolt11Invoice {
1137				raw_invoice: RawBolt11Invoice {
1138					hrp: RawHrp {
1139						currency: Currency::Bitcoin,
1140						raw_amount: None,
1141						si_prefix: None,
1142					},
1143					data: RawDataPart {
1144					timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1145					tagged_fields: vec ! [
1146						PaymentHash(Sha256(sha256::Hash::from_str(
1147							"0001020304050607080900010203040506070809000102030405060708090102"
1148						).unwrap())).into(),
1149						Description(
1150							crate::Description::new(
1151								"Please consider supporting this project".to_owned()
1152							).unwrap()
1153						).into(),
1154					],
1155					},
1156					},
1157				hash: [
1158					0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27,
1159					0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
1160					0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
1161				],
1162				signature: Bolt11InvoiceSignature(RecoverableSignature::from_compact(
1163					& [
1164						0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
1165						0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
1166						0x4e, 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f,
1167						0x42, 0x5f, 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad,
1168						0x0d, 0x6e, 0x35, 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9,
1169						0xaa, 0xb1, 0x5e, 0x57, 0x38, 0xb1, 0x1f, 0x12, 0x7f
1170					],
1171					RecoveryId::from_i32(0).unwrap()
1172				).unwrap()),
1173				}
1174			)
1175		)
1176	}
1177
1178	// Test some long invoice test vectors successfully roundtrip. Generated
1179	// from Lexe proptest: <https://github.com/lexe-app/lexe-public/blob/4bc7018307e5221e1e1ee8b17ce366338fb11a16/common/src/ln/invoice.rs#L183>.
1180	#[test]
1181	fn test_deser_long_test_vectors() {
1182		use crate::Bolt11Invoice;
1183
1184		#[track_caller]
1185		fn parse_ok(invoice_str: &str) {
1186			let invoice = Bolt11Invoice::from_str(invoice_str).unwrap();
1187			let invoice_str2 = invoice.to_string();
1188			if invoice_str != invoice_str2 {
1189				panic!(
1190					"Invoice does not roundtrip: invoice_str != invoice_str2\n\
1191					 invoice_str: {invoice_str}\n\
1192					 invoice_str2: {invoice_str2}\n\
1193					 \n\
1194					 {invoice:?}"
1195				);
1196			}
1197		}
1198
1199		// 1024 B shrunk invoice just above previous limit of 1023 B from Lexe proptest
1200		parse_ok(
1201			"lnbc10000000000000000010p1qqqqqqqdtuxpqkzq8sjzqgps4pvyczqq8sjzqgpuysszq0pyyqsrp2zs0sjz\
1202			 qgps4pxrcfpqyqc2slpyyqsqsv9gwz59s5zqpqyps5rc9qsrs2pqxz5ysyzcfqgysyzs0sjzqgqq8sjzqgps4p\
1203			 xqqzps4pqpssqgzpxps5ruysszqrps4pg8p2zgpsc2snpuysszqzqsgqvys0pyyqsrcfpqyqvycv9gfqqrcfpq\
1204			 yq7zggpq8q5zqyruysszqwpgyqxpsjqsgq7zggpqps7zggpq8sjzqgqgqq7zggpqpq7zggpq8q5zqqpuysszq0\
1205			 pyyqsqs0pyyqspsnqgzpqpqlpyyqsqszpuysszqyzvzpvysrqq8sjzqgqvrp7zggpqpqxpsspp5mf45hs3cgph\
1206			 h0074r5qmr74y82r26ac4pzdg4nd9mdmsvz6ffqpssp5vr4yra4pcv74h9hk3d0233nqu4gktpuykjamrafrdp\
1207			 uedqugzh3q9q2sqqqqqysgqcqrpqqxq8pqqqqqqnp4qgvcxpme2q5lng36j9gruwlrtk2f86s3c5xmk87yhvyu\
1208			 wdeh025q5r9yqwnqegv9hj9nzkhyxaeyq92wcrnqp36pyrc2qzrvswj5g96ey2dn6qqqqqqqqqqqqqqqqqqqqq\
1209			 qqqqqqqqp9a5vs0t4z56p64xyma8s84yvdx7uhqj0gvrr424fea2wpztq2fwqqqqqqqqqqqqqqqqqqqqqqqqqq\
1210			 qqqqmy9qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\
1211			 qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpcnsxc32du9n7amlypuhclzqrt6lkegq\
1212			 0v3r7nczjv9tv30z7phq80r3dm7pvgykl7gwuenmem93h5xwdwac6ngsmzqc34khrg3qjgsq6qk6lc"
1213		);
1214		// 1517 B mainnet invoice from Lexe proptest
1215		parse_ok(
1216			"lnbc8735500635020489010p1av5kfs8deupvyk4u5ynj03hmalhhhml0fxc2jlrv9z4lg6s4hnhkz69malhhe\
1217			 t3x9yqpsxru4a3kwar2qtu2q2ughx367q600s5x7c7tln4k0fu78skxqevaqm8sayhuur377zgf3uf94n57xzh\
1218			 dw99u42hwc089djn5xj723w7zageflsnzdmyte89tecf2ac7xhg4y3u9f4xpuv2hwxjlsarp0e24fu8tme6rgv\
1219			 0tqj08z9f4u30rw59k8emhtvs7wye0xfw6x5q5tju2p208rvtkunzwtwghtp22tlnh62gxwhfkxp4cnz7ts3rx\
1220			 vlzszhv9y00h77lpdvcjyhjtmalh5dn5e8n5w8cqle0vunzduu4nza9y0734qhxday9hzywl0aa0vhzy0qmphc\
1221			 64d4hduj08dv2krpgqtc2v83gptk34reelxyc7wsgnze890c6nrv6p0cmepatc269eayzjjkqk30n52rfl5dg7\
1222			 wztl96f7wc2tzx34q909xuajnyt4u4lnk87lwal7z0etdz5tmece0v3u796jfp68nccn05ty54ncfelts3v8g0\
1223			 sn6v6hsu87zat4r03368ersu87252dd0nswymxzc2pyxl8yy844hspuyj47w0px4u4leefq568sk0rr9th4ql9\
1224			 f9ykawrczkz5hp22nstg3lrlsa6u2q2ull3kzce2sh0h77sjv0zszhzy4hfh6u0pwux5l3gpthsn72mfu47sw9\
1225			 zw3hzk7srznp27z0etdp0725me00sn72mgkf0fteehruk0lg6swh34z52puaekzmjlmalhhe6m8ug7z3c8g8zh\
1226			 jjspp5zj0sm85g5ufng9w7s6p4ucdk80tyvz64sg54v0cy4vgnr37f78sqsp5l6azu2hv6we30er90jrslqpvd\
1227			 trnrphhesca2wg5q83k52rsu2cq9q2sqqqqqysgqcqr8h2np4qw0ha2k282hm8jh5rcfq0hsp2zhddtlc5vs23\
1228			 uphyv0lv3k8sqsfgfp4qyrk86tx5xg2aa7et4cdzhnvl5s4nd33ugytt7gamk9tugn9yransr9yq08gpwsn8t2\
1229			 tq4ducjfhrcz707av0ss20urjh8vldrpmehqxa0stkesvuq82txyqzfhej7qccswy7k5wvcppk63c6zpjytfda\
1230			 ccadacjtn52lpe6s85rjfqlxzp6frq33xshaz2nr9xjkhd3jj8qg39nmfzvpgmayakqmy9rseakwgcudug7hs4\
1231			 5wh430ywh7qhj3khczh8gle4cn93ymgfwa7rrvcw9lywyyz58k4p40a3nu9svthaf0qeg8f2ay4tw9p48p70qm\
1232			 ayu3ejl2q8pj9e2l22h7775tl44hs6ke4sdfgcr6aj8wra4r2v9sj6xa5chd5ctpfg8chtrer3kkp0e6af88lk\
1233			 rfxcklf2hyslv2hr0xl5lwrm5y5uttxn4ndfz8789znf78nspa3xy68"
1234		);
1235		// 1804 B regtest invoice from Lexe proptest
1236		parse_ok(
1237			"lnbcrt17124979001314909880p1y6lkcwgd76tfnxksfk2atyy4tzw4nyg6jrx3282s2ygvcxyj64gevhxsjk\
1238			 2ymhzv3e0p5h5u3kfey92jt9ge44gsfnwycxynm2g3unw3ntt9qh25texe98jcfhxvcxuezxw9tngwrndpy9s4\
1239			 p4x9eyze2tfe9rxm68tp5yj5jfduen2nny8prhsm6edegn2stww4n4gwp4vfjkvdthd43524n9fa8h262vwesk\
1240			 g66nw3vnyafn29zhsvfeg9mxummtfp35uumzfqmhy3jwgdh55mt5xpvhgmjn25uku5e5g939wmmnvdfygnrdgd\
1241			 h56uzcx4a92vfhgdcky3z9gfnrsvp4f4f55j68vak9yufhvdm8x5zrgc6955jvf429zumv89nh2a35wae5yntg\
1242			 v985jumpxehyv7t92pjrwufs89yh23f5ddy5s568wgchve3cg9ek5nzewgcrzjz0dftxg3nvf4hngje52ac4zm\
1243			 esxpvk6sfef4hkuetvd4vk6n29wftrw5rvg4yy2vjjwyexc5mnvfd8xknndpqkkenx0q642j35298hwve3dyc5\
1244			 25jrd3295sm9v9jrqup3wpykg7zd239ns7jgtqu95jz0deaxksjh2fu56n6n2f5x6mm8wa89qjfef385sam2x9\
1245			 mxcs20gfpnq460d3axzknnf3e4sw2kvf25wjjxddpyg52dw4vx7nn2w9cyu5t8vfnyxjtpg33kssjp24ch536p\
1246			 d938snmtx345x6r4x93kvv2tff855um3tfekxjted4kxys2kve5hvu6g89z4ynmjgfhnw7tv892rymejgvey77\
1247			 rcfqe9xjr92d85636fvajxyajndfa92k2nxycx5jtjx4zxsm2y2dyn2up50f5ku3nrfdk4g5npxehkzjjv8y69\
1248			 gveev4z56denddaxy7tfwe8xx42zgf6kzmnxxpk826ze2s6xk6jrwearw6ejvd8rsvj2fpg525jtd5pp5j2tlt\
1249			 28m4kakjr84w6ce4fd8e7awy6ncyswcyut760rdnem30ptssp5p5u3xgxxtr6aev8y2w9m30wcw3kyn7fgm8wm\
1250			 f8qw8wzrqt34zcvq9q2sqqqqqysgqcqypmw9xq8lllllllnp4qt36twam2ca08m3s7vnhre3c0j89589wyw4vd\
1251			 k7fln0lryxzkdcrur28qwqq3hnyt84vsasuldd2786eysdf4dyuggwsmvw2atftf7spkmpa9dd3efq5tenpqm2\
1252			 v7vcz2a4s0s7jnqpjn0srysnstnw5y5z9taxn0ue37aqgufxcdsj6f8a2m4pm9udppdzc4shsdqzzx0u0rm4xl\
1253			 js0dqz3c5zqyvglda7nsqvqfztmlyup7vyuadzav4zyuqwx90ev6nmk53nkhkt0sev9e745wxqtdvrqzgqkaka\
1254			 zen7e2qmsdauk665g3llg5qtl79t3xulrhjnducehdn72gpmkjvtth7kh6ejpl9dv0qcsxv2jvzzvg0hzdmk3y\
1255			 jsmydqksdk3h78kc63qnr265h8vyeslqexszppfm7y287t3gxvhw0ulg2wp0rsw3tevz03z50kpy77zdz9snxm\
1256			 kkwxd76xvj4qvj2f89rrnuvdvzw947ay0kydc077pkec2jet9qwp2tud98s24u65uz07eaxk5jk3e4nggn2caa\
1257			 ek2p5pkrc6mm6mxjm2ezpdu8p5jstg6tgvnttgac3ygt5ys04t4udujzlshpl7e4f3ff03xe6v24cp6aq4wa"
1258		);
1259		// 1870 B testnet invoice from Lexe proptest
1260		parse_ok(
1261			"lntb5826417333454665580p1c5rwh5edlhf33hvkj5vav5z3t02a5hxvj3vfv5kuny2f3yzj6zwf9hx3nn2fk\
1262			 9gepc2a3ywvj6dax5v3jy2d5nxmp3gaxhycjkv38hx4z4d4vyznrp2p24xa6t2pg4w4rrxfens6tcxdhxvvfhx\
1263			 a8xvvpkgat8xnpe2p44juz9g43hyur00989gvfhwd2kj72wfum4g4mgx5m5cs2rg9d9vnn6xe89ydnnvfpyy52\
1264			 s2dxx2er4x4xxwstdd5cxwdrjw3nkxnnv2uexxnrxw4t56sjswfn52s2xv4t8xmjtwpn8xm6sfeh4q526dyu8x\
1265			 3r9gceyw6fhd934qjttvdk57az5w368zdrhwfjxxu35xcmrsmmpd4g8wwtev4tkzutdd32k56mxveuy6c6v2em\
1266			 yv7zkfp39zjpjgd8hx7n4xph5kceswf6xxmnyfcuxca20fp24z7ncvfhyu5jf2exhw36nwf68s7rh2a6yzjf4d\
1267			 gukcenfxpchqsjn2pt5x334tf98wsm6dvcrvvfcwapxvk2cdvmk2npcfe68zue3w4f9xc6s2fvrw6nrg3fkskt\
1268			 e2ftxyc20ffckcd692964sdzjwdp4yvrfdfm9q72pxp3kwat5f4j9xee5da8rss60w92857tgwych55f5w3n8z\
1269			 mzexpy4jwredejrqm6txf3nxm64ffh8x460dp9yjazhw4yx6dm5xerysnn5wa455k3h2d89ss2fd9axwjp3f4r\
1270			 9qdmfd4fx6stx2eg9sezrv369w7nvvfvhj4nnwaz5z3ny8qcxcdnvwd64jc2nx9uy2e2gxdrnx6r3w9ykxatxx\
1271			 g6kk6rv2ekr2emwx5ehy362d3x82dzvddfxs5rcg4vn27npf564qdtg2anycc6523jnwe3e0p65unrpvccrs5m\
1272			 2fuexgmnj23ay5e34v4xk5jnrwpg4xemfwqe5vjjjw9qk76zsd9yrzu6xdpv5v5ntdejxg6jtv3kx65t6gdhrg\
1273			 vj3fe34sj2vv3h5kegpp57hjf5kv6clw97y2e063yuz0psrz9a6l49v836dflum00rh8qtn8qsp5gd29qycuze\
1274			 08xls8l32zjaaf2uqv78v97lg9ss0c699huw980h2q9q2sqqqqqysgqcqr8ulnp4q26hcfwr7qxz7lwwlr2kjc\
1275			 rws7m2u5j36mm0kxa45uxy6zvsqt2zzfppjdkrm2rlgadt9dq3d6jkv4r2cugmf2kamr28qwuleyzzyyly8a6t\
1276			 u70eldahx7hzxx5x9gms7vjjr577ps8n4qyds5nern39j0v7czkch2letnt46895jupxgehf208xgxz8d6j8gu\
1277			 3h2qqtsk9nr9nuquhkqjxw40h2ucpldrawmktxzxdgtkt9a3p95g98nywved8s8laj2a0c98rq5zzdnzddz6nd\
1278			 w0lvr6u0av9m7859844cgz9vpeq05gw79zqae2s7jzeq66wydyueqtp56qc67g7krv6lj5aahxtmq4y208q5qy\
1279			 z38cnwl9ma6m5f4nhzqaj0tjxpfrk4nr5arv9d20lvxvddvffhzygmyuvwd959uhdcgcgjejchqt2qncuwpqqk\
1280			 5vws7dflw8x6esrfwhz7h3jwmhevf445k76nme926sr8drsdveqg7l7t7lnjvhaludqnwk4l2pmevkjf9pla92\
1281			 4p77v76r7x8jzyy7h59hmk0lgzfsk6c8dpj37hssj7jt4q7jzvy8hq25l3pag37axxanjqnq56c47gpgy6frsy\
1282			 c0str9w2aahz4h6t7axaka4cwvhwg49r6qgj8kwz2mt6vcje25l9ekvmgq5spqtn"
1283		);
1284	}
1285
1286	// Generate a valid invoice of `MAX_LENGTH` bytes and ensure that it roundtrips.
1287	#[test]
1288	fn test_serde_long_invoice() {
1289		use crate::TaggedField::*;
1290		use crate::{
1291			Bolt11Invoice, Bolt11InvoiceFeatures, Bolt11InvoiceSignature, Currency,
1292			PositiveTimestamp, RawBolt11Invoice, RawDataPart, RawHrp, RawTaggedField, Sha256,
1293			SignedRawBolt11Invoice,
1294		};
1295		use bitcoin::secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
1296		use bitcoin::secp256k1::PublicKey;
1297		use lightning_types::routing::{RouteHint, RouteHintHop, RoutingFees};
1298
1299		// Generate an `UnknownSemantics` field with a given length.
1300		fn unknown_semantics_field(len: usize) -> Vec<Fe32> {
1301			assert!(len <= 1023);
1302			let mut field = Vec::with_capacity(len + 3);
1303			// Big-endian encoded length prefix
1304			field.push(Fe32::Q);
1305			field.push(Fe32::try_from((len >> 5) as u8).unwrap());
1306			field.push(Fe32::try_from((len & 0x1f) as u8).unwrap());
1307			// Data
1308			field.extend(std::iter::repeat(Fe32::P).take(len));
1309			field
1310		}
1311
1312		// Invoice fields
1313		let payment_hash = sha256::Hash::from_str(
1314			"0001020304050607080900010203040506070809000102030405060708090102",
1315		)
1316		.unwrap();
1317		let description = "A".repeat(639);
1318		let fallback_addr = crate::Fallback::SegWitProgram {
1319			version: bitcoin::WitnessVersion::V0,
1320			program: vec![0; 32],
1321		};
1322		let payee_pk = PublicKey::from_slice(&[
1323			0x03, 0x24, 0x65, 0x3e, 0xac, 0x43, 0x44, 0x88, 0x00, 0x2c, 0xc0, 0x6b, 0xbf, 0xb7,
1324			0xf1, 0x0f, 0xe1, 0x89, 0x91, 0xe3, 0x5f, 0x9f, 0xe4, 0x30, 0x2d, 0xbe, 0xa6, 0xd2,
1325			0x35, 0x3d, 0xc0, 0xab, 0x1c,
1326		])
1327		.unwrap();
1328		let route_hints = std::iter::repeat(RouteHintHop {
1329			src_node_id: payee_pk,
1330			short_channel_id: 0x0102030405060708,
1331			fees: RoutingFees { base_msat: 1, proportional_millionths: 20 },
1332			cltv_expiry_delta: 3,
1333			htlc_minimum_msat: None,
1334			htlc_maximum_msat: None,
1335		})
1336		.take(12)
1337		.collect::<Vec<_>>();
1338
1339		// Build raw invoice
1340		let raw_invoice = RawBolt11Invoice {
1341			hrp: RawHrp {
1342				currency: Currency::Bitcoin,
1343				raw_amount: Some(10000000000000000010),
1344				si_prefix: Some(crate::SiPrefix::Pico),
1345			},
1346			data: RawDataPart {
1347				timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1348				tagged_fields: vec![
1349					PaymentHash(Sha256(payment_hash)).into(),
1350					Description(crate::Description::new(description).unwrap()).into(),
1351					PayeePubKey(crate::PayeePubKey(payee_pk)).into(),
1352					ExpiryTime(crate::ExpiryTime(std::time::Duration::from_secs(u64::MAX))).into(),
1353					MinFinalCltvExpiryDelta(crate::MinFinalCltvExpiryDelta(u64::MAX)).into(),
1354					Fallback(fallback_addr).into(),
1355					PrivateRoute(crate::PrivateRoute(RouteHint(route_hints))).into(),
1356					PaymentSecret(crate::PaymentSecret([17; 32])).into(),
1357					PaymentMetadata(vec![0x69; 639]).into(),
1358					Features(Bolt11InvoiceFeatures::from_le_bytes(vec![0xaa; 639])).into(),
1359					// This invoice is 4458 B w/o unknown semantics fields.
1360					// Need to add some non-standard fields to reach 7089 B limit.
1361					RawTaggedField::UnknownSemantics(unknown_semantics_field(1023)),
1362					RawTaggedField::UnknownSemantics(unknown_semantics_field(1023)),
1363					RawTaggedField::UnknownSemantics(unknown_semantics_field(576)),
1364				],
1365			},
1366		};
1367
1368		// Build signed invoice
1369		let hash = [
1370			0x75, 0x99, 0xe1, 0x51, 0x7f, 0xa1, 0x0e, 0xb5, 0xc0, 0x79, 0xb4, 0x6e, 0x8e, 0x62,
1371			0x0c, 0x4f, 0xb0, 0x72, 0x71, 0xd2, 0x81, 0xa1, 0x92, 0x65, 0x9c, 0x90, 0x89, 0x69,
1372			0xe1, 0xf3, 0xd6, 0x59,
1373		];
1374		let signature = &[
1375			0x6c, 0xbe, 0xbe, 0xfe, 0xd3, 0xfb, 0x07, 0x68, 0xb5, 0x79, 0x98, 0x82, 0x29, 0xab,
1376			0x0e, 0xcc, 0x8d, 0x3a, 0x81, 0xee, 0xee, 0x07, 0xb3, 0x5d, 0x64, 0xca, 0xb4, 0x12,
1377			0x33, 0x99, 0x33, 0x2a, 0x31, 0xc2, 0x2c, 0x2b, 0x62, 0x96, 0x4e, 0x37, 0xd7, 0x96,
1378			0x50, 0x5e, 0xdb, 0xe9, 0xa9, 0x5b, 0x0b, 0x3b, 0x87, 0x22, 0x89, 0xed, 0x95, 0xf1,
1379			0xf1, 0xdf, 0x2d, 0xb6, 0xbd, 0xf5, 0x0a, 0x20,
1380		];
1381		let signature = Bolt11InvoiceSignature(
1382			RecoverableSignature::from_compact(signature, RecoveryId::from_i32(1).unwrap())
1383				.unwrap(),
1384		);
1385		let signed_invoice = SignedRawBolt11Invoice { raw_invoice, hash, signature };
1386
1387		// Ensure serialized invoice roundtrips
1388		let invoice = Bolt11Invoice::from_signed(signed_invoice).unwrap();
1389		let invoice_str = invoice.to_string();
1390		assert_eq!(invoice_str.len(), crate::MAX_LENGTH);
1391		assert_eq!(invoice, Bolt11Invoice::from_str(&invoice_str).unwrap());
1392	}
1393
1394	// Test that invoices above the maximum length fail to parse with the expected error.
1395	#[test]
1396	fn test_deser_too_long_fails() {
1397		use crate::{Bolt11Invoice, ParseOrSemanticError, MAX_LENGTH};
1398		use bech32::primitives::decode::{CheckedHrpstringError, ChecksumError};
1399
1400		fn parse_is_code_length_err(s: &str) -> bool {
1401			// Need matches! b/c ChecksumError::CodeLength(_) is marked non-exhaustive
1402			matches!(
1403				Bolt11Invoice::from_str(s),
1404				Err(ParseOrSemanticError::ParseError(Bolt11ParseError::Bech32Error(
1405					CheckedHrpstringError::Checksum(ChecksumError::CodeLength(_))
1406				))),
1407			)
1408		}
1409
1410		let mut too_long = String::from("lnbc1");
1411		too_long.push_str(
1412			String::from_utf8(vec![b'x'; (MAX_LENGTH + 1) - too_long.len()]).unwrap().as_str(),
1413		);
1414		assert!(parse_is_code_length_err(&too_long));
1415		assert!(!parse_is_code_length_err(&too_long[..too_long.len() - 1]));
1416	}
1417}