From: Jeffrey Czyz Date: Thu, 9 Feb 2023 16:59:11 +0000 (-0600) Subject: Expose Bech32Encode trait for fuzzing X-Git-Url: http://git.bitcoin.ninja/?a=commitdiff_plain;h=1772546b732b79c7fef6c7d76e5666fd52f6b856;p=rust-lightning Expose Bech32Encode trait for fuzzing In order to fuzz test Bech32Encode parsing independent of the underlying message deserialization, the trait needs to be exposed. Conditionally expose it only for fuzzing. --- diff --git a/lightning/src/offers/parse.rs b/lightning/src/offers/parse.rs index 35c1425ac..6afd4d68f 100644 --- a/lightning/src/offers/parse.rs +++ b/lightning/src/offers/parse.rs @@ -10,69 +10,83 @@ //! Parsing and formatting for bech32 message encoding. use bitcoin::bech32; -use bitcoin::bech32::{FromBase32, ToBase32}; use bitcoin::secp256k1; use core::convert::TryFrom; -use core::fmt; use crate::io; use crate::ln::msgs::DecodeError; use crate::util::ser::SeekReadable; use crate::prelude::*; -/// Indicates a message can be encoded using bech32. -pub(super) trait Bech32Encode: AsRef<[u8]> + TryFrom, Error=ParseError> { - /// Human readable part of the message's bech32 encoding. - const BECH32_HRP: &'static str; - - /// Parses a bech32-encoded message into a TLV stream. - fn from_bech32_str(s: &str) -> Result { - // Offer encoding may be split by '+' followed by optional whitespace. - let encoded = match s.split('+').skip(1).next() { - Some(_) => { - for chunk in s.split('+') { - let chunk = chunk.trim_start(); - if chunk.is_empty() || chunk.contains(char::is_whitespace) { - return Err(ParseError::InvalidContinuation); +#[cfg(not(fuzzing))] +pub(super) use sealed::Bech32Encode; + +#[cfg(fuzzing)] +pub use sealed::Bech32Encode; + +mod sealed { + use bitcoin::bech32; + use bitcoin::bech32::{FromBase32, ToBase32}; + use core::convert::TryFrom; + use core::fmt; + use super::ParseError; + + use crate::prelude::*; + + /// Indicates a message can be encoded using bech32. + pub trait Bech32Encode: AsRef<[u8]> + TryFrom, Error=ParseError> { + /// Human readable part of the message's bech32 encoding. + const BECH32_HRP: &'static str; + + /// Parses a bech32-encoded message into a TLV stream. + fn from_bech32_str(s: &str) -> Result { + // Offer encoding may be split by '+' followed by optional whitespace. + let encoded = match s.split('+').skip(1).next() { + Some(_) => { + for chunk in s.split('+') { + let chunk = chunk.trim_start(); + if chunk.is_empty() || chunk.contains(char::is_whitespace) { + return Err(ParseError::InvalidContinuation); + } } - } - let s = s.chars().filter(|c| *c != '+' && !c.is_whitespace()).collect::(); - Bech32String::Owned(s) - }, - None => Bech32String::Borrowed(s), - }; + let s: String = s.chars().filter(|c| *c != '+' && !c.is_whitespace()).collect(); + Bech32String::Owned(s) + }, + None => Bech32String::Borrowed(s), + }; - let (hrp, data) = bech32::decode_without_checksum(encoded.as_ref())?; + let (hrp, data) = bech32::decode_without_checksum(encoded.as_ref())?; - if hrp != Self::BECH32_HRP { - return Err(ParseError::InvalidBech32Hrp); - } + if hrp != Self::BECH32_HRP { + return Err(ParseError::InvalidBech32Hrp); + } - let data = Vec::::from_base32(&data)?; - Self::try_from(data) - } + let data = Vec::::from_base32(&data)?; + Self::try_from(data) + } - /// Formats the message using bech32-encoding. - fn fmt_bech32_str(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - bech32::encode_without_checksum_to_fmt(f, Self::BECH32_HRP, self.as_ref().to_base32()) - .expect("HRP is invalid").unwrap(); + /// Formats the message using bech32-encoding. + fn fmt_bech32_str(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + bech32::encode_without_checksum_to_fmt(f, Self::BECH32_HRP, self.as_ref().to_base32()) + .expect("HRP is invalid").unwrap(); - Ok(()) + Ok(()) + } } -} -// Used to avoid copying a bech32 string not containing the continuation character (+). -enum Bech32String<'a> { - Borrowed(&'a str), - Owned(String), -} + // Used to avoid copying a bech32 string not containing the continuation character (+). + enum Bech32String<'a> { + Borrowed(&'a str), + Owned(String), + } -impl<'a> AsRef for Bech32String<'a> { - fn as_ref(&self) -> &str { - match self { - Bech32String::Borrowed(s) => s, - Bech32String::Owned(s) => s, + impl<'a> AsRef for Bech32String<'a> { + fn as_ref(&self) -> &str { + match self { + Bech32String::Borrowed(s) => s, + Bech32String::Owned(s) => s, + } } } }