1 // This file is Copyright its original authors, visible in version control
4 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7 // You may not use this file except in accordance with one or both of these
10 //! Parsing and formatting for bech32 message encoding.
13 use bitcoin::secp256k1;
14 use core::convert::TryFrom;
16 use crate::ln::msgs::DecodeError;
17 use crate::util::ser::SeekReadable;
19 use crate::prelude::*;
22 pub(super) use sealed::Bech32Encode;
25 pub use sealed::Bech32Encode;
29 use bitcoin::bech32::{FromBase32, ToBase32};
30 use core::convert::TryFrom;
32 use super::Bolt12ParseError;
34 use crate::prelude::*;
36 /// Indicates a message can be encoded using bech32.
37 pub trait Bech32Encode: AsRef<[u8]> + TryFrom<Vec<u8>, Error=Bolt12ParseError> {
38 /// Human readable part of the message's bech32 encoding.
39 const BECH32_HRP: &'static str;
41 /// Parses a bech32-encoded message into a TLV stream.
42 fn from_bech32_str(s: &str) -> Result<Self, Bolt12ParseError> {
43 // Offer encoding may be split by '+' followed by optional whitespace.
44 let encoded = match s.split('+').skip(1).next() {
46 for chunk in s.split('+') {
47 let chunk = chunk.trim_start();
48 if chunk.is_empty() || chunk.contains(char::is_whitespace) {
49 return Err(Bolt12ParseError::InvalidContinuation);
53 let s: String = s.chars().filter(|c| *c != '+' && !c.is_whitespace()).collect();
54 Bech32String::Owned(s)
56 None => Bech32String::Borrowed(s),
59 let (hrp, data) = bech32::decode_without_checksum(encoded.as_ref())?;
61 if hrp != Self::BECH32_HRP {
62 return Err(Bolt12ParseError::InvalidBech32Hrp);
65 let data = Vec::<u8>::from_base32(&data)?;
69 /// Formats the message using bech32-encoding.
70 fn fmt_bech32_str(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
71 bech32::encode_without_checksum_to_fmt(f, Self::BECH32_HRP, self.as_ref().to_base32())
72 .expect("HRP is invalid").unwrap();
78 // Used to avoid copying a bech32 string not containing the continuation character (+).
79 enum Bech32String<'a> {
84 impl<'a> AsRef<str> for Bech32String<'a> {
85 fn as_ref(&self) -> &str {
87 Bech32String::Borrowed(s) => s,
88 Bech32String::Owned(s) => s,
94 /// A wrapper for reading a message as a TLV stream `T` from a byte sequence, while still
95 /// maintaining ownership of the bytes for later use.
96 pub(super) struct ParsedMessage<T: SeekReadable> {
101 impl<T: SeekReadable> TryFrom<Vec<u8>> for ParsedMessage<T> {
102 type Error = DecodeError;
104 fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
105 let mut cursor = io::Cursor::new(bytes);
106 let tlv_stream: T = SeekReadable::read(&mut cursor)?;
108 // Ensure that there are no more TLV records left to parse.
109 if cursor.position() < cursor.get_ref().len() as u64 {
110 return Err(DecodeError::InvalidValue);
113 let bytes = cursor.into_inner();
114 Ok(Self { bytes, tlv_stream })
118 /// Error when parsing a bech32 encoded message using [`str::parse`].
119 #[derive(Clone, Debug, PartialEq)]
120 pub enum Bolt12ParseError {
121 /// The bech32 encoding does not conform to the BOLT 12 requirements for continuing messages
122 /// across multiple parts (i.e., '+' followed by whitespace).
124 /// The bech32 encoding's human-readable part does not match what was expected for the message
127 /// The string could not be bech32 decoded.
128 Bech32(/// This is not exported to bindings users as the details don't matter much
130 /// The bech32 decoded string could not be decoded as the expected message type.
132 /// The parsed message has invalid semantics.
133 InvalidSemantics(Bolt12SemanticError),
134 /// The parsed message has an invalid signature.
135 InvalidSignature(secp256k1::Error),
138 /// Error when interpreting a TLV stream as a specific type.
139 #[derive(Clone, Debug, PartialEq)]
140 pub enum Bolt12SemanticError {
141 /// The current [`std::time::SystemTime`] is past the offer or invoice's expiration.
143 /// The provided chain hash does not correspond to a supported chain.
145 /// A chain was provided but was not expected.
147 /// An amount was expected but was missing.
149 /// The amount exceeded the total bitcoin supply.
151 /// An amount was provided but was not sufficient in value.
153 /// An amount was provided but was not expected.
155 /// A currency was provided that is not supported.
157 /// A feature was required but is unknown.
158 UnknownRequiredFeatures,
159 /// Features were provided but were not expected.
161 /// A required description was not provided.
163 /// A signing pubkey was not provided.
164 MissingSigningPubkey,
165 /// A signing pubkey was provided but a different one was expected.
166 InvalidSigningPubkey,
167 /// A signing pubkey was provided but was not expected.
168 UnexpectedSigningPubkey,
169 /// A quantity was expected but was missing.
171 /// An unsupported quantity was provided.
173 /// A quantity or quantity bounds was provided but was not expected.
175 /// Metadata could not be used to verify the offers message.
177 /// Metadata was provided but was not expected.
179 /// Payer metadata was expected but was missing.
180 MissingPayerMetadata,
181 /// A payer id was expected but was missing.
183 /// Blinded paths were expected but were missing.
185 /// The blinded payinfo given does not match the number of blinded path hops.
187 /// An invoice creation time was expected but was missing.
189 /// An invoice payment hash was expected but was missing.
191 /// A signature was expected but was missing.
195 impl From<bech32::Error> for Bolt12ParseError {
196 fn from(error: bech32::Error) -> Self {
201 impl From<DecodeError> for Bolt12ParseError {
202 fn from(error: DecodeError) -> Self {
207 impl From<Bolt12SemanticError> for Bolt12ParseError {
208 fn from(error: Bolt12SemanticError) -> Self {
209 Self::InvalidSemantics(error)
213 impl From<secp256k1::Error> for Bolt12ParseError {
214 fn from(error: secp256k1::Error) -> Self {
215 Self::InvalidSignature(error)