Merge rust-bitcoin/rust-bitcoin#1951: Use newly released bech32 API
e4c7e01a6f
Use the new bech32 iterator API (Tobin C. Harding) Pull request description: Depend on the newly released version of `bech32`, BOOM! ACKs for top commit: apoelstra: ACKe4c7e01a6f
clarkmoody: ACKe4c7e01a6f
Tree-SHA512: 91675a830cf67f8dcabd42e7dc1b70d80b669330be5244bb8102e0ec5d1a206d5ead07f73b328a158b761c328bc78d573185af8d31f14183ccc17318d752c02b
This commit is contained in:
commit
675fd54c95
|
@ -16,9 +16,9 @@ checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53"
|
|||
|
||||
[[package]]
|
||||
name = "bech32"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0-alpha"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5738be7561b0eeb501ef1d5c5db3f24e01ceb55fededd9b00039aada34966ad"
|
||||
checksum = "81cc1dec4c25e5a78c52802eda8e2adf0d2aca57ffc536326b75c0e531ea0a9b"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
|
|
|
@ -16,9 +16,9 @@ checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53"
|
|||
|
||||
[[package]]
|
||||
name = "bech32"
|
||||
version = "0.9.1"
|
||||
version = "0.10.0-alpha"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445"
|
||||
checksum = "81cc1dec4c25e5a78c52802eda8e2adf0d2aca57ffc536326b75c0e531ea0a9b"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
|
|
|
@ -27,7 +27,7 @@ bitcoinconsensus-std = ["bitcoinconsensus/std", "std"]
|
|||
# Instead no-std enables additional features required for this crate to be usable without std.
|
||||
# As a result, both can be enabled without conflict.
|
||||
std = ["secp256k1/std", "hashes/std", "bech32/std", "internals/std", "hex/std"]
|
||||
no-std = ["core2", "hashes/alloc", "hashes/core2", "secp256k1/alloc", "hex/alloc", "hex/core2"]
|
||||
no-std = ["core2", "hashes/alloc", "hashes/core2", "bech32/alloc", "secp256k1/alloc", "hex/alloc", "hex/core2"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
@ -36,7 +36,7 @@ rustdoc-args = ["--cfg", "docsrs"]
|
|||
[dependencies]
|
||||
internals = { package = "bitcoin-internals", version = "0.2.0" }
|
||||
hex = { package = "hex-conservative", version = "0.1.1", default-features = false }
|
||||
bech32 = { version = "0.9.0", default-features = false }
|
||||
bech32 = { version = "0.10.0-alpha", default-features = false }
|
||||
hashes = { package = "bitcoin_hashes", version = "0.13.0", default-features = false }
|
||||
secp256k1 = { version = "0.27.0", default-features = false, features = ["bitcoin_hashes"] }
|
||||
hex_lit = "0.1.1"
|
||||
|
|
|
@ -99,17 +99,8 @@ impl_std_error!(UnknownAddressTypeError);
|
|||
pub enum ParseError {
|
||||
/// Base58 error.
|
||||
Base58(base58::Error),
|
||||
/// Bech32 error.
|
||||
Bech32(bech32::Error),
|
||||
/// The bech32 payload was empty.
|
||||
EmptyBech32Payload,
|
||||
/// The wrong checksum algorithm was used. See BIP-0350.
|
||||
InvalidBech32Variant {
|
||||
/// Bech32 variant that is required by the used Witness version.
|
||||
expected: bech32::Variant,
|
||||
/// The actual Bech32 variant encoded in the address representation.
|
||||
found: bech32::Variant,
|
||||
},
|
||||
/// Bech32 segwit decoding error.
|
||||
Bech32(bech32::primitives::decode::SegwitHrpstringError),
|
||||
/// A witness version conversion/parsing error.
|
||||
WitnessVersion(witness_version::TryFromError),
|
||||
/// A witness program error.
|
||||
|
@ -122,13 +113,7 @@ impl fmt::Display for ParseError {
|
|||
|
||||
match *self {
|
||||
Base58(ref e) => write_err!(f, "base58 error"; e),
|
||||
Bech32(ref e) => write_err!(f, "bech32 error"; e),
|
||||
EmptyBech32Payload => write!(f, "the bech32 payload was empty"),
|
||||
InvalidBech32Variant { expected, found } => write!(
|
||||
f,
|
||||
"invalid bech32 checksum variant found {:?} when {:?} was expected",
|
||||
found, expected
|
||||
),
|
||||
Bech32(ref e) => write_err!(f, "bech32 segwit decoding error"; e),
|
||||
WitnessVersion(ref e) => write_err!(f, "witness version conversion/parsing error"; e),
|
||||
WitnessProgram(ref e) => write_err!(f, "witness program error"; e),
|
||||
}
|
||||
|
@ -145,7 +130,6 @@ impl std::error::Error for ParseError {
|
|||
Bech32(ref e) => Some(e),
|
||||
WitnessVersion(ref e) => Some(e),
|
||||
WitnessProgram(ref e) => Some(e),
|
||||
EmptyBech32Payload | InvalidBech32Variant { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -154,8 +138,8 @@ impl From<base58::Error> for ParseError {
|
|||
fn from(e: base58::Error) -> Self { Self::Base58(e) }
|
||||
}
|
||||
|
||||
impl From<bech32::Error> for ParseError {
|
||||
fn from(e: bech32::Error) -> Self { Self::Bech32(e) }
|
||||
impl From<bech32::primitives::decode::SegwitHrpstringError> for ParseError {
|
||||
fn from(e: bech32::primitives::decode::SegwitHrpstringError) -> Self { Self::Bech32(e) }
|
||||
}
|
||||
|
||||
impl From<witness_version::TryFromError> for ParseError {
|
||||
|
|
|
@ -31,7 +31,7 @@ use core::fmt;
|
|||
use core::marker::PhantomData;
|
||||
use core::str::FromStr;
|
||||
|
||||
use bech32;
|
||||
use bech32::primitives::hrp::{self, Hrp};
|
||||
use hashes::{sha256, Hash, HashEngine};
|
||||
use secp256k1::{Secp256k1, Verification, XOnlyPublicKey};
|
||||
|
||||
|
@ -46,6 +46,7 @@ use crate::blockdata::script::{self, Script, ScriptBuf, ScriptHash};
|
|||
use crate::crypto::key::{PubkeyHash, PublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey};
|
||||
use crate::network::Network;
|
||||
use crate::prelude::*;
|
||||
use crate::script::PushBytesBuf;
|
||||
use crate::taproot::TapNodeHash;
|
||||
|
||||
/// Error code for the address module.
|
||||
|
@ -237,8 +238,8 @@ pub struct AddressEncoding<'a> {
|
|||
pub p2pkh_prefix: u8,
|
||||
/// base58 version byte for p2sh payloads (e.g. 0x05 for "3..." addresses).
|
||||
pub p2sh_prefix: u8,
|
||||
/// hrp used in bech32 addresss (e.g. "bc" for "bc1..." addresses).
|
||||
pub bech32_hrp: &'a str,
|
||||
/// The bech32 human-readable part.
|
||||
pub hrp: Hrp,
|
||||
}
|
||||
|
||||
/// Formats bech32 as upper case if alternate formatting is chosen (`{:#}`).
|
||||
|
@ -257,19 +258,16 @@ impl<'a> fmt::Display for AddressEncoding<'a> {
|
|||
prefixed[1..].copy_from_slice(&hash[..]);
|
||||
base58::encode_check_to_fmt(fmt, &prefixed[..])
|
||||
}
|
||||
Payload::WitnessProgram(witness_prog) => {
|
||||
let (version, prog) = (witness_prog.version(), witness_prog.program());
|
||||
let mut upper_writer;
|
||||
let writer = if fmt.alternate() {
|
||||
upper_writer = UpperWriter(fmt);
|
||||
&mut upper_writer as &mut dyn fmt::Write
|
||||
Payload::WitnessProgram(witness_program) => {
|
||||
let hrp = &self.hrp;
|
||||
let version = witness_program.version().to_fe();
|
||||
let program = witness_program.program().as_bytes();
|
||||
|
||||
if fmt.alternate() {
|
||||
bech32::segwit::encode_to_fmt_unchecked_uppercase(fmt, hrp, version, program)
|
||||
} else {
|
||||
fmt as &mut dyn fmt::Write
|
||||
};
|
||||
let mut bech32_writer =
|
||||
bech32::Bech32Writer::new(self.bech32_hrp, version.bech32_variant(), writer)?;
|
||||
bech32::WriteBase32::write_u5(&mut bech32_writer, version.into())?;
|
||||
bech32::ToBase32::write_base32(&prog.as_bytes(), &mut bech32_writer)
|
||||
bech32::segwit::encode_to_fmt_unchecked(fmt, hrp, version, program)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -495,13 +493,12 @@ impl<V: NetworkValidation> Address<V> {
|
|||
Network::Bitcoin => SCRIPT_ADDRESS_PREFIX_MAIN,
|
||||
Network::Testnet | Network::Signet | Network::Regtest => SCRIPT_ADDRESS_PREFIX_TEST,
|
||||
};
|
||||
let bech32_hrp = match self.network() {
|
||||
Network::Bitcoin => "bc",
|
||||
Network::Testnet | Network::Signet => "tb",
|
||||
Network::Regtest => "bcrt",
|
||||
let hrp = match self.network() {
|
||||
Network::Bitcoin => hrp::BC,
|
||||
Network::Testnet | Network::Signet => hrp::TB,
|
||||
Network::Regtest => hrp::BCRT,
|
||||
};
|
||||
let encoding =
|
||||
AddressEncoding { payload: self.payload(), p2pkh_prefix, p2sh_prefix, bech32_hrp };
|
||||
let encoding = AddressEncoding { payload: self.payload(), p2pkh_prefix, p2sh_prefix, hrp };
|
||||
|
||||
use fmt::Display;
|
||||
|
||||
|
@ -775,17 +772,6 @@ impl<V: NetworkValidation> fmt::Debug for Address<V> {
|
|||
}
|
||||
}
|
||||
|
||||
struct UpperWriter<W: fmt::Write>(W);
|
||||
|
||||
impl<W: fmt::Write> fmt::Write for UpperWriter<W> {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
for c in s.chars() {
|
||||
self.0.write_char(c.to_ascii_uppercase())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts the bech32 prefix.
|
||||
///
|
||||
/// # Returns
|
||||
|
@ -812,26 +798,11 @@ impl FromStr for Address<NetworkUnchecked> {
|
|||
_ => None,
|
||||
};
|
||||
if let Some(network) = bech32_network {
|
||||
// decode as bech32
|
||||
let (_, payload, variant) = bech32::decode(s)?;
|
||||
if payload.is_empty() {
|
||||
return Err(ParseError::EmptyBech32Payload);
|
||||
}
|
||||
|
||||
// Get the script version and program (converted from 5-bit to 8-bit)
|
||||
let (version, program): (WitnessVersion, Vec<u8>) = {
|
||||
let (v, p5) = payload.split_at(1);
|
||||
(WitnessVersion::try_from(v[0])?, bech32::FromBase32::from_base32(p5)?)
|
||||
};
|
||||
|
||||
let (_hrp, version, data) = bech32::segwit::decode(s)?;
|
||||
let version = WitnessVersion::try_from(version).expect("we know this is in range 0-16");
|
||||
let program = PushBytesBuf::try_from(data).expect("decode() guarantees valid length");
|
||||
let witness_program = WitnessProgram::new(version, program)?;
|
||||
|
||||
// Encoding check
|
||||
let expected = version.bech32_variant();
|
||||
if expected != variant {
|
||||
return Err(ParseError::InvalidBech32Variant { expected, found: variant });
|
||||
}
|
||||
|
||||
return Ok(Address::new(network, Payload::WitnessProgram(witness_program)));
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ use core::convert::TryFrom;
|
|||
use core::fmt;
|
||||
use core::str::FromStr;
|
||||
|
||||
use bech32::Fe32;
|
||||
use internals::write_err;
|
||||
|
||||
use crate::blockdata::opcodes::all::*;
|
||||
|
@ -72,12 +73,9 @@ impl WitnessVersion {
|
|||
/// into a byte since the conversion requires context (bitcoin script or just a version number).
|
||||
pub fn to_num(self) -> u8 { self as u8 }
|
||||
|
||||
/// Determines the checksum variant. See BIP-0350 for specification.
|
||||
pub fn bech32_variant(&self) -> bech32::Variant {
|
||||
match self {
|
||||
WitnessVersion::V0 => bech32::Variant::Bech32,
|
||||
_ => bech32::Variant::Bech32m,
|
||||
}
|
||||
/// Converts this witness version to a GF32 field element.
|
||||
pub fn to_fe(self) -> Fe32 {
|
||||
Fe32::try_from(self.to_num()).expect("0-16 are valid fe32 values")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,10 +93,10 @@ impl FromStr for WitnessVersion {
|
|||
}
|
||||
}
|
||||
|
||||
impl TryFrom<bech32::u5> for WitnessVersion {
|
||||
impl TryFrom<bech32::Fe32> for WitnessVersion {
|
||||
type Error = TryFromError;
|
||||
|
||||
fn try_from(value: bech32::u5) -> Result<Self, Self::Error> { Self::try_from(value.to_u8()) }
|
||||
fn try_from(value: Fe32) -> Result<Self, Self::Error> { Self::try_from(value.to_u8()) }
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for WitnessVersion {
|
||||
|
@ -155,10 +153,8 @@ impl<'a> TryFrom<Instruction<'a>> for WitnessVersion {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<WitnessVersion> for bech32::u5 {
|
||||
fn from(version: WitnessVersion) -> Self {
|
||||
bech32::u5::try_from_u8(version.to_num()).expect("WitnessVersion must be 0..=16")
|
||||
}
|
||||
impl From<WitnessVersion> for Fe32 {
|
||||
fn from(version: WitnessVersion) -> Self { version.to_fe() }
|
||||
}
|
||||
|
||||
impl From<WitnessVersion> for Opcode {
|
||||
|
|
Loading…
Reference in New Issue