lightning_invoice/
ser.rs

1use alloc::boxed::Box;
2use core::fmt;
3use core::fmt::{Display, Formatter};
4use core::{array, iter};
5
6use crate::prelude::*;
7use bech32::{ByteIterExt, Fe32, Fe32IterExt};
8
9use super::{
10	constants, Bolt11Invoice, Bolt11InvoiceFeatures, Bolt11InvoiceSignature, Currency, Description,
11	ExpiryTime, Fallback, MinFinalCltvExpiryDelta, PayeePubKey, PaymentSecret, PositiveTimestamp,
12	PrivateRoute, RawDataPart, RawHrp, RawTaggedField, RouteHintHop, Sha256, SiPrefix,
13	SignedRawBolt11Invoice, TaggedField,
14};
15
16/// Objects that can be encoded to base32 (bech32).
17///
18/// Private to this crate to avoid polluting the API.
19pub trait Base32Iterable {
20	/// apoelstra: In future we want to replace this Box<dyn Iterator> with an explicit
21	/// associated type, to avoid the allocation. But we cannot do this until
22	/// Rust 1.65 and GATs since the iterator may contain a reference to self.
23	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's>;
24}
25
26/// Interface to calculate the length of the base32 representation before actually serializing
27pub(crate) trait Base32Len: Base32Iterable {
28	/// Calculate the bech32 serialized length
29	fn base32_len(&self) -> usize;
30}
31
32// Base32Iterable & Base32Len implementations are here, because the traits are in this module.
33
34impl<const N: usize> Base32Iterable for [u8; N] {
35	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
36		self[..].fe_iter()
37	}
38}
39
40impl<const N: usize> Base32Len for [u8; N] {
41	/// Calculate the base32 serialized length
42	fn base32_len(&self) -> usize {
43		bytes_size_to_base32_size(N)
44	}
45}
46
47impl Base32Iterable for [u8] {
48	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
49		Box::new(self.iter().copied().bytes_to_fes())
50	}
51}
52
53impl Base32Len for [u8] {
54	/// Calculate the base32 serialized length
55	fn base32_len(&self) -> usize {
56		bytes_size_to_base32_size(self.len())
57	}
58}
59
60impl Base32Iterable for Vec<u8> {
61	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
62		Box::new(self.iter().copied().bytes_to_fes())
63	}
64}
65
66impl Base32Len for Vec<u8> {
67	/// Calculate the base32 serialized length
68	fn base32_len(&self) -> usize {
69		bytes_size_to_base32_size(self.len())
70	}
71}
72
73impl Base32Iterable for PaymentSecret {
74	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
75		Box::new(self.0[..].fe_iter())
76	}
77}
78
79impl Base32Len for PaymentSecret {
80	fn base32_len(&self) -> usize {
81		52
82	}
83}
84
85impl Base32Iterable for Bolt11InvoiceFeatures {
86	/// Convert to 5-bit values, by unpacking the 5 bit groups,
87	/// putting the bytes from right-to-left,
88	/// starting from the rightmost bit,
89	/// and taking the resulting 5-bit values in reverse (left-to-right),
90	/// with the leading 0's skipped.
91	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
92		// Fe32 conversion cannot be used, because this packs from right, right-to-left
93		let mut input_iter = self.le_flags().iter();
94		// Carry bits, 0..7 bits
95		let mut carry = 0u8;
96		let mut carry_bits = 0;
97		let mut output = Vec::<Fe32>::new();
98
99		loop {
100			let next_out8 = if carry_bits >= 5 {
101				// We have enough carry bits for an output, no need to read the input
102				let next_out8 = carry;
103				carry >>= 5;
104				carry_bits -= 5;
105				next_out8
106			} else {
107				// take next byte
108				if let Some(curr_in) = input_iter.next() {
109					// we have at least one Fe32 to output (maybe two)
110					// For combining with carry '|', '^', or '+' can be used (disjoint bit positions)
111					let next_out8 = carry + (curr_in << carry_bits);
112					carry = curr_in >> (5 - carry_bits);
113					carry_bits += 3; // added 8, removed 5
114					next_out8
115				} else {
116					// No more inputs, output remaining (if any)
117					if carry_bits > 0 {
118						carry_bits = 0;
119						carry
120					} else {
121						break;
122					}
123				}
124			};
125			// Isolate the 5 right bits
126			output.push(Fe32::try_from(next_out8 & 31u8).expect("<32"))
127		}
128		// Take result in reverse order, and skip leading 0s
129		Box::new(output.into_iter().rev().skip_while(|e| *e == Fe32::Q))
130	}
131}
132
133impl Base32Len for Bolt11InvoiceFeatures {
134	fn base32_len(&self) -> usize {
135		// Here we perform the real conversion, due to trimming it's hard to estimate
136		self.fe_iter().count()
137	}
138}
139
140/// Calculates the base32 encoded size of a byte slice
141fn bytes_size_to_base32_size(byte_size: usize) -> usize {
142	let bits = byte_size * 8;
143	if bits % 5 == 0 {
144		// without padding bits
145		bits / 5
146	} else {
147		// with padding bits
148		bits / 5 + 1
149	}
150}
151
152impl Display for Bolt11Invoice {
153	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
154		self.signed_invoice.fmt(f)
155	}
156}
157
158impl Display for SignedRawBolt11Invoice {
159	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
160		let hrp = self.raw_invoice.hrp.to_hrp();
161		for ch in self
162			.raw_invoice
163			.data
164			.fe_iter()
165			.chain(self.signature.fe_iter())
166			.with_checksum::<bech32::Bech32>(&hrp)
167			.chars()
168		{
169			write!(f, "{}", ch)?;
170		}
171		Ok(())
172	}
173}
174
175/// This is not exported to bindings users
176impl Display for RawHrp {
177	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
178		let amount = match self.raw_amount {
179			Some(ref amt) => amt.to_string(),
180			None => String::new(),
181		};
182
183		let si_prefix = match self.si_prefix {
184			Some(ref si) => si.to_string(),
185			None => String::new(),
186		};
187
188		write!(f, "ln{}{}{}", self.currency, amount, si_prefix)
189	}
190}
191
192impl Display for Currency {
193	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
194		let currency_code = match *self {
195			Currency::Bitcoin => "bc",
196			Currency::BitcoinTestnet => "tb",
197			Currency::Regtest => "bcrt",
198			Currency::Simnet => "sb",
199			Currency::Signet => "tbs",
200		};
201		write!(f, "{}", currency_code)
202	}
203}
204
205impl Display for SiPrefix {
206	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
207		write!(
208			f,
209			"{}",
210			match *self {
211				SiPrefix::Milli => "m",
212				SiPrefix::Micro => "u",
213				SiPrefix::Nano => "n",
214				SiPrefix::Pico => "p",
215			}
216		)
217	}
218}
219
220/// Encode an integer to base32, big endian, without leading zeros
221fn encode_int_be_base32(int: u64) -> impl ExactSizeIterator<Item = Fe32> {
222	let base = 32u64;
223
224	// (64 + 4) / 5 == 13
225	let mut out = [Fe32::Q; 13];
226	let mut out_pos = 0;
227	let mut rem_int = int;
228	while rem_int != 0 {
229		out[out_pos] = Fe32::try_from((rem_int % base) as u8).expect("always <32");
230		out_pos += 1;
231		rem_int /= base;
232	}
233
234	out.into_iter().take(out_pos).rev()
235}
236
237/// The length of the output of `encode_int_be_base32`.
238fn encoded_int_be_base32_size(int: u64) -> usize {
239	let bit_len = 64 - int.leading_zeros() as usize; // cast ok as value is in 0..=64.
240	(bit_len + 4) / 5
241}
242
243impl Base32Iterable for RawDataPart {
244	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
245		let ts_iter = self.timestamp.fe_iter();
246		let fields_iter = self.tagged_fields.iter().map(RawTaggedField::fe_iter).flatten();
247		Box::new(ts_iter.chain(fields_iter))
248	}
249}
250
251impl Base32Iterable for PositiveTimestamp {
252	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
253		let fes = encode_int_be_base32(self.as_unix_timestamp());
254		debug_assert!(fes.len() <= 7, "Invalid timestamp length");
255		let to_pad = 7 - fes.len();
256		Box::new(core::iter::repeat(Fe32::Q).take(to_pad).chain(fes))
257	}
258}
259
260impl Base32Iterable for RawTaggedField {
261	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
262		// Annoyingly, when we move to explicit types, we will need an
263		// explicit enum holding the two iterator variants.
264		match *self {
265			RawTaggedField::UnknownSemantics(ref content) => Box::new(content.iter().copied()),
266			RawTaggedField::KnownSemantics(ref tagged_field) => tagged_field.fe_iter(),
267		}
268	}
269}
270
271impl Base32Iterable for Sha256 {
272	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
273		Box::new(self.0[..].fe_iter())
274	}
275}
276
277impl Base32Len for Sha256 {
278	fn base32_len(&self) -> usize {
279		self.0[..].base32_len()
280	}
281}
282
283impl Base32Iterable for Description {
284	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
285		Box::new(self.0 .0.as_bytes().fe_iter())
286	}
287}
288
289impl Base32Len for Description {
290	fn base32_len(&self) -> usize {
291		self.0 .0.as_bytes().base32_len()
292	}
293}
294
295impl Base32Iterable for PayeePubKey {
296	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
297		Box::new(self.serialize().into_iter().bytes_to_fes())
298	}
299}
300
301impl Base32Len for PayeePubKey {
302	fn base32_len(&self) -> usize {
303		bytes_size_to_base32_size(bitcoin::secp256k1::constants::PUBLIC_KEY_SIZE)
304	}
305}
306
307impl Base32Iterable for ExpiryTime {
308	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
309		Box::new(encode_int_be_base32(self.as_seconds()))
310	}
311}
312
313impl Base32Len for ExpiryTime {
314	fn base32_len(&self) -> usize {
315		encoded_int_be_base32_size(self.0.as_secs())
316	}
317}
318
319impl Base32Iterable for MinFinalCltvExpiryDelta {
320	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
321		Box::new(encode_int_be_base32(self.0))
322	}
323}
324
325impl Base32Len for MinFinalCltvExpiryDelta {
326	fn base32_len(&self) -> usize {
327		encoded_int_be_base32_size(self.0)
328	}
329}
330
331impl Base32Iterable for Fallback {
332	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
333		Box::new(match *self {
334			Fallback::SegWitProgram { version: v, program: ref p } => {
335				let v = Fe32::try_from(v.to_num()).expect("valid version");
336				core::iter::once(v).chain(p[..].fe_iter())
337			},
338			Fallback::PubKeyHash(ref hash) => {
339				// 17 '3'
340				core::iter::once(Fe32::_3).chain(hash[..].fe_iter())
341			},
342			Fallback::ScriptHash(ref hash) => {
343				// 18 'J'
344				core::iter::once(Fe32::J).chain(hash[..].fe_iter())
345			},
346		})
347	}
348}
349
350impl Base32Len for Fallback {
351	fn base32_len(&self) -> usize {
352		match *self {
353			Fallback::SegWitProgram { program: ref p, .. } => {
354				bytes_size_to_base32_size(p.len()) + 1
355			},
356			Fallback::PubKeyHash(_) | Fallback::ScriptHash(_) => 33,
357		}
358	}
359}
360
361// Shorthand type
362type RouteHintHopIter = iter::Chain<
363	iter::Chain<
364		iter::Chain<
365			iter::Chain<array::IntoIter<u8, 33>, array::IntoIter<u8, 8>>,
366			array::IntoIter<u8, 4>,
367		>,
368		array::IntoIter<u8, 4>,
369	>,
370	array::IntoIter<u8, 2>,
371>;
372
373impl Base32Iterable for PrivateRoute {
374	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
375		fn serialize_to_iter(hop: &RouteHintHop) -> RouteHintHopIter {
376			let i1 = hop.src_node_id.serialize().into_iter();
377			let i2 = u64::to_be_bytes(hop.short_channel_id).into_iter();
378			let i3 = u32::to_be_bytes(hop.fees.base_msat).into_iter();
379			let i4 = u32::to_be_bytes(hop.fees.proportional_millionths).into_iter();
380			let i5 = u16::to_be_bytes(hop.cltv_expiry_delta).into_iter();
381			i1.chain(i2).chain(i3).chain(i4).chain(i5)
382		}
383
384		Box::new(self.0 .0.iter().map(serialize_to_iter).flatten().bytes_to_fes())
385	}
386}
387
388impl Base32Len for PrivateRoute {
389	fn base32_len(&self) -> usize {
390		bytes_size_to_base32_size((self.0).0.len() * 51)
391	}
392}
393
394// Shorthand type
395type TaggedFieldIter<I> = core::iter::Chain<core::array::IntoIter<Fe32, 3>, I>;
396
397impl Base32Iterable for TaggedField {
398	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
399		/// Writes a tagged field: tag, length and data. `tag` should be in `0..32` otherwise the
400		/// function will panic.
401		fn write_tagged_field<'s, P>(
402			tag: u8, payload: &'s P,
403		) -> TaggedFieldIter<Box<dyn Iterator<Item = Fe32> + 's>>
404		where
405			P: Base32Iterable + Base32Len + ?Sized,
406		{
407			let len = payload.base32_len();
408			assert!(len < 1024, "Every tagged field data can be at most 1023 bytes long.");
409
410			[
411				Fe32::try_from(tag).expect("invalid tag, not in 0..32"),
412				Fe32::try_from((len / 32) as u8).expect("< 32"),
413				Fe32::try_from((len % 32) as u8).expect("< 32"),
414			]
415			.into_iter()
416			.chain(payload.fe_iter())
417		}
418
419		// we will also need a giant enum for this
420		Box::new(match *self {
421			TaggedField::PaymentHash(ref hash) => {
422				write_tagged_field(constants::TAG_PAYMENT_HASH, hash)
423			},
424			TaggedField::Description(ref description) => {
425				write_tagged_field(constants::TAG_DESCRIPTION, description)
426			},
427			TaggedField::PayeePubKey(ref pub_key) => {
428				write_tagged_field(constants::TAG_PAYEE_PUB_KEY, pub_key)
429			},
430			TaggedField::DescriptionHash(ref hash) => {
431				write_tagged_field(constants::TAG_DESCRIPTION_HASH, hash)
432			},
433			TaggedField::ExpiryTime(ref duration) => {
434				write_tagged_field(constants::TAG_EXPIRY_TIME, duration)
435			},
436			TaggedField::MinFinalCltvExpiryDelta(ref expiry) => {
437				write_tagged_field(constants::TAG_MIN_FINAL_CLTV_EXPIRY_DELTA, expiry)
438			},
439			TaggedField::Fallback(ref fallback_address) => {
440				write_tagged_field(constants::TAG_FALLBACK, fallback_address)
441			},
442			TaggedField::PrivateRoute(ref route_hops) => {
443				write_tagged_field(constants::TAG_PRIVATE_ROUTE, route_hops)
444			},
445			TaggedField::PaymentSecret(ref payment_secret) => {
446				write_tagged_field(constants::TAG_PAYMENT_SECRET, payment_secret)
447			},
448			TaggedField::PaymentMetadata(ref payment_metadata) => {
449				write_tagged_field(constants::TAG_PAYMENT_METADATA, payment_metadata)
450			},
451			TaggedField::Features(ref features) => {
452				write_tagged_field(constants::TAG_FEATURES, features)
453			},
454		})
455	}
456}
457
458impl Base32Iterable for Bolt11InvoiceSignature {
459	fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
460		let (recovery_id, signature) = self.0.serialize_compact();
461		Box::new(
462			signature
463				.into_iter()
464				.chain(core::iter::once(recovery_id.to_i32() as u8))
465				.bytes_to_fes(),
466		)
467	}
468}
469
470#[cfg(test)]
471mod test {
472	#[test]
473	fn test_currency_code() {
474		use crate::Currency;
475
476		assert_eq!("bc", Currency::Bitcoin.to_string());
477		assert_eq!("tb", Currency::BitcoinTestnet.to_string());
478		assert_eq!("bcrt", Currency::Regtest.to_string());
479		assert_eq!("sb", Currency::Simnet.to_string());
480		assert_eq!("tbs", Currency::Signet.to_string());
481	}
482
483	#[test]
484	fn test_raw_hrp() {
485		use crate::{Currency, RawHrp, SiPrefix};
486
487		let hrp = RawHrp {
488			currency: Currency::Bitcoin,
489			raw_amount: Some(100),
490			si_prefix: Some(SiPrefix::Micro),
491		};
492
493		assert_eq!(hrp.to_string(), "lnbc100u");
494	}
495
496	#[test]
497	fn test_encode_int_be_base32() {
498		use crate::ser::encode_int_be_base32;
499		use bech32::Fe32;
500
501		let input: u64 = 33764;
502		let expected_out = [1, 0, 31, 4]
503			.iter()
504			.copied()
505			.map(|v| Fe32::try_from(v).expect("<= 31"))
506			.collect::<Vec<Fe32>>();
507
508		assert_eq!(expected_out, encode_int_be_base32(input).collect::<Vec<Fe32>>());
509	}
510}