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::InvalidRecoveryId => {
776				f.write_str("recovery id is out of range (should be in [0,3])")
777			},
778			Bolt11ParseError::Skip => f.write_str(
779				"the tagged field has to be skipped because of an unexpected, but allowed property",
780			),
781		}
782	}
783}
784
785impl Display for ParseOrSemanticError {
786	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
787		match self {
788			ParseOrSemanticError::ParseError(err) => err.fmt(f),
789			ParseOrSemanticError::SemanticError(err) => err.fmt(f),
790		}
791	}
792}
793
794#[cfg(feature = "std")]
795impl error::Error for Bolt11ParseError {}
796
797#[cfg(feature = "std")]
798impl error::Error for ParseOrSemanticError {}
799
800macro_rules! from_error {
801	($my_error:expr, $extern_error:ty) => {
802		impl From<$extern_error> for Bolt11ParseError {
803			fn from(e: $extern_error) -> Self {
804				$my_error(e)
805			}
806		}
807	};
808}
809
810from_error!(Bolt11ParseError::MalformedSignature, bitcoin::secp256k1::Error);
811from_error!(Bolt11ParseError::ParseAmountError, ParseIntError);
812from_error!(Bolt11ParseError::DescriptionDecodeError, string::FromUtf8Error);
813
814impl From<CheckedHrpstringError> for Bolt11ParseError {
815	fn from(e: CheckedHrpstringError) -> Self {
816		Self::Bech32Error(e)
817	}
818}
819
820impl From<Bolt11ParseError> for ParseOrSemanticError {
821	fn from(e: Bolt11ParseError) -> Self {
822		ParseOrSemanticError::ParseError(e)
823	}
824}
825
826impl From<crate::Bolt11SemanticError> for ParseOrSemanticError {
827	fn from(e: Bolt11SemanticError) -> Self {
828		ParseOrSemanticError::SemanticError(e)
829	}
830}
831
832#[cfg(test)]
833mod test {
834	use super::FromBase32;
835	use crate::de::Bolt11ParseError;
836	use bech32::Fe32;
837	use bitcoin::hashes::sha256;
838	use bitcoin::secp256k1::PublicKey;
839	use std::str::FromStr;
840
841	const CHARSET_REV: [i8; 128] = [
842		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
843		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
844		-1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13,
845		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,
846		-1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, 3, 16, 11, 28,
847		12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
848	];
849
850	fn from_bech32(bytes_5b: &[u8]) -> Vec<Fe32> {
851		bytes_5b.iter().map(|c| Fe32::try_from(CHARSET_REV[*c as usize] as u8).unwrap()).collect()
852	}
853
854	#[test]
855	fn test_parse_currency_prefix() {
856		use crate::Currency;
857
858		assert_eq!("bc".parse::<Currency>(), Ok(Currency::Bitcoin));
859		assert_eq!("tb".parse::<Currency>(), Ok(Currency::BitcoinTestnet));
860		assert_eq!("bcrt".parse::<Currency>(), Ok(Currency::Regtest));
861		assert_eq!("sb".parse::<Currency>(), Ok(Currency::Simnet));
862		assert_eq!("tbs".parse::<Currency>(), Ok(Currency::Signet));
863		assert_eq!("something_else".parse::<Currency>(), Err(Bolt11ParseError::UnknownCurrency))
864	}
865
866	#[test]
867	fn test_parse_int_from_bytes_be() {
868		use crate::de::parse_u16_be;
869
870		assert_eq!(
871			parse_u16_be(&[
872				Fe32::try_from(1).unwrap(),
873				Fe32::try_from(2).unwrap(),
874				Fe32::try_from(3).unwrap(),
875				Fe32::try_from(4).unwrap(),
876			]),
877			Some(34916)
878		);
879		assert_eq!(
880			parse_u16_be(&[
881				Fe32::try_from(2).unwrap(),
882				Fe32::try_from(0).unwrap(),
883				Fe32::try_from(0).unwrap(),
884				Fe32::try_from(0).unwrap(),
885			]),
886			None
887		);
888	}
889
890	#[test]
891	fn test_parse_sha256_hash() {
892		use crate::Sha256;
893
894		let input = from_bech32("qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypq".as_bytes());
895
896		let hash = sha256::Hash::from_str(
897			"0001020304050607080900010203040506070809000102030405060708090102",
898		)
899		.unwrap();
900		let expected = Ok(Sha256(hash));
901
902		assert_eq!(Sha256::from_base32(&input), expected);
903
904		// make sure hashes of unknown length get skipped
905		let input_unexpected_length =
906			from_bech32("qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypyq".as_bytes());
907		assert_eq!(Sha256::from_base32(&input_unexpected_length), Err(Bolt11ParseError::Skip));
908	}
909
910	#[test]
911	fn test_parse_description() {
912		use crate::Description;
913
914		let input = from_bech32("xysxxatsyp3k7enxv4js".as_bytes());
915		let expected = Ok(Description::new("1 cup coffee".to_owned()).unwrap());
916		assert_eq!(Description::from_base32(&input), expected);
917	}
918
919	#[test]
920	fn test_parse_payee_pub_key() {
921		use crate::PayeePubKey;
922
923		let input = from_bech32("q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66".as_bytes());
924		let pk_bytes = [
925			0x03, 0xe7, 0x15, 0x6a, 0xe3, 0x3b, 0x0a, 0x20, 0x8d, 0x07, 0x44, 0x19, 0x91, 0x63,
926			0x17, 0x7e, 0x90, 0x9e, 0x80, 0x17, 0x6e, 0x55, 0xd9, 0x7a, 0x2f, 0x22, 0x1e, 0xde,
927			0x0f, 0x93, 0x4d, 0xd9, 0xad,
928		];
929		let expected = Ok(PayeePubKey(PublicKey::from_slice(&pk_bytes[..]).unwrap()));
930
931		assert_eq!(PayeePubKey::from_base32(&input), expected);
932
933		// expects 33 bytes
934		let input_unexpected_length =
935			from_bech32("q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhvq".as_bytes());
936		assert_eq!(PayeePubKey::from_base32(&input_unexpected_length), Err(Bolt11ParseError::Skip));
937	}
938
939	#[test]
940	fn test_parse_expiry_time() {
941		use crate::ExpiryTime;
942
943		let input = from_bech32("pu".as_bytes());
944		let expected = Ok(ExpiryTime::from_seconds(60));
945		assert_eq!(ExpiryTime::from_base32(&input), expected);
946
947		let input_too_large = from_bech32("sqqqqqqqqqqqq".as_bytes());
948		assert_eq!(
949			ExpiryTime::from_base32(&input_too_large),
950			Err(Bolt11ParseError::IntegerOverflowError)
951		);
952	}
953
954	#[test]
955	fn test_parse_min_final_cltv_expiry_delta() {
956		use crate::MinFinalCltvExpiryDelta;
957
958		let input = from_bech32("pr".as_bytes());
959		let expected = Ok(MinFinalCltvExpiryDelta(35));
960
961		assert_eq!(MinFinalCltvExpiryDelta::from_base32(&input), expected);
962	}
963
964	#[test]
965	fn test_parse_fallback() {
966		use crate::Fallback;
967		use bitcoin::hashes::Hash;
968		use bitcoin::{PubkeyHash, ScriptHash, WitnessVersion};
969
970		let cases = vec![
971			(
972				from_bech32("3x9et2e20v6pu37c5d9vax37wxq72un98".as_bytes()),
973				Ok(Fallback::PubKeyHash(
974					PubkeyHash::from_slice(&[
975						0x31, 0x72, 0xb5, 0x65, 0x4f, 0x66, 0x83, 0xc8, 0xfb, 0x14, 0x69, 0x59,
976						0xd3, 0x47, 0xce, 0x30, 0x3c, 0xae, 0x4c, 0xa7,
977					])
978					.unwrap(),
979				)),
980			),
981			(
982				from_bech32("j3a24vwu6r8ejrss3axul8rxldph2q7z9".as_bytes()),
983				Ok(Fallback::ScriptHash(
984					ScriptHash::from_slice(&[
985						0x8f, 0x55, 0x56, 0x3b, 0x9a, 0x19, 0xf3, 0x21, 0xc2, 0x11, 0xe9, 0xb9,
986						0xf3, 0x8c, 0xdf, 0x68, 0x6e, 0xa0, 0x78, 0x45,
987					])
988					.unwrap(),
989				)),
990			),
991			(
992				from_bech32("qw508d6qejxtdg4y5r3zarvary0c5xw7k".as_bytes()),
993				Ok(Fallback::SegWitProgram {
994					version: WitnessVersion::V0,
995					program: Vec::from(
996						&[
997							0x75u8, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c,
998							0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6,
999						][..],
1000					),
1001				}),
1002			),
1003			(vec![Fe32::try_from(21).unwrap(); 41], Err(Bolt11ParseError::Skip)),
1004			(vec![], Err(Bolt11ParseError::UnexpectedEndOfTaggedFields)),
1005			(
1006				vec![Fe32::try_from(1).unwrap(); 81],
1007				Err(Bolt11ParseError::InvalidSegWitProgramLength),
1008			),
1009			(vec![Fe32::try_from(17).unwrap(); 1], Err(Bolt11ParseError::InvalidPubKeyHashLength)),
1010			(vec![Fe32::try_from(18).unwrap(); 1], Err(Bolt11ParseError::InvalidScriptHashLength)),
1011		];
1012
1013		for (input, expected) in cases.into_iter() {
1014			assert_eq!(Fallback::from_base32(&input), expected);
1015		}
1016	}
1017
1018	#[test]
1019	fn test_parse_route() {
1020		use crate::PrivateRoute;
1021		use lightning_types::routing::{RouteHint, RouteHintHop, RoutingFees};
1022
1023		let input = from_bech32(
1024			"q20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqa\
1025			fqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzq".as_bytes()
1026		);
1027
1028		let mut expected = Vec::<RouteHintHop>::new();
1029		expected.push(RouteHintHop {
1030			src_node_id: PublicKey::from_slice(
1031				&[
1032					0x02u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
1033					0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
1034					0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55,
1035				][..],
1036			)
1037			.unwrap(),
1038			short_channel_id: 0x0102030405060708,
1039			fees: RoutingFees { base_msat: 1, proportional_millionths: 20 },
1040			cltv_expiry_delta: 3,
1041			htlc_minimum_msat: None,
1042			htlc_maximum_msat: None,
1043		});
1044		expected.push(RouteHintHop {
1045			src_node_id: PublicKey::from_slice(
1046				&[
1047					0x03u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
1048					0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
1049					0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55,
1050				][..],
1051			)
1052			.unwrap(),
1053			short_channel_id: 0x030405060708090a,
1054			fees: RoutingFees { base_msat: 2, proportional_millionths: 30 },
1055			cltv_expiry_delta: 4,
1056			htlc_minimum_msat: None,
1057			htlc_maximum_msat: None,
1058		});
1059
1060		assert_eq!(PrivateRoute::from_base32(&input), Ok(PrivateRoute(RouteHint(expected))));
1061
1062		assert_eq!(
1063			PrivateRoute::from_base32(&[Fe32::try_from(0).unwrap(); 40][..]),
1064			Err(Bolt11ParseError::UnexpectedEndOfTaggedFields)
1065		);
1066	}
1067
1068	#[test]
1069	fn test_payment_secret_and_features_de_and_ser() {
1070		use crate::TaggedField::*;
1071		use crate::{
1072			Bolt11InvoiceSignature, Currency, PositiveTimestamp, RawBolt11Invoice, RawDataPart,
1073			RawHrp, Sha256, SiPrefix, SignedRawBolt11Invoice,
1074		};
1075		use bitcoin::secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
1076		use lightning_types::features::Bolt11InvoiceFeatures;
1077
1078		// Feature bits 9, 15, and 99 are set.
1079		let expected_features =
1080			Bolt11InvoiceFeatures::from_le_bytes(vec![0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]);
1081		let invoice_str = "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqsq67gye39hfg3zd8rgc80k32tvy9xk2xunwm5lzexnvpx6fd77en8qaq424dxgt56cag2dpt359k3ssyhetktkpqh24jqnjyw6uqd08sgptq44qu";
1082		let invoice =
1083			SignedRawBolt11Invoice {
1084				raw_invoice: RawBolt11Invoice {
1085					hrp: RawHrp {
1086						currency: Currency::Bitcoin,
1087						raw_amount: Some(25),
1088						si_prefix: Some(SiPrefix::Milli),
1089					},
1090					data: RawDataPart {
1091						timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1092						tagged_fields: vec ! [
1093								PaymentHash(Sha256(sha256::Hash::from_str(
1094									"0001020304050607080900010203040506070809000102030405060708090102"
1095								).unwrap())).into(),
1096								Description(crate::Description::new("coffee beans".to_owned()).unwrap()).into(),
1097								PaymentSecret(crate::PaymentSecret([17; 32])).into(),
1098								Features(expected_features).into()],
1099					},
1100				},
1101				hash: [
1102					0xb1, 0x96, 0x46, 0xc3, 0xbc, 0x56, 0x76, 0x1d, 0x20, 0x65, 0x6e, 0x0e, 0x32,
1103					0xec, 0xd2, 0x69, 0x27, 0xb7, 0x62, 0x6e, 0x2a, 0x8b, 0xe6, 0x97, 0x71, 0x9f,
1104					0xf8, 0x7e, 0x44, 0x54, 0x55, 0xb9,
1105				],
1106				signature: Bolt11InvoiceSignature(
1107					RecoverableSignature::from_compact(
1108						&[
1109							0xd7, 0x90, 0x4c, 0xc4, 0xb7, 0x4a, 0x22, 0x26, 0x9c, 0x68, 0xc1, 0xdf,
1110							0x68, 0xa9, 0x6c, 0x21, 0x4d, 0x65, 0x1b, 0x93, 0x76, 0xe9, 0xf1, 0x64,
1111							0xd3, 0x60, 0x4d, 0xa4, 0xb7, 0xde, 0xcc, 0xce, 0x0e, 0x82, 0xaa, 0xab,
1112							0x4c, 0x85, 0xd3, 0x58, 0xea, 0x14, 0xd0, 0xae, 0x34, 0x2d, 0xa3, 0x08,
1113							0x12, 0xf9, 0x5d, 0x97, 0x60, 0x82, 0xea, 0xac, 0x81, 0x39, 0x11, 0xda,
1114							0xe0, 0x1a, 0xf3, 0xc1,
1115						],
1116						RecoveryId::from_i32(1).unwrap(),
1117					)
1118					.unwrap(),
1119				),
1120			};
1121		assert_eq!(invoice_str, invoice.to_string());
1122		assert_eq!(invoice_str.parse(), Ok(invoice));
1123	}
1124
1125	#[test]
1126	fn test_raw_signed_invoice_deserialization() {
1127		use crate::TaggedField::*;
1128		use crate::{
1129			Bolt11InvoiceSignature, Currency, PositiveTimestamp, RawBolt11Invoice, RawDataPart,
1130			RawHrp, Sha256, SignedRawBolt11Invoice,
1131		};
1132		use bitcoin::secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
1133
1134		assert_eq!(
1135			"lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmw\
1136			wd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9\
1137			ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w".parse(),
1138			Ok(SignedRawBolt11Invoice {
1139				raw_invoice: RawBolt11Invoice {
1140					hrp: RawHrp {
1141						currency: Currency::Bitcoin,
1142						raw_amount: None,
1143						si_prefix: None,
1144					},
1145					data: RawDataPart {
1146					timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1147					tagged_fields: vec ! [
1148						PaymentHash(Sha256(sha256::Hash::from_str(
1149							"0001020304050607080900010203040506070809000102030405060708090102"
1150						).unwrap())).into(),
1151						Description(
1152							crate::Description::new(
1153								"Please consider supporting this project".to_owned()
1154							).unwrap()
1155						).into(),
1156					],
1157					},
1158					},
1159				hash: [
1160					0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27,
1161					0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
1162					0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
1163				],
1164				signature: Bolt11InvoiceSignature(RecoverableSignature::from_compact(
1165					& [
1166						0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
1167						0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
1168						0x4e, 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f,
1169						0x42, 0x5f, 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad,
1170						0x0d, 0x6e, 0x35, 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9,
1171						0xaa, 0xb1, 0x5e, 0x57, 0x38, 0xb1, 0x1f, 0x12, 0x7f
1172					],
1173					RecoveryId::from_i32(0).unwrap()
1174				).unwrap()),
1175				}
1176			)
1177		)
1178	}
1179
1180	// Test some long invoice test vectors successfully roundtrip. Generated
1181	// from Lexe proptest: <https://github.com/lexe-app/lexe-public/blob/4bc7018307e5221e1e1ee8b17ce366338fb11a16/common/src/ln/invoice.rs#L183>.
1182	#[test]
1183	fn test_deser_long_test_vectors() {
1184		use crate::Bolt11Invoice;
1185
1186		#[track_caller]
1187		fn parse_ok(invoice_str: &str) {
1188			let invoice = Bolt11Invoice::from_str(invoice_str).unwrap();
1189			let invoice_str2 = invoice.to_string();
1190			if invoice_str != invoice_str2 {
1191				panic!(
1192					"Invoice does not roundtrip: invoice_str != invoice_str2\n\
1193					 invoice_str: {invoice_str}\n\
1194					 invoice_str2: {invoice_str2}\n\
1195					 \n\
1196					 {invoice:?}"
1197				);
1198			}
1199		}
1200
1201		// 1024 B shrunk invoice just above previous limit of 1023 B from Lexe proptest
1202		parse_ok(
1203			"lnbc10000000000000000010p1qqqqqqqdtuxpqkzq8sjzqgps4pvyczqq8sjzqgpuysszq0pyyqsrp2zs0sjz\
1204			 qgps4pxrcfpqyqc2slpyyqsqsv9gwz59s5zqpqyps5rc9qsrs2pqxz5ysyzcfqgysyzs0sjzqgqq8sjzqgps4p\
1205			 xqqzps4pqpssqgzpxps5ruysszqrps4pg8p2zgpsc2snpuysszqzqsgqvys0pyyqsrcfpqyqvycv9gfqqrcfpq\
1206			 yq7zggpq8q5zqyruysszqwpgyqxpsjqsgq7zggpqps7zggpq8sjzqgqgqq7zggpqpq7zggpq8q5zqqpuysszq0\
1207			 pyyqsqs0pyyqspsnqgzpqpqlpyyqsqszpuysszqyzvzpvysrqq8sjzqgqvrp7zggpqpqxpsspp5mf45hs3cgph\
1208			 h0074r5qmr74y82r26ac4pzdg4nd9mdmsvz6ffqpssp5vr4yra4pcv74h9hk3d0233nqu4gktpuykjamrafrdp\
1209			 uedqugzh3q9q2sqqqqqysgqcqrpqqxq8pqqqqqqnp4qgvcxpme2q5lng36j9gruwlrtk2f86s3c5xmk87yhvyu\
1210			 wdeh025q5r9yqwnqegv9hj9nzkhyxaeyq92wcrnqp36pyrc2qzrvswj5g96ey2dn6qqqqqqqqqqqqqqqqqqqqq\
1211			 qqqqqqqqp9a5vs0t4z56p64xyma8s84yvdx7uhqj0gvrr424fea2wpztq2fwqqqqqqqqqqqqqqqqqqqqqqqqqq\
1212			 qqqqmy9qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\
1213			 qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpcnsxc32du9n7amlypuhclzqrt6lkegq\
1214			 0v3r7nczjv9tv30z7phq80r3dm7pvgykl7gwuenmem93h5xwdwac6ngsmzqc34khrg3qjgsq6qk6lc"
1215		);
1216		// 1517 B mainnet invoice from Lexe proptest
1217		parse_ok(
1218			"lnbc8735500635020489010p1av5kfs8deupvyk4u5ynj03hmalhhhml0fxc2jlrv9z4lg6s4hnhkz69malhhe\
1219			 t3x9yqpsxru4a3kwar2qtu2q2ughx367q600s5x7c7tln4k0fu78skxqevaqm8sayhuur377zgf3uf94n57xzh\
1220			 dw99u42hwc089djn5xj723w7zageflsnzdmyte89tecf2ac7xhg4y3u9f4xpuv2hwxjlsarp0e24fu8tme6rgv\
1221			 0tqj08z9f4u30rw59k8emhtvs7wye0xfw6x5q5tju2p208rvtkunzwtwghtp22tlnh62gxwhfkxp4cnz7ts3rx\
1222			 vlzszhv9y00h77lpdvcjyhjtmalh5dn5e8n5w8cqle0vunzduu4nza9y0734qhxday9hzywl0aa0vhzy0qmphc\
1223			 64d4hduj08dv2krpgqtc2v83gptk34reelxyc7wsgnze890c6nrv6p0cmepatc269eayzjjkqk30n52rfl5dg7\
1224			 wztl96f7wc2tzx34q909xuajnyt4u4lnk87lwal7z0etdz5tmece0v3u796jfp68nccn05ty54ncfelts3v8g0\
1225			 sn6v6hsu87zat4r03368ersu87252dd0nswymxzc2pyxl8yy844hspuyj47w0px4u4leefq568sk0rr9th4ql9\
1226			 f9ykawrczkz5hp22nstg3lrlsa6u2q2ull3kzce2sh0h77sjv0zszhzy4hfh6u0pwux5l3gpthsn72mfu47sw9\
1227			 zw3hzk7srznp27z0etdp0725me00sn72mgkf0fteehruk0lg6swh34z52puaekzmjlmalhhe6m8ug7z3c8g8zh\
1228			 jjspp5zj0sm85g5ufng9w7s6p4ucdk80tyvz64sg54v0cy4vgnr37f78sqsp5l6azu2hv6we30er90jrslqpvd\
1229			 trnrphhesca2wg5q83k52rsu2cq9q2sqqqqqysgqcqr8h2np4qw0ha2k282hm8jh5rcfq0hsp2zhddtlc5vs23\
1230			 uphyv0lv3k8sqsfgfp4qyrk86tx5xg2aa7et4cdzhnvl5s4nd33ugytt7gamk9tugn9yransr9yq08gpwsn8t2\
1231			 tq4ducjfhrcz707av0ss20urjh8vldrpmehqxa0stkesvuq82txyqzfhej7qccswy7k5wvcppk63c6zpjytfda\
1232			 ccadacjtn52lpe6s85rjfqlxzp6frq33xshaz2nr9xjkhd3jj8qg39nmfzvpgmayakqmy9rseakwgcudug7hs4\
1233			 5wh430ywh7qhj3khczh8gle4cn93ymgfwa7rrvcw9lywyyz58k4p40a3nu9svthaf0qeg8f2ay4tw9p48p70qm\
1234			 ayu3ejl2q8pj9e2l22h7775tl44hs6ke4sdfgcr6aj8wra4r2v9sj6xa5chd5ctpfg8chtrer3kkp0e6af88lk\
1235			 rfxcklf2hyslv2hr0xl5lwrm5y5uttxn4ndfz8789znf78nspa3xy68"
1236		);
1237		// 1804 B regtest invoice from Lexe proptest
1238		parse_ok(
1239			"lnbcrt17124979001314909880p1y6lkcwgd76tfnxksfk2atyy4tzw4nyg6jrx3282s2ygvcxyj64gevhxsjk\
1240			 2ymhzv3e0p5h5u3kfey92jt9ge44gsfnwycxynm2g3unw3ntt9qh25texe98jcfhxvcxuezxw9tngwrndpy9s4\
1241			 p4x9eyze2tfe9rxm68tp5yj5jfduen2nny8prhsm6edegn2stww4n4gwp4vfjkvdthd43524n9fa8h262vwesk\
1242			 g66nw3vnyafn29zhsvfeg9mxummtfp35uumzfqmhy3jwgdh55mt5xpvhgmjn25uku5e5g939wmmnvdfygnrdgd\
1243			 h56uzcx4a92vfhgdcky3z9gfnrsvp4f4f55j68vak9yufhvdm8x5zrgc6955jvf429zumv89nh2a35wae5yntg\
1244			 v985jumpxehyv7t92pjrwufs89yh23f5ddy5s568wgchve3cg9ek5nzewgcrzjz0dftxg3nvf4hngje52ac4zm\
1245			 esxpvk6sfef4hkuetvd4vk6n29wftrw5rvg4yy2vjjwyexc5mnvfd8xknndpqkkenx0q642j35298hwve3dyc5\
1246			 25jrd3295sm9v9jrqup3wpykg7zd239ns7jgtqu95jz0deaxksjh2fu56n6n2f5x6mm8wa89qjfef385sam2x9\
1247			 mxcs20gfpnq460d3axzknnf3e4sw2kvf25wjjxddpyg52dw4vx7nn2w9cyu5t8vfnyxjtpg33kssjp24ch536p\
1248			 d938snmtx345x6r4x93kvv2tff855um3tfekxjted4kxys2kve5hvu6g89z4ynmjgfhnw7tv892rymejgvey77\
1249			 rcfqe9xjr92d85636fvajxyajndfa92k2nxycx5jtjx4zxsm2y2dyn2up50f5ku3nrfdk4g5npxehkzjjv8y69\
1250			 gveev4z56denddaxy7tfwe8xx42zgf6kzmnxxpk826ze2s6xk6jrwearw6ejvd8rsvj2fpg525jtd5pp5j2tlt\
1251			 28m4kakjr84w6ce4fd8e7awy6ncyswcyut760rdnem30ptssp5p5u3xgxxtr6aev8y2w9m30wcw3kyn7fgm8wm\
1252			 f8qw8wzrqt34zcvq9q2sqqqqqysgqcqypmw9xq8lllllllnp4qt36twam2ca08m3s7vnhre3c0j89589wyw4vd\
1253			 k7fln0lryxzkdcrur28qwqq3hnyt84vsasuldd2786eysdf4dyuggwsmvw2atftf7spkmpa9dd3efq5tenpqm2\
1254			 v7vcz2a4s0s7jnqpjn0srysnstnw5y5z9taxn0ue37aqgufxcdsj6f8a2m4pm9udppdzc4shsdqzzx0u0rm4xl\
1255			 js0dqz3c5zqyvglda7nsqvqfztmlyup7vyuadzav4zyuqwx90ev6nmk53nkhkt0sev9e745wxqtdvrqzgqkaka\
1256			 zen7e2qmsdauk665g3llg5qtl79t3xulrhjnducehdn72gpmkjvtth7kh6ejpl9dv0qcsxv2jvzzvg0hzdmk3y\
1257			 jsmydqksdk3h78kc63qnr265h8vyeslqexszppfm7y287t3gxvhw0ulg2wp0rsw3tevz03z50kpy77zdz9snxm\
1258			 kkwxd76xvj4qvj2f89rrnuvdvzw947ay0kydc077pkec2jet9qwp2tud98s24u65uz07eaxk5jk3e4nggn2caa\
1259			 ek2p5pkrc6mm6mxjm2ezpdu8p5jstg6tgvnttgac3ygt5ys04t4udujzlshpl7e4f3ff03xe6v24cp6aq4wa"
1260		);
1261		// 1870 B testnet invoice from Lexe proptest
1262		parse_ok(
1263			"lntb5826417333454665580p1c5rwh5edlhf33hvkj5vav5z3t02a5hxvj3vfv5kuny2f3yzj6zwf9hx3nn2fk\
1264			 9gepc2a3ywvj6dax5v3jy2d5nxmp3gaxhycjkv38hx4z4d4vyznrp2p24xa6t2pg4w4rrxfens6tcxdhxvvfhx\
1265			 a8xvvpkgat8xnpe2p44juz9g43hyur00989gvfhwd2kj72wfum4g4mgx5m5cs2rg9d9vnn6xe89ydnnvfpyy52\
1266			 s2dxx2er4x4xxwstdd5cxwdrjw3nkxnnv2uexxnrxw4t56sjswfn52s2xv4t8xmjtwpn8xm6sfeh4q526dyu8x\
1267			 3r9gceyw6fhd934qjttvdk57az5w368zdrhwfjxxu35xcmrsmmpd4g8wwtev4tkzutdd32k56mxveuy6c6v2em\
1268			 yv7zkfp39zjpjgd8hx7n4xph5kceswf6xxmnyfcuxca20fp24z7ncvfhyu5jf2exhw36nwf68s7rh2a6yzjf4d\
1269			 gukcenfxpchqsjn2pt5x334tf98wsm6dvcrvvfcwapxvk2cdvmk2npcfe68zue3w4f9xc6s2fvrw6nrg3fkskt\
1270			 e2ftxyc20ffckcd692964sdzjwdp4yvrfdfm9q72pxp3kwat5f4j9xee5da8rss60w92857tgwych55f5w3n8z\
1271			 mzexpy4jwredejrqm6txf3nxm64ffh8x460dp9yjazhw4yx6dm5xerysnn5wa455k3h2d89ss2fd9axwjp3f4r\
1272			 9qdmfd4fx6stx2eg9sezrv369w7nvvfvhj4nnwaz5z3ny8qcxcdnvwd64jc2nx9uy2e2gxdrnx6r3w9ykxatxx\
1273			 g6kk6rv2ekr2emwx5ehy362d3x82dzvddfxs5rcg4vn27npf564qdtg2anycc6523jnwe3e0p65unrpvccrs5m\
1274			 2fuexgmnj23ay5e34v4xk5jnrwpg4xemfwqe5vjjjw9qk76zsd9yrzu6xdpv5v5ntdejxg6jtv3kx65t6gdhrg\
1275			 vj3fe34sj2vv3h5kegpp57hjf5kv6clw97y2e063yuz0psrz9a6l49v836dflum00rh8qtn8qsp5gd29qycuze\
1276			 08xls8l32zjaaf2uqv78v97lg9ss0c699huw980h2q9q2sqqqqqysgqcqr8ulnp4q26hcfwr7qxz7lwwlr2kjc\
1277			 rws7m2u5j36mm0kxa45uxy6zvsqt2zzfppjdkrm2rlgadt9dq3d6jkv4r2cugmf2kamr28qwuleyzzyyly8a6t\
1278			 u70eldahx7hzxx5x9gms7vjjr577ps8n4qyds5nern39j0v7czkch2letnt46895jupxgehf208xgxz8d6j8gu\
1279			 3h2qqtsk9nr9nuquhkqjxw40h2ucpldrawmktxzxdgtkt9a3p95g98nywved8s8laj2a0c98rq5zzdnzddz6nd\
1280			 w0lvr6u0av9m7859844cgz9vpeq05gw79zqae2s7jzeq66wydyueqtp56qc67g7krv6lj5aahxtmq4y208q5qy\
1281			 z38cnwl9ma6m5f4nhzqaj0tjxpfrk4nr5arv9d20lvxvddvffhzygmyuvwd959uhdcgcgjejchqt2qncuwpqqk\
1282			 5vws7dflw8x6esrfwhz7h3jwmhevf445k76nme926sr8drsdveqg7l7t7lnjvhaludqnwk4l2pmevkjf9pla92\
1283			 4p77v76r7x8jzyy7h59hmk0lgzfsk6c8dpj37hssj7jt4q7jzvy8hq25l3pag37axxanjqnq56c47gpgy6frsy\
1284			 c0str9w2aahz4h6t7axaka4cwvhwg49r6qgj8kwz2mt6vcje25l9ekvmgq5spqtn"
1285		);
1286	}
1287
1288	// Generate a valid invoice of `MAX_LENGTH` bytes and ensure that it roundtrips.
1289	#[test]
1290	fn test_serde_long_invoice() {
1291		use crate::TaggedField::*;
1292		use crate::{
1293			Bolt11Invoice, Bolt11InvoiceFeatures, Bolt11InvoiceSignature, Currency,
1294			PositiveTimestamp, RawBolt11Invoice, RawDataPart, RawHrp, RawTaggedField, Sha256,
1295			SignedRawBolt11Invoice,
1296		};
1297		use bitcoin::secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
1298		use bitcoin::secp256k1::PublicKey;
1299		use lightning_types::routing::{RouteHint, RouteHintHop, RoutingFees};
1300
1301		// Generate an `UnknownSemantics` field with a given length.
1302		fn unknown_semantics_field(len: usize) -> Vec<Fe32> {
1303			assert!(len <= 1023);
1304			let mut field = Vec::with_capacity(len + 3);
1305			// Big-endian encoded length prefix
1306			field.push(Fe32::Q);
1307			field.push(Fe32::try_from((len >> 5) as u8).unwrap());
1308			field.push(Fe32::try_from((len & 0x1f) as u8).unwrap());
1309			// Data
1310			field.extend(std::iter::repeat(Fe32::P).take(len));
1311			field
1312		}
1313
1314		// Invoice fields
1315		let payment_hash = sha256::Hash::from_str(
1316			"0001020304050607080900010203040506070809000102030405060708090102",
1317		)
1318		.unwrap();
1319		let description = std::iter::repeat("A").take(639).collect::<String>();
1320		let fallback_addr = crate::Fallback::SegWitProgram {
1321			version: bitcoin::WitnessVersion::V0,
1322			program: vec![0; 32],
1323		};
1324		let payee_pk = PublicKey::from_slice(&[
1325			0x03, 0x24, 0x65, 0x3e, 0xac, 0x43, 0x44, 0x88, 0x00, 0x2c, 0xc0, 0x6b, 0xbf, 0xb7,
1326			0xf1, 0x0f, 0xe1, 0x89, 0x91, 0xe3, 0x5f, 0x9f, 0xe4, 0x30, 0x2d, 0xbe, 0xa6, 0xd2,
1327			0x35, 0x3d, 0xc0, 0xab, 0x1c,
1328		])
1329		.unwrap();
1330		let route_hints = std::iter::repeat(RouteHintHop {
1331			src_node_id: payee_pk,
1332			short_channel_id: 0x0102030405060708,
1333			fees: RoutingFees { base_msat: 1, proportional_millionths: 20 },
1334			cltv_expiry_delta: 3,
1335			htlc_minimum_msat: None,
1336			htlc_maximum_msat: None,
1337		})
1338		.take(12)
1339		.collect::<Vec<_>>();
1340
1341		// Build raw invoice
1342		let raw_invoice = RawBolt11Invoice {
1343			hrp: RawHrp {
1344				currency: Currency::Bitcoin,
1345				raw_amount: Some(10000000000000000010),
1346				si_prefix: Some(crate::SiPrefix::Pico),
1347			},
1348			data: RawDataPart {
1349				timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1350				tagged_fields: vec![
1351					PaymentHash(Sha256(payment_hash)).into(),
1352					Description(crate::Description::new(description).unwrap()).into(),
1353					PayeePubKey(crate::PayeePubKey(payee_pk)).into(),
1354					ExpiryTime(crate::ExpiryTime(std::time::Duration::from_secs(u64::MAX))).into(),
1355					MinFinalCltvExpiryDelta(crate::MinFinalCltvExpiryDelta(u64::MAX)).into(),
1356					Fallback(fallback_addr).into(),
1357					PrivateRoute(crate::PrivateRoute(RouteHint(route_hints))).into(),
1358					PaymentSecret(crate::PaymentSecret([17; 32])).into(),
1359					PaymentMetadata(vec![0x69; 639]).into(),
1360					Features(Bolt11InvoiceFeatures::from_le_bytes(vec![0xaa; 639])).into(),
1361					// This invoice is 4458 B w/o unknown semantics fields.
1362					// Need to add some non-standard fields to reach 7089 B limit.
1363					RawTaggedField::UnknownSemantics(unknown_semantics_field(1023)),
1364					RawTaggedField::UnknownSemantics(unknown_semantics_field(1023)),
1365					RawTaggedField::UnknownSemantics(unknown_semantics_field(576)),
1366				],
1367			},
1368		};
1369
1370		// Build signed invoice
1371		let hash = [
1372			0x75, 0x99, 0xe1, 0x51, 0x7f, 0xa1, 0x0e, 0xb5, 0xc0, 0x79, 0xb4, 0x6e, 0x8e, 0x62,
1373			0x0c, 0x4f, 0xb0, 0x72, 0x71, 0xd2, 0x81, 0xa1, 0x92, 0x65, 0x9c, 0x90, 0x89, 0x69,
1374			0xe1, 0xf3, 0xd6, 0x59,
1375		];
1376		let signature = &[
1377			0x6c, 0xbe, 0xbe, 0xfe, 0xd3, 0xfb, 0x07, 0x68, 0xb5, 0x79, 0x98, 0x82, 0x29, 0xab,
1378			0x0e, 0xcc, 0x8d, 0x3a, 0x81, 0xee, 0xee, 0x07, 0xb3, 0x5d, 0x64, 0xca, 0xb4, 0x12,
1379			0x33, 0x99, 0x33, 0x2a, 0x31, 0xc2, 0x2c, 0x2b, 0x62, 0x96, 0x4e, 0x37, 0xd7, 0x96,
1380			0x50, 0x5e, 0xdb, 0xe9, 0xa9, 0x5b, 0x0b, 0x3b, 0x87, 0x22, 0x89, 0xed, 0x95, 0xf1,
1381			0xf1, 0xdf, 0x2d, 0xb6, 0xbd, 0xf5, 0x0a, 0x20,
1382		];
1383		let signature = Bolt11InvoiceSignature(
1384			RecoverableSignature::from_compact(signature, RecoveryId::from_i32(1).unwrap())
1385				.unwrap(),
1386		);
1387		let signed_invoice = SignedRawBolt11Invoice { raw_invoice, hash, signature };
1388
1389		// Ensure serialized invoice roundtrips
1390		let invoice = Bolt11Invoice::from_signed(signed_invoice).unwrap();
1391		let invoice_str = invoice.to_string();
1392		assert_eq!(invoice_str.len(), crate::MAX_LENGTH);
1393		assert_eq!(invoice, Bolt11Invoice::from_str(&invoice_str).unwrap());
1394	}
1395
1396	// Test that invoices above the maximum length fail to parse with the expected error.
1397	#[test]
1398	fn test_deser_too_long_fails() {
1399		use crate::{Bolt11Invoice, ParseOrSemanticError, MAX_LENGTH};
1400		use bech32::primitives::decode::{CheckedHrpstringError, ChecksumError};
1401
1402		fn parse_is_code_length_err(s: &str) -> bool {
1403			// Need matches! b/c ChecksumError::CodeLength(_) is marked non-exhaustive
1404			matches!(
1405				Bolt11Invoice::from_str(s),
1406				Err(ParseOrSemanticError::ParseError(Bolt11ParseError::Bech32Error(
1407					CheckedHrpstringError::Checksum(ChecksumError::CodeLength(_))
1408				))),
1409			)
1410		}
1411
1412		let mut too_long = String::from("lnbc1");
1413		too_long.push_str(
1414			String::from_utf8(vec![b'x'; (MAX_LENGTH + 1) - too_long.len()]).unwrap().as_str(),
1415		);
1416		assert!(parse_is_code_length_err(&too_long));
1417		assert!(!parse_is_code_length_err(&too_long[..too_long.len() - 1]));
1418	}
1419}