Skip to content

Commit 9274d76

Browse files
committed
rewrite Address::from_base58 to eliminate all the unwraps
These unwraps and indexing (which hide more panic paths) irritated me, and also would need to be tweaked once we get rid of the Hash::from_slice methods. I figured I'd preemptively get rid of them.
1 parent b03c594 commit 9274d76

1 file changed

Lines changed: 24 additions & 19 deletions

File tree

src/address.rs

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use crate::blech32::{Blech32, Blech32m};
2626
use crate::hashes::Hash;
2727
use bitcoin::base58;
2828
use bitcoin::PublicKey;
29+
use internals::array::ArrayExt as _;
2930
use secp256k1_zkp;
3031
use secp256k1_zkp::Secp256k1;
3132
use secp256k1_zkp::Verification;
@@ -486,35 +487,39 @@ impl Address {
486487

487488
// data.len() should be >= 1 when this method is called
488489
fn from_base58(data: &[u8], params: &'static AddressParams) -> Result<Address, AddressError> {
490+
let len_error = AddressError::InvalidLength(data.len());
489491
// When unblinded, the structure is:
490492
// <1: regular prefix> <20: hash160>
491493
// When blinded, the structure is:
492494
// <1: blinding prefix> <1: regular prefix> <33: blinding pubkey> <20: hash160>
493495

494-
let blinded = data[0] == params.blinded_prefix;
495-
let prefix = match (blinded, data.len()) {
496-
(true, 55) => data[1],
497-
(false, 21) => data[0],
498-
(_, len) => return Err(AddressError::InvalidLength(len)),
496+
let Some((blinding_prefix, blinded_data)) = data.split_first() else {
497+
return Err(len_error);
499498
};
500499

501-
let (blinding_pubkey, payload_data) = match blinded {
502-
true => (
503-
Some(
504-
secp256k1_zkp::PublicKey::from_slice(&data[2..35])
505-
.map_err(AddressError::InvalidBlindingPubKey)?,
506-
),
507-
&data[35..],
508-
),
509-
false => (None, &data[1..]),
500+
let (prefix, blinding_pubkey, hash) = if *blinding_prefix == params.blinded_prefix {
501+
let Some((prefix, pubkey_and_hash)) = blinded_data.split_first() else {
502+
return Err(len_error);
503+
};
504+
505+
let pubkey_and_hash = <&[u8; 53]>::try_from(pubkey_and_hash).map_err(|_| len_error)?;
506+
let (pubkey, hash) = pubkey_and_hash.split_array::<33, 20>();
507+
508+
let blinding_pubkey = secp256k1_zkp::PublicKey::from_slice(pubkey)
509+
.map_err(AddressError::InvalidBlindingPubKey)?;
510+
511+
(prefix, Some(blinding_pubkey), hash)
512+
} else {
513+
let hash = <&[u8; 20]>::try_from(blinded_data).map_err(|_| len_error)?;
514+
(blinding_prefix, None, hash)
510515
};
511516

512-
let payload = if prefix == params.p2pkh_prefix {
513-
Payload::PubkeyHash(PubkeyHash::from_slice(payload_data).unwrap())
514-
} else if prefix == params.p2sh_prefix {
515-
Payload::ScriptHash(ScriptHash::from_slice(payload_data).unwrap())
517+
let payload = if *prefix == params.p2pkh_prefix {
518+
Payload::PubkeyHash(PubkeyHash::from_byte_array(*hash))
519+
} else if *prefix == params.p2sh_prefix {
520+
Payload::ScriptHash(ScriptHash::from_byte_array(*hash))
516521
} else {
517-
return Err(AddressError::InvalidAddressVersion(prefix));
522+
return Err(AddressError::InvalidAddressVersion(*prefix));
518523
};
519524

520525
Ok(Address {

0 commit comments

Comments
 (0)