]> git.bitcoin.ninja Git - rust-lightning/blob - lightning-invoice/src/de.rs
Merge pull request #1706 from jkczyz/2022-09-filtered-blocks
[rust-lightning] / lightning-invoice / src / de.rs
1 #[cfg(feature = "std")]
2 use std::error;
3 use core::fmt;
4 use core::fmt::{Display, Formatter};
5 use core::num::ParseIntError;
6 use core::str;
7 use core::str::FromStr;
8
9 use bech32;
10 use bech32::{u5, FromBase32};
11
12 use bitcoin_hashes::Hash;
13 use bitcoin_hashes::sha256;
14 use crate::prelude::*;
15 use lightning::ln::PaymentSecret;
16 use lightning::routing::gossip::RoutingFees;
17 use lightning::routing::router::{RouteHint, RouteHintHop};
18
19 use num_traits::{CheckedAdd, CheckedMul};
20
21 use secp256k1;
22 use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
23 use secp256k1::PublicKey;
24
25 use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiry, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
26         SemanticError, PrivateRoute, ParseError, ParseOrSemanticError, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawInvoice,
27         constants, SignedRawInvoice, RawDataPart, InvoiceFeatures};
28
29 use self::hrp_sm::parse_hrp;
30
31 /// State machine to parse the hrp
32 mod hrp_sm {
33         use core::ops::Range;
34
35         #[derive(PartialEq, Eq, Debug)]
36         enum States {
37                 Start,
38                 ParseL,
39                 ParseN,
40                 ParseCurrencyPrefix,
41                 ParseAmountNumber,
42                 ParseAmountSiPrefix,
43         }
44
45         impl States {
46                 fn next_state(&self, read_symbol: char) -> Result<States, super::ParseError> {
47                         match *self {
48                                 States::Start => {
49                                         if read_symbol == 'l' {
50                                                 Ok(States::ParseL)
51                                         } else {
52                                                 Err(super::ParseError::MalformedHRP)
53                                         }
54                                 }
55                                 States::ParseL => {
56                                         if read_symbol == 'n' {
57                                                 Ok(States::ParseN)
58                                         } else {
59                                                 Err(super::ParseError::MalformedHRP)
60                                         }
61                                 },
62                                 States::ParseN => {
63                                         if !read_symbol.is_numeric() {
64                                                 Ok(States::ParseCurrencyPrefix)
65                                         } else {
66                                                 Ok(States::ParseAmountNumber)
67                                         }
68                                 },
69                                 States::ParseCurrencyPrefix => {
70                                         if !read_symbol.is_numeric() {
71                                                 Ok(States::ParseCurrencyPrefix)
72                                         } else {
73                                                 Ok(States::ParseAmountNumber)
74                                         }
75                                 },
76                                 States::ParseAmountNumber => {
77                                         if read_symbol.is_numeric() {
78                                                 Ok(States::ParseAmountNumber)
79                                         } else if ['m', 'u', 'n', 'p'].contains(&read_symbol) {
80                                                 Ok(States::ParseAmountSiPrefix)
81                                         } else {
82                                                 Err(super::ParseError::UnknownSiPrefix)
83                                         }
84                                 },
85                                 States::ParseAmountSiPrefix => Err(super::ParseError::MalformedHRP),
86                         }
87                 }
88
89                 fn is_final(&self) -> bool {
90                         !(*self == States::ParseL || *self == States::ParseN)
91                 }
92         }
93
94
95         struct StateMachine {
96                 state: States,
97                 position: usize,
98                 currency_prefix: Option<Range<usize>>,
99                 amount_number: Option<Range<usize>>,
100                 amount_si_prefix: Option<Range<usize>>,
101         }
102
103         impl StateMachine {
104                 fn new() -> StateMachine {
105                         StateMachine {
106                                 state: States::Start,
107                                 position: 0,
108                                 currency_prefix: None,
109                                 amount_number: None,
110                                 amount_si_prefix: None,
111                         }
112                 }
113
114                 fn update_range(range: &mut Option<Range<usize>>, position: usize) {
115                         let new_range = match *range {
116                                 None => Range {start: position, end: position + 1},
117                                 Some(ref r) => Range {start: r.start, end: r.end + 1},
118                         };
119                         *range = Some(new_range);
120                 }
121
122                 fn step(&mut self, c: char) -> Result<(), super::ParseError> {
123                         let next_state = self.state.next_state(c)?;
124                         match next_state {
125                                 States::ParseCurrencyPrefix => {
126                                         StateMachine::update_range(&mut self.currency_prefix, self.position)
127                                 }
128                                 States::ParseAmountNumber => {
129                                         StateMachine::update_range(&mut self.amount_number, self.position)
130                                 },
131                                 States::ParseAmountSiPrefix => {
132                                         StateMachine::update_range(&mut self.amount_si_prefix, self.position)
133                                 },
134                                 _ => {}
135                         }
136
137                         self.position += 1;
138                         self.state = next_state;
139                         Ok(())
140                 }
141
142                 fn is_final(&self) -> bool {
143                         self.state.is_final()
144                 }
145
146                 fn currency_prefix(&self) -> &Option<Range<usize>> {
147                         &self.currency_prefix
148                 }
149
150                 fn amount_number(&self) -> &Option<Range<usize>> {
151                         &self.amount_number
152                 }
153
154                 fn amount_si_prefix(&self) -> &Option<Range<usize>> {
155                         &self.amount_si_prefix
156                 }
157         }
158
159         pub fn parse_hrp(input: &str) -> Result<(&str, &str, &str), super::ParseError> {
160                 let mut sm = StateMachine::new();
161                 for c in input.chars() {
162                         sm.step(c)?;
163                 }
164
165                 if !sm.is_final() {
166                         return Err(super::ParseError::MalformedHRP);
167                 }
168
169                 let currency = sm.currency_prefix().clone()
170                         .map(|r| &input[r]).unwrap_or("");
171                 let amount = sm.amount_number().clone()
172                         .map(|r| &input[r]).unwrap_or("");
173                 let si = sm.amount_si_prefix().clone()
174                         .map(|r| &input[r]).unwrap_or("");
175
176                 Ok((currency, amount, si))
177         }
178 }
179
180
181 impl FromStr for super::Currency {
182         type Err = ParseError;
183
184         fn from_str(currency_prefix: &str) -> Result<Self, ParseError> {
185                 match currency_prefix {
186                         "bc" => Ok(Currency::Bitcoin),
187                         "tb" => Ok(Currency::BitcoinTestnet),
188                         "bcrt" => Ok(Currency::Regtest),
189                         "sb" => Ok(Currency::Simnet),
190                         "tbs" => Ok(Currency::Signet),
191                         _ => Err(ParseError::UnknownCurrency)
192                 }
193         }
194 }
195
196 impl FromStr for SiPrefix {
197         type Err = ParseError;
198
199         fn from_str(currency_prefix: &str) -> Result<Self, ParseError> {
200                 use SiPrefix::*;
201                 match currency_prefix {
202                         "m" => Ok(Milli),
203                         "u" => Ok(Micro),
204                         "n" => Ok(Nano),
205                         "p" => Ok(Pico),
206                         _ => Err(ParseError::UnknownSiPrefix)
207                 }
208         }
209 }
210
211 /// ```
212 /// use lightning_invoice::Invoice;
213 ///
214 ///
215 /// let invoice = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\
216 /// h2pu5qc7lgq0xs578ngs6s0s68ua4h7cvspp5q6rmq35js88zp5dvwrv9m459tnk2zunwj5jalqtyxqulh0l\
217 /// 5gflssp5nf55ny5gcrfl30xuhzj3nphgj27rstekmr9fw3ny5989s300gyus9qyysgqcqpcrzjqw2sxwe993\
218 /// h5pcm4dxzpvttgza8zhkqxpgffcrf5v25nwpr3cmfg7z54kuqq8rgqqqqqqqq2qqqqq9qq9qrzjqd0ylaqcl\
219 /// j9424x9m8h2vcukcgnm6s56xfgu3j78zyqzhgs4hlpzvznlugqq9vsqqqqqqqlgqqqqqeqq9qrzjqwldmj9d\
220 /// ha74df76zhx6l9we0vjdquygcdt3kssupehe64g6yyp5yz5rhuqqwccqqyqqqqlgqqqqjcqq9qrzjqf9e58a\
221 /// guqr0rcun0ajlvmzq3ek63cw2w282gv3z5uupmuwvgjtq2z55qsqqg6qqqyqqqrtnqqqzq3cqygrzjqvphms\
222 /// ywntrrhqjcraumvc4y6r8v4z5v593trte429v4hredj7ms5z52usqq9ngqqqqqqqlgqqqqqqgq9qrzjq2v0v\
223 /// p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\
224 /// 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
225 /// j5r6drg6k6zcqj0fcwg";
226 ///
227 /// assert!(invoice.parse::<Invoice>().is_ok());
228 /// ```
229 impl FromStr for Invoice {
230         type Err = ParseOrSemanticError;
231
232         fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
233                 let signed = s.parse::<SignedRawInvoice>()?;
234                 Ok(Invoice::from_signed(signed)?)
235         }
236 }
237
238 /// ```
239 /// use lightning_invoice::*;
240 ///
241 /// let invoice = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\
242 /// h2pu5qc7lgq0xs578ngs6s0s68ua4h7cvspp5q6rmq35js88zp5dvwrv9m459tnk2zunwj5jalqtyxqulh0l\
243 /// 5gflssp5nf55ny5gcrfl30xuhzj3nphgj27rstekmr9fw3ny5989s300gyus9qyysgqcqpcrzjqw2sxwe993\
244 /// h5pcm4dxzpvttgza8zhkqxpgffcrf5v25nwpr3cmfg7z54kuqq8rgqqqqqqqq2qqqqq9qq9qrzjqd0ylaqcl\
245 /// j9424x9m8h2vcukcgnm6s56xfgu3j78zyqzhgs4hlpzvznlugqq9vsqqqqqqqlgqqqqqeqq9qrzjqwldmj9d\
246 /// ha74df76zhx6l9we0vjdquygcdt3kssupehe64g6yyp5yz5rhuqqwccqqyqqqqlgqqqqjcqq9qrzjqf9e58a\
247 /// guqr0rcun0ajlvmzq3ek63cw2w282gv3z5uupmuwvgjtq2z55qsqqg6qqqyqqqrtnqqqzq3cqygrzjqvphms\
248 /// ywntrrhqjcraumvc4y6r8v4z5v593trte429v4hredj7ms5z52usqq9ngqqqqqqqlgqqqqqqgq9qrzjq2v0v\
249 /// p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\
250 /// 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
251 /// j5r6drg6k6zcqj0fcwg";
252 ///
253 /// let parsed_1 = invoice.parse::<Invoice>();
254 ///
255 /// let parsed_2 = match invoice.parse::<SignedRawInvoice>() {
256 ///     Ok(signed) => match Invoice::from_signed(signed) {
257 ///             Ok(invoice) => Ok(invoice),
258 ///             Err(e) => Err(ParseOrSemanticError::SemanticError(e)),
259 ///     },
260 ///     Err(e) => Err(ParseOrSemanticError::ParseError(e)),
261 /// };
262 ///
263 /// assert!(parsed_1.is_ok());
264 /// assert_eq!(parsed_1, parsed_2);
265 /// ```
266 impl FromStr for SignedRawInvoice {
267         type Err = ParseError;
268
269         fn from_str(s: &str) -> Result<Self, Self::Err> {
270                 let (hrp, data, var) = bech32::decode(s)?;
271
272                 if var == bech32::Variant::Bech32m {
273                         // Consider Bech32m addresses to be "Invalid Checksum", since that is what we'd get if
274                         // we didn't support Bech32m (which lightning does not use).
275                         return Err(ParseError::Bech32Error(bech32::Error::InvalidChecksum));
276                 }
277
278                 if data.len() < 104 {
279                         return Err(ParseError::TooShortDataPart);
280                 }
281
282                 let raw_hrp: RawHrp = hrp.parse()?;
283                 let data_part = RawDataPart::from_base32(&data[..data.len()-104])?;
284
285                 Ok(SignedRawInvoice {
286                         raw_invoice: RawInvoice {
287                                 hrp: raw_hrp,
288                                 data: data_part,
289                         },
290                         hash: RawInvoice::hash_from_parts(
291                                 hrp.as_bytes(),
292                                 &data[..data.len()-104]
293                         ),
294                         signature: InvoiceSignature::from_base32(&data[data.len()-104..])?,
295                 })
296         }
297 }
298
299 impl FromStr for RawHrp {
300         type Err = ParseError;
301
302         fn from_str(hrp: &str) -> Result<Self, <Self as FromStr>::Err> {
303                 let parts = parse_hrp(hrp)?;
304
305                 let currency = parts.0.parse::<Currency>()?;
306
307                 let amount = if !parts.1.is_empty() {
308                         Some(parts.1.parse::<u64>()?)
309                 } else {
310                         None
311                 };
312
313                 let si_prefix: Option<SiPrefix> = if parts.2.is_empty() {
314                         None
315                 } else {
316                         let si: SiPrefix = parts.2.parse()?;
317                         if let Some(amt) = amount {
318                                 if amt.checked_mul(si.multiplier()).is_none() {
319                                         return Err(ParseError::IntegerOverflowError);
320                                 }
321                         }
322                         Some(si)
323                 };
324
325                 Ok(RawHrp {
326                         currency: currency,
327                         raw_amount: amount,
328                         si_prefix: si_prefix,
329                 })
330         }
331 }
332
333 impl FromBase32 for RawDataPart {
334         type Err = ParseError;
335
336         fn from_base32(data: &[u5]) -> Result<Self, Self::Err> {
337                 if data.len() < 7 { // timestamp length
338                         return Err(ParseError::TooShortDataPart);
339                 }
340
341                 let timestamp = PositiveTimestamp::from_base32(&data[0..7])?;
342                 let tagged = parse_tagged_parts(&data[7..])?;
343
344                 Ok(RawDataPart {
345                         timestamp: timestamp,
346                         tagged_fields: tagged,
347                 })
348         }
349 }
350
351 impl FromBase32 for PositiveTimestamp {
352         type Err = ParseError;
353
354         fn from_base32(b32: &[u5]) -> Result<Self, Self::Err> {
355                 if b32.len() != 7 {
356                         return Err(ParseError::InvalidSliceLength("PositiveTimestamp::from_base32()".into()));
357                 }
358                 let timestamp: u64 = parse_int_be(b32, 32)
359                         .expect("7*5bit < 64bit, no overflow possible");
360                 match PositiveTimestamp::from_unix_timestamp(timestamp) {
361                         Ok(t) => Ok(t),
362                         Err(_) => unreachable!(),
363                 }
364         }
365 }
366
367 impl FromBase32 for InvoiceSignature {
368         type Err = ParseError;
369         fn from_base32(signature: &[u5]) -> Result<Self, Self::Err> {
370                 if signature.len() != 104 {
371                         return Err(ParseError::InvalidSliceLength("InvoiceSignature::from_base32()".into()));
372                 }
373                 let recoverable_signature_bytes = Vec::<u8>::from_base32(signature)?;
374                 let signature = &recoverable_signature_bytes[0..64];
375                 let recovery_id = RecoveryId::from_i32(recoverable_signature_bytes[64] as i32)?;
376
377                 Ok(InvoiceSignature(RecoverableSignature::from_compact(
378                         signature,
379                         recovery_id
380                 )?))
381         }
382 }
383
384 pub(crate) fn parse_int_be<T, U>(digits: &[U], base: T) -> Option<T>
385         where T: CheckedAdd + CheckedMul + From<u8> + Default,
386               U: Into<u8> + Copy
387 {
388         digits.iter().fold(Some(Default::default()), |acc, b|
389                 acc
390                         .and_then(|x| x.checked_mul(&base))
391                         .and_then(|x| x.checked_add(&(Into::<u8>::into(*b)).into()))
392         )
393 }
394
395 fn parse_tagged_parts(data: &[u5]) -> Result<Vec<RawTaggedField>, ParseError> {
396         let mut parts = Vec::<RawTaggedField>::new();
397         let mut data = data;
398
399         while !data.is_empty() {
400                 if data.len() < 3 {
401                         return Err(ParseError::UnexpectedEndOfTaggedFields);
402                 }
403
404                 // Ignore tag at data[0], it will be handled in the TaggedField parsers and
405                 // parse the length to find the end of the tagged field's data
406                 let len = parse_int_be(&data[1..3], 32).expect("can't overflow");
407                 let last_element = 3 + len;
408
409                 if data.len() < last_element {
410                         return Err(ParseError::UnexpectedEndOfTaggedFields);
411                 }
412
413                 // Get the tagged field's data slice
414                 let field = &data[0..last_element];
415
416                 // Set data slice to remaining data
417                 data = &data[last_element..];
418
419                 match TaggedField::from_base32(field) {
420                         Ok(field) => {
421                                 parts.push(RawTaggedField::KnownSemantics(field))
422                         },
423                         Err(ParseError::Skip)|Err(ParseError::Bech32Error(bech32::Error::InvalidLength)) => {
424                                 parts.push(RawTaggedField::UnknownSemantics(field.into()))
425                         },
426                         Err(e) => {return Err(e)}
427                 }
428         }
429         Ok(parts)
430 }
431
432 impl FromBase32 for TaggedField {
433         type Err = ParseError;
434
435         fn from_base32(field: &[u5]) -> Result<TaggedField, ParseError> {
436                 if field.len() < 3 {
437                         return Err(ParseError::UnexpectedEndOfTaggedFields);
438                 }
439
440                 let tag = field[0];
441                 let field_data =  &field[3..];
442
443                 match tag.to_u8() {
444                         constants::TAG_PAYMENT_HASH =>
445                                 Ok(TaggedField::PaymentHash(Sha256::from_base32(field_data)?)),
446                         constants::TAG_DESCRIPTION =>
447                                 Ok(TaggedField::Description(Description::from_base32(field_data)?)),
448                         constants::TAG_PAYEE_PUB_KEY =>
449                                 Ok(TaggedField::PayeePubKey(PayeePubKey::from_base32(field_data)?)),
450                         constants::TAG_DESCRIPTION_HASH =>
451                                 Ok(TaggedField::DescriptionHash(Sha256::from_base32(field_data)?)),
452                         constants::TAG_EXPIRY_TIME =>
453                                 Ok(TaggedField::ExpiryTime(ExpiryTime::from_base32(field_data)?)),
454                         constants::TAG_MIN_FINAL_CLTV_EXPIRY =>
455                                 Ok(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry::from_base32(field_data)?)),
456                         constants::TAG_FALLBACK =>
457                                 Ok(TaggedField::Fallback(Fallback::from_base32(field_data)?)),
458                         constants::TAG_PRIVATE_ROUTE =>
459                                 Ok(TaggedField::PrivateRoute(PrivateRoute::from_base32(field_data)?)),
460                         constants::TAG_PAYMENT_SECRET =>
461                                 Ok(TaggedField::PaymentSecret(PaymentSecret::from_base32(field_data)?)),
462                         constants::TAG_FEATURES =>
463                                 Ok(TaggedField::Features(InvoiceFeatures::from_base32(field_data)?)),
464                         _ => {
465                                 // "A reader MUST skip over unknown fields"
466                                 Err(ParseError::Skip)
467                         }
468                 }
469         }
470 }
471
472 impl FromBase32 for Sha256 {
473         type Err = ParseError;
474
475         fn from_base32(field_data: &[u5]) -> Result<Sha256, ParseError> {
476                 if field_data.len() != 52 {
477                         // "A reader MUST skip over […] a p, [or] h […] field that does not have data_length 52 […]."
478                         Err(ParseError::Skip)
479                 } else {
480                         Ok(Sha256(sha256::Hash::from_slice(&Vec::<u8>::from_base32(field_data)?)
481                                 .expect("length was checked before (52 u5 -> 32 u8)")))
482                 }
483         }
484 }
485
486 impl FromBase32 for Description {
487         type Err = ParseError;
488
489         fn from_base32(field_data: &[u5]) -> Result<Description, ParseError> {
490                 let bytes = Vec::<u8>::from_base32(field_data)?;
491                 let description = String::from(str::from_utf8(&bytes)?);
492                 Ok(Description::new(description).expect(
493                         "Max len is 639=floor(1023*5/8) since the len field is only 10bits long"
494                 ))
495         }
496 }
497
498 impl FromBase32 for PayeePubKey {
499         type Err = ParseError;
500
501         fn from_base32(field_data: &[u5]) -> Result<PayeePubKey, ParseError> {
502                 if field_data.len() != 53 {
503                         // "A reader MUST skip over […] a n […] field that does not have data_length 53 […]."
504                         Err(ParseError::Skip)
505                 } else {
506                         let data_bytes = Vec::<u8>::from_base32(field_data)?;
507                         let pub_key = PublicKey::from_slice(&data_bytes)?;
508                         Ok(pub_key.into())
509                 }
510         }
511 }
512
513 impl FromBase32 for ExpiryTime {
514         type Err = ParseError;
515
516         fn from_base32(field_data: &[u5]) -> Result<ExpiryTime, ParseError> {
517                 match parse_int_be::<u64, u5>(field_data, 32)
518                         .map(|t| ExpiryTime::from_seconds(t))
519                 {
520                         Some(t) => Ok(t),
521                         None => Err(ParseError::IntegerOverflowError),
522                 }
523         }
524 }
525
526 impl FromBase32 for MinFinalCltvExpiry {
527         type Err = ParseError;
528
529         fn from_base32(field_data: &[u5]) -> Result<MinFinalCltvExpiry, ParseError> {
530                 let expiry = parse_int_be::<u64, u5>(field_data, 32);
531                 if let Some(expiry) = expiry {
532                         Ok(MinFinalCltvExpiry(expiry))
533                 } else {
534                         Err(ParseError::IntegerOverflowError)
535                 }
536         }
537 }
538
539 impl FromBase32 for Fallback {
540         type Err = ParseError;
541
542         fn from_base32(field_data: &[u5]) -> Result<Fallback, ParseError> {
543                 if field_data.len() < 1 {
544                         return Err(ParseError::UnexpectedEndOfTaggedFields);
545                 }
546
547                 let version = field_data[0];
548                 let bytes = Vec::<u8>::from_base32(&field_data[1..])?;
549
550                 match version.to_u8() {
551                         0..=16 => {
552                                 if bytes.len() < 2 || bytes.len() > 40 {
553                                         return Err(ParseError::InvalidSegWitProgramLength);
554                                 }
555
556                                 Ok(Fallback::SegWitProgram {
557                                         version: version,
558                                         program: bytes
559                                 })
560                         },
561                         17 => {
562                                 if bytes.len() != 20 {
563                                         return Err(ParseError::InvalidPubKeyHashLength);
564                                 }
565                                 //TODO: refactor once const generics are available
566                                 let mut pkh = [0u8; 20];
567                                 pkh.copy_from_slice(&bytes);
568                                 Ok(Fallback::PubKeyHash(pkh))
569                         }
570                         18 => {
571                                 if bytes.len() != 20 {
572                                         return Err(ParseError::InvalidScriptHashLength);
573                                 }
574                                 let mut sh = [0u8; 20];
575                                 sh.copy_from_slice(&bytes);
576                                 Ok(Fallback::ScriptHash(sh))
577                         }
578                         _ => Err(ParseError::Skip)
579                 }
580         }
581 }
582
583 impl FromBase32 for PrivateRoute {
584         type Err = ParseError;
585
586         fn from_base32(field_data: &[u5]) -> Result<PrivateRoute, ParseError> {
587                 let bytes = Vec::<u8>::from_base32(field_data)?;
588
589                 if bytes.len() % 51 != 0 {
590                         return Err(ParseError::UnexpectedEndOfTaggedFields);
591                 }
592
593                 let mut route_hops = Vec::<RouteHintHop>::new();
594
595                 let mut bytes = bytes.as_slice();
596                 while !bytes.is_empty() {
597                         let hop_bytes = &bytes[0..51];
598                         bytes = &bytes[51..];
599
600                         let mut channel_id: [u8; 8] = Default::default();
601                         channel_id.copy_from_slice(&hop_bytes[33..41]);
602
603                         let hop = RouteHintHop {
604                                 src_node_id: PublicKey::from_slice(&hop_bytes[0..33])?,
605                                 short_channel_id: parse_int_be(&channel_id, 256).expect("short chan ID slice too big?"),
606                                 fees: RoutingFees {
607                                         base_msat: parse_int_be(&hop_bytes[41..45], 256).expect("slice too big?"),
608                                         proportional_millionths: parse_int_be(&hop_bytes[45..49], 256).expect("slice too big?"),
609                                 },
610                                 cltv_expiry_delta: parse_int_be(&hop_bytes[49..51], 256).expect("slice too big?"),
611                                 htlc_minimum_msat: None,
612                                 htlc_maximum_msat: None,
613                         };
614
615                         route_hops.push(hop);
616                 }
617
618                 Ok(PrivateRoute(RouteHint(route_hops)))
619         }
620 }
621
622 impl Display for ParseError {
623         fn fmt(&self, f: &mut Formatter) -> fmt::Result {
624                 match *self {
625                         // TODO: find a way to combine the first three arms (e as error::Error?)
626                         ParseError::Bech32Error(ref e) => {
627                                 write!(f, "Invalid bech32: {}", e)
628                         }
629                         ParseError::ParseAmountError(ref e) => {
630                                 write!(f, "Invalid amount in hrp ({})", e)
631                         }
632                         ParseError::MalformedSignature(ref e) => {
633                                 write!(f, "Invalid secp256k1 signature: {}", e)
634                         }
635                         ParseError::DescriptionDecodeError(ref e) => {
636                                 write!(f, "Description is not a valid utf-8 string: {}", e)
637                         }
638                         ParseError::InvalidSliceLength(ref function) => {
639                                 write!(f, "Slice in function {} had the wrong length", function)
640                         }
641                         ParseError::BadPrefix => f.write_str("did not begin with 'ln'"),
642                         ParseError::UnknownCurrency => f.write_str("currency code unknown"),
643                         ParseError::UnknownSiPrefix => f.write_str("unknown SI prefix"),
644                         ParseError::MalformedHRP => f.write_str("malformed human readable part"),
645                         ParseError::TooShortDataPart => {
646                                 f.write_str("data part too short (should be at least 111 bech32 chars long)")
647                         },
648                         ParseError::UnexpectedEndOfTaggedFields => {
649                                 f.write_str("tagged fields part ended unexpectedly")
650                         },
651                         ParseError::PaddingError => f.write_str("some data field had bad padding"),
652                         ParseError::IntegerOverflowError => {
653                                 f.write_str("parsed integer doesn't fit into receiving type")
654                         },
655                         ParseError::InvalidSegWitProgramLength => {
656                                 f.write_str("fallback SegWit program is too long or too short")
657                         },
658                         ParseError::InvalidPubKeyHashLength => {
659                                 f.write_str("fallback public key hash has a length unequal 20 bytes")
660                         },
661                         ParseError::InvalidScriptHashLength => {
662                                 f.write_str("fallback script hash has a length unequal 32 bytes")
663                         },
664                         ParseError::InvalidRecoveryId => {
665                                 f.write_str("recovery id is out of range (should be in [0,3])")
666                         },
667                         ParseError::Skip => {
668                                 f.write_str("the tagged field has to be skipped because of an unexpected, but allowed property")
669                         },
670                 }
671         }
672 }
673
674 impl Display for ParseOrSemanticError {
675         fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
676                 match self {
677                         ParseOrSemanticError::ParseError(err) => err.fmt(f),
678                         ParseOrSemanticError::SemanticError(err) => err.fmt(f),
679                 }
680         }
681 }
682
683 #[cfg(feature = "std")]
684 impl error::Error for ParseError {}
685
686 #[cfg(feature = "std")]
687 impl error::Error for ParseOrSemanticError {}
688
689 macro_rules! from_error {
690     ($my_error:expr, $extern_error:ty) => {
691         impl From<$extern_error> for ParseError {
692             fn from(e: $extern_error) -> Self {
693                 $my_error(e)
694             }
695         }
696     }
697 }
698
699 from_error!(ParseError::MalformedSignature, secp256k1::Error);
700 from_error!(ParseError::ParseAmountError, ParseIntError);
701 from_error!(ParseError::DescriptionDecodeError, str::Utf8Error);
702
703 impl From<bech32::Error> for ParseError {
704         fn from(e: bech32::Error) -> Self {
705                 match e {
706                         bech32::Error::InvalidPadding => ParseError::PaddingError,
707                         _ => ParseError::Bech32Error(e)
708                 }
709         }
710 }
711
712 impl From<ParseError> for ParseOrSemanticError {
713         fn from(e: ParseError) -> Self {
714                 ParseOrSemanticError::ParseError(e)
715         }
716 }
717
718 impl From<::SemanticError> for ParseOrSemanticError {
719         fn from(e: SemanticError) -> Self {
720                 ParseOrSemanticError::SemanticError(e)
721         }
722 }
723
724 #[cfg(test)]
725 mod test {
726         use de::ParseError;
727         use secp256k1::PublicKey;
728         use bech32::u5;
729         use bitcoin_hashes::hex::FromHex;
730         use bitcoin_hashes::sha256;
731
732         const CHARSET_REV: [i8; 128] = [
733                 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
734                 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
735                 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
736                 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
737                 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
738                 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
739                 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
740                 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
741         ];
742
743         fn from_bech32(bytes_5b: &[u8]) -> Vec<u5> {
744                 bytes_5b
745                         .iter()
746                         .map(|c| u5::try_from_u8(CHARSET_REV[*c as usize] as u8).unwrap())
747                         .collect()
748         }
749
750         #[test]
751         fn test_parse_currency_prefix() {
752                 use Currency;
753
754                 assert_eq!("bc".parse::<Currency>(), Ok(Currency::Bitcoin));
755                 assert_eq!("tb".parse::<Currency>(), Ok(Currency::BitcoinTestnet));
756                 assert_eq!("bcrt".parse::<Currency>(), Ok(Currency::Regtest));
757                 assert_eq!("sb".parse::<Currency>(), Ok(Currency::Simnet));
758                 assert_eq!("tbs".parse::<Currency>(), Ok(Currency::Signet));
759                 assert_eq!("something_else".parse::<Currency>(), Err(ParseError::UnknownCurrency))
760         }
761
762         #[test]
763         fn test_parse_int_from_bytes_be() {
764                 use de::parse_int_be;
765
766                 assert_eq!(parse_int_be::<u32, u8>(&[1, 2, 3, 4], 256), Some(16909060));
767                 assert_eq!(parse_int_be::<u32, u8>(&[1, 3], 32), Some(35));
768                 assert_eq!(parse_int_be::<u32, u8>(&[255, 255, 255, 255], 256), Some(4294967295));
769                 assert_eq!(parse_int_be::<u32, u8>(&[1, 0, 0, 0, 0], 256), None);
770         }
771
772         #[test]
773         fn test_parse_sha256_hash() {
774                 use Sha256;
775                 use bech32::FromBase32;
776
777                 let input = from_bech32(
778                         "qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypq".as_bytes()
779                 );
780
781                 let hash = sha256::Hash::from_hex(
782                         "0001020304050607080900010203040506070809000102030405060708090102"
783                 ).unwrap();
784                 let expected = Ok(Sha256(hash));
785
786                 assert_eq!(Sha256::from_base32(&input), expected);
787
788                 // make sure hashes of unknown length get skipped
789                 let input_unexpected_length = from_bech32(
790                         "qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypyq".as_bytes()
791                 );
792                 assert_eq!(Sha256::from_base32(&input_unexpected_length), Err(ParseError::Skip));
793         }
794
795         #[test]
796         fn test_parse_description() {
797                 use ::Description;
798                 use bech32::FromBase32;
799
800                 let input = from_bech32("xysxxatsyp3k7enxv4js".as_bytes());
801                 let expected = Ok(Description::new("1 cup coffee".to_owned()).unwrap());
802                 assert_eq!(Description::from_base32(&input), expected);
803         }
804
805         #[test]
806         fn test_parse_payee_pub_key() {
807                 use ::PayeePubKey;
808                 use bech32::FromBase32;
809
810                 let input = from_bech32("q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66".as_bytes());
811                 let pk_bytes = [
812                         0x03, 0xe7, 0x15, 0x6a, 0xe3, 0x3b, 0x0a, 0x20, 0x8d, 0x07, 0x44, 0x19, 0x91, 0x63,
813                         0x17, 0x7e, 0x90, 0x9e, 0x80, 0x17, 0x6e, 0x55, 0xd9, 0x7a, 0x2f, 0x22, 0x1e, 0xde,
814                         0x0f, 0x93, 0x4d, 0xd9, 0xad
815                 ];
816                 let expected = Ok(PayeePubKey(
817                         PublicKey::from_slice(&pk_bytes[..]).unwrap()
818                 ));
819
820                 assert_eq!(PayeePubKey::from_base32(&input), expected);
821
822                 // expects 33 bytes
823                 let input_unexpected_length = from_bech32(
824                         "q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhvq".as_bytes()
825                 );
826                 assert_eq!(PayeePubKey::from_base32(&input_unexpected_length), Err(ParseError::Skip));
827         }
828
829         #[test]
830         fn test_parse_expiry_time() {
831                 use ::ExpiryTime;
832                 use bech32::FromBase32;
833
834                 let input = from_bech32("pu".as_bytes());
835                 let expected = Ok(ExpiryTime::from_seconds(60));
836                 assert_eq!(ExpiryTime::from_base32(&input), expected);
837
838                 let input_too_large = from_bech32("sqqqqqqqqqqqq".as_bytes());
839                 assert_eq!(ExpiryTime::from_base32(&input_too_large), Err(ParseError::IntegerOverflowError));
840         }
841
842         #[test]
843         fn test_parse_min_final_cltv_expiry() {
844                 use ::MinFinalCltvExpiry;
845                 use bech32::FromBase32;
846
847                 let input = from_bech32("pr".as_bytes());
848                 let expected = Ok(MinFinalCltvExpiry(35));
849
850                 assert_eq!(MinFinalCltvExpiry::from_base32(&input), expected);
851         }
852
853         #[test]
854         fn test_parse_fallback() {
855                 use Fallback;
856                 use bech32::FromBase32;
857
858                 let cases = vec![
859                         (
860                                 from_bech32("3x9et2e20v6pu37c5d9vax37wxq72un98".as_bytes()),
861                                 Ok(Fallback::PubKeyHash([
862                                         0x31, 0x72, 0xb5, 0x65, 0x4f, 0x66, 0x83, 0xc8, 0xfb, 0x14, 0x69, 0x59, 0xd3,
863                                         0x47, 0xce, 0x30, 0x3c, 0xae, 0x4c, 0xa7
864                                 ]))
865                         ),
866                         (
867                                 from_bech32("j3a24vwu6r8ejrss3axul8rxldph2q7z9".as_bytes()),
868                                 Ok(Fallback::ScriptHash([
869                                         0x8f, 0x55, 0x56, 0x3b, 0x9a, 0x19, 0xf3, 0x21, 0xc2, 0x11, 0xe9, 0xb9, 0xf3,
870                                         0x8c, 0xdf, 0x68, 0x6e, 0xa0, 0x78, 0x45
871                                 ]))
872                         ),
873                         (
874                                 from_bech32("qw508d6qejxtdg4y5r3zarvary0c5xw7k".as_bytes()),
875                                 Ok(Fallback::SegWitProgram {
876                                         version: u5::try_from_u8(0).unwrap(),
877                                         program: Vec::from(&[
878                                                 0x75u8, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, 0x45,
879                                                 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
880                                         ][..])
881                                 })
882                         ),
883                         (
884                                 vec![u5::try_from_u8(21).unwrap(); 41],
885                                 Err(ParseError::Skip)
886                         ),
887                         (
888                                 vec![],
889                                 Err(ParseError::UnexpectedEndOfTaggedFields)
890                         ),
891                         (
892                                 vec![u5::try_from_u8(1).unwrap(); 81],
893                                 Err(ParseError::InvalidSegWitProgramLength)
894                         ),
895                         (
896                                 vec![u5::try_from_u8(17).unwrap(); 1],
897                                 Err(ParseError::InvalidPubKeyHashLength)
898                         ),
899                         (
900                                 vec![u5::try_from_u8(18).unwrap(); 1],
901                                 Err(ParseError::InvalidScriptHashLength)
902                         )
903                 ];
904
905                 for (input, expected) in cases.into_iter() {
906                         assert_eq!(Fallback::from_base32(&input), expected);
907                 }
908         }
909
910         #[test]
911         fn test_parse_route() {
912                 use lightning::routing::gossip::RoutingFees;
913                 use lightning::routing::router::{RouteHint, RouteHintHop};
914                 use ::PrivateRoute;
915                 use bech32::FromBase32;
916                 use de::parse_int_be;
917
918                 let input = from_bech32(
919                         "q20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqa\
920                         fqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzq".as_bytes()
921                 );
922
923                 let mut expected = Vec::<RouteHintHop>::new();
924                 expected.push(RouteHintHop {
925                         src_node_id: PublicKey::from_slice(
926                                 &[
927                                         0x02u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
928                                         0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
929                                         0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
930                                 ][..]
931                         ).unwrap(),
932                         short_channel_id: parse_int_be(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08], 256).expect("short chan ID slice too big?"),
933                         fees: RoutingFees {
934                                 base_msat: 1,
935                                 proportional_millionths: 20,
936                         },
937                         cltv_expiry_delta: 3,
938                         htlc_minimum_msat: None,
939                         htlc_maximum_msat: None
940                 });
941                 expected.push(RouteHintHop {
942                         src_node_id: PublicKey::from_slice(
943                                 &[
944                                         0x03u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
945                                         0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
946                                         0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
947                                 ][..]
948                         ).unwrap(),
949                         short_channel_id: parse_int_be(&[0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a], 256).expect("short chan ID slice too big?"),
950                         fees: RoutingFees {
951                                 base_msat: 2,
952                                 proportional_millionths: 30,
953                         },
954                         cltv_expiry_delta: 4,
955                         htlc_minimum_msat: None,
956                         htlc_maximum_msat: None
957                 });
958
959                 assert_eq!(PrivateRoute::from_base32(&input), Ok(PrivateRoute(RouteHint(expected))));
960
961                 assert_eq!(
962                         PrivateRoute::from_base32(&[u5::try_from_u8(0).unwrap(); 40][..]),
963                         Err(ParseError::UnexpectedEndOfTaggedFields)
964                 );
965         }
966
967         #[test]
968         fn test_payment_secret_and_features_de_and_ser() {
969                 use lightning::ln::features::InvoiceFeatures;
970                 use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
971                 use TaggedField::*;
972                 use {SiPrefix, SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart,
973                                  Currency, Sha256, PositiveTimestamp};
974
975                 // Feature bits 9, 15, and 99 are set.
976                 let expected_features = InvoiceFeatures::from_le_bytes(vec![0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]);
977                 let invoice_str = "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqsq67gye39hfg3zd8rgc80k32tvy9xk2xunwm5lzexnvpx6fd77en8qaq424dxgt56cag2dpt359k3ssyhetktkpqh24jqnjyw6uqd08sgptq44qu";
978                 let invoice = SignedRawInvoice {
979                                         raw_invoice: RawInvoice {
980                                                 hrp: RawHrp {
981                                                         currency: Currency::Bitcoin,
982                                                         raw_amount: Some(25),
983                                                         si_prefix: Some(SiPrefix::Milli)
984                                                 },
985                                                 data: RawDataPart {
986                                                         timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
987                                                         tagged_fields: vec ! [
988                                                                 PaymentHash(Sha256(sha256::Hash::from_hex(
989                                                                         "0001020304050607080900010203040506070809000102030405060708090102"
990                                                                 ).unwrap())).into(),
991                                                                 Description(::Description::new("coffee beans".to_owned()).unwrap()).into(),
992                                                                 PaymentSecret(::PaymentSecret([17; 32])).into(),
993                                                                 Features(expected_features).into()]}
994                                                                 },
995                                         hash: [0xb1, 0x96, 0x46, 0xc3, 0xbc, 0x56, 0x76, 0x1d, 0x20, 0x65, 0x6e, 0x0e, 0x32,
996                                                                         0xec, 0xd2, 0x69, 0x27, 0xb7, 0x62, 0x6e, 0x2a, 0x8b, 0xe6, 0x97, 0x71, 0x9f,
997                                                                         0xf8, 0x7e, 0x44, 0x54, 0x55, 0xb9],
998                                         signature: InvoiceSignature(RecoverableSignature::from_compact(
999                                                                                 &[0xd7, 0x90, 0x4c, 0xc4, 0xb7, 0x4a, 0x22, 0x26, 0x9c, 0x68, 0xc1, 0xdf, 0x68,
1000                                                                                         0xa9, 0x6c, 0x21, 0x4d, 0x65, 0x1b, 0x93, 0x76, 0xe9, 0xf1, 0x64, 0xd3, 0x60,
1001                                                                                         0x4d, 0xa4, 0xb7, 0xde, 0xcc, 0xce, 0x0e, 0x82, 0xaa, 0xab, 0x4c, 0x85, 0xd3,
1002                                                                                         0x58, 0xea, 0x14, 0xd0, 0xae, 0x34, 0x2d, 0xa3, 0x08, 0x12, 0xf9, 0x5d, 0x97,
1003                                                                                         0x60, 0x82, 0xea, 0xac, 0x81, 0x39, 0x11, 0xda, 0xe0, 0x1a, 0xf3, 0xc1],
1004                                                                                 RecoveryId::from_i32(1).unwrap()
1005                                                                 ).unwrap()),
1006                         };
1007                 assert_eq!(invoice_str, invoice.to_string());
1008                 assert_eq!(
1009                         invoice_str.parse(),
1010                         Ok(invoice)
1011                 );
1012         }
1013
1014         #[test]
1015         fn test_raw_signed_invoice_deserialization() {
1016                 use TaggedField::*;
1017                 use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
1018                 use {SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256,
1019                          PositiveTimestamp};
1020
1021                 assert_eq!(
1022                         "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmw\
1023                         wd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9\
1024                         ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w".parse(),
1025                         Ok(SignedRawInvoice {
1026                                 raw_invoice: RawInvoice {
1027                                         hrp: RawHrp {
1028                                                 currency: Currency::Bitcoin,
1029                                                 raw_amount: None,
1030                                                 si_prefix: None,
1031                                         },
1032                                         data: RawDataPart {
1033                                         timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1034                                         tagged_fields: vec ! [
1035                                                 PaymentHash(Sha256(sha256::Hash::from_hex(
1036                                                         "0001020304050607080900010203040506070809000102030405060708090102"
1037                                                 ).unwrap())).into(),
1038                                                 Description(
1039                                                         ::Description::new(
1040                                                                 "Please consider supporting this project".to_owned()
1041                                                         ).unwrap()
1042                                                 ).into(),
1043                                         ],
1044                                         },
1045                                         },
1046                                 hash: [
1047                                         0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27,
1048                                         0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
1049                                         0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
1050                                 ],
1051                                 signature: InvoiceSignature(RecoverableSignature::from_compact(
1052                                         & [
1053                                                 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
1054                                                 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
1055                                                 0x4e, 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f,
1056                                                 0x42, 0x5f, 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad,
1057                                                 0x0d, 0x6e, 0x35, 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9,
1058                                                 0xaa, 0xb1, 0x5e, 0x57, 0x38, 0xb1, 0x1f, 0x12, 0x7f
1059                                         ],
1060                                         RecoveryId::from_i32(0).unwrap()
1061                                 ).unwrap()),
1062                                 }
1063                         )
1064                 )
1065         }
1066 }