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
16pub trait Base32Iterable {
20 fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's>;
24}
25
26pub(crate) trait Base32Len: Base32Iterable {
28 fn base32_len(&self) -> usize;
30}
31
32impl<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 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 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 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 fn fe_iter<'s>(&'s self) -> Box<dyn Iterator<Item = Fe32> + 's> {
92 let mut input_iter = self.le_flags().iter();
94 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 let next_out8 = carry;
103 carry >>= 5;
104 carry_bits -= 5;
105 next_out8
106 } else {
107 if let Some(curr_in) = input_iter.next() {
109 let next_out8 = carry + (curr_in << carry_bits);
112 carry = curr_in >> (5 - carry_bits);
113 carry_bits += 3; next_out8
115 } else {
116 if carry_bits > 0 {
118 carry_bits = 0;
119 carry
120 } else {
121 break;
122 }
123 }
124 };
125 output.push(Fe32::try_from(next_out8 & 31u8).expect("<32"))
127 }
128 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 self.fe_iter().count()
137 }
138}
139
140fn bytes_size_to_base32_size(byte_size: usize) -> usize {
142 let bits = byte_size * 8;
143 if bits % 5 == 0 {
144 bits / 5
146 } else {
147 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
175impl 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
220fn encode_int_be_base32(int: u64) -> impl ExactSizeIterator<Item = Fe32> {
222 let base = 32u64;
223
224 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
237fn encoded_int_be_base32_size(int: u64) -> usize {
239 let bit_len = 64 - int.leading_zeros() as usize; (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 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 core::iter::once(Fe32::_3).chain(hash[..].fe_iter())
341 },
342 Fallback::ScriptHash(ref hash) => {
343 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
361type 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
394type 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 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 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}