Implement TransparentAddress encoding and decoding

This commit is contained in:
Jack Grigg 2019-05-24 15:17:36 +01:00
parent 97c21e0c1a
commit 932f1c9737
4 changed files with 126 additions and 0 deletions

View File

@ -13,6 +13,7 @@ edition = "2018"
[dependencies]
bech32 = "0.7"
bs58 = { version = "0.3", features = ["check"] }
ff = { version = "0.6", path = "../ff" }
hex = "0.3"
pairing = { version = "0.16", path = "../pairing" }

View File

@ -28,3 +28,13 @@ pub const HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY: &str = "zxviews";
/// [`PaymentAddress`]: zcash_primitives::primitives::PaymentAddress
/// [Zcash Protocol Specification]: https://github.com/zcash/zips/blob/master/protocol/protocol.pdf
pub const HRP_SAPLING_PAYMENT_ADDRESS: &str = "zs";
/// The prefix for a Base58Check-encoded mainnet [`TransparentAddress::PublicKey`].
///
/// [`TransparentAddress::PublicKey`]: zcash_primitives::legacy::TransparentAddress::PublicKey
pub const B58_PUBKEY_ADDRESS_PREFIX: [u8; 2] = [0x1c, 0xb8];
/// The prefix for a Base58Check-encoded mainnet [`TransparentAddress::Script`].
///
/// [`TransparentAddress::Script`]: zcash_primitives::legacy::TransparentAddress::Script
pub const B58_SCRIPT_ADDRESS_PREFIX: [u8; 2] = [0x1c, 0xbd];

View File

@ -28,3 +28,13 @@ pub const HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY: &str = "zxviewtestsapling";
/// [`PaymentAddress`]: zcash_primitives::primitives::PaymentAddress
/// [Zcash Protocol Specification]: https://github.com/zcash/zips/blob/master/protocol/protocol.pdf
pub const HRP_SAPLING_PAYMENT_ADDRESS: &str = "ztestsapling";
/// The prefix for a Base58Check-encoded testnet [`TransparentAddress::PublicKey`].
///
/// [`TransparentAddress::PublicKey`]: zcash_primitives::legacy::TransparentAddress::PublicKey
pub const B58_PUBKEY_ADDRESS_PREFIX: [u8; 2] = [0x1d, 0x25];
/// The prefix for a Base58Check-encoded testnet [`TransparentAddress::Script`].
///
/// [`TransparentAddress::Script`]: zcash_primitives::legacy::TransparentAddress::Script
pub const B58_SCRIPT_ADDRESS_PREFIX: [u8; 2] = [0x1c, 0xba];

View File

@ -6,9 +6,12 @@
//! [`constants`]: crate::constants
use bech32::{self, Error, FromBase32, ToBase32};
use bs58::{self, decode::Error as Bs58Error};
use pairing::bls12_381::Bls12;
use std::convert::TryInto;
use std::io::{self, Write};
use zcash_primitives::{
legacy::TransparentAddress,
primitives::PaymentAddress,
zip32::{ExtendedFullViewingKey, ExtendedSpendingKey},
JUBJUB,
@ -176,6 +179,108 @@ pub fn decode_payment_address(hrp: &str, s: &str) -> Result<Option<PaymentAddres
})
}
/// Writes a [`TransparentAddress`] as a Base58Check-encoded string.
///
/// # Examples
///
/// ```
/// use zcash_client_backend::{
/// constants::testnet::{B58_PUBKEY_ADDRESS_PREFIX, B58_SCRIPT_ADDRESS_PREFIX},
/// encoding::encode_transparent_address,
/// };
/// use zcash_primitives::legacy::TransparentAddress;
///
/// assert_eq!(
/// encode_transparent_address(
/// &B58_PUBKEY_ADDRESS_PREFIX,
/// &B58_SCRIPT_ADDRESS_PREFIX,
/// &TransparentAddress::PublicKey([0; 20]),
/// ),
/// "tm9iMLAuYMzJ6jtFLcA7rzUmfreGuKvr7Ma",
/// );
///
/// assert_eq!(
/// encode_transparent_address(
/// &B58_PUBKEY_ADDRESS_PREFIX,
/// &B58_SCRIPT_ADDRESS_PREFIX,
/// &TransparentAddress::Script([0; 20]),
/// ),
/// "t26YoyZ1iPgiMEWL4zGUm74eVWfhyDMXzY2",
/// );
/// ```
pub fn encode_transparent_address(
pubkey_version: &[u8],
script_version: &[u8],
addr: &TransparentAddress,
) -> String {
let decoded = match addr {
TransparentAddress::PublicKey(key_id) => {
let mut decoded = vec![0; pubkey_version.len() + 20];
decoded[..pubkey_version.len()].copy_from_slice(pubkey_version);
decoded[pubkey_version.len()..].copy_from_slice(key_id);
decoded
}
TransparentAddress::Script(script_id) => {
let mut decoded = vec![0; script_version.len() + 20];
decoded[..script_version.len()].copy_from_slice(script_version);
decoded[script_version.len()..].copy_from_slice(script_id);
decoded
}
};
bs58::encode(decoded).with_check().into_string()
}
/// Decodes a [`TransparentAddress`] from a Base58Check-encoded string.
///
/// # Examples
///
/// ```
/// use zcash_client_backend::{
/// constants::testnet::{B58_PUBKEY_ADDRESS_PREFIX, B58_SCRIPT_ADDRESS_PREFIX},
/// encoding::decode_transparent_address,
/// };
/// use zcash_primitives::legacy::TransparentAddress;
///
/// assert_eq!(
/// decode_transparent_address(
/// &B58_PUBKEY_ADDRESS_PREFIX,
/// &B58_SCRIPT_ADDRESS_PREFIX,
/// "tm9iMLAuYMzJ6jtFLcA7rzUmfreGuKvr7Ma",
/// ),
/// Ok(Some(TransparentAddress::PublicKey([0; 20]))),
/// );
///
/// assert_eq!(
/// decode_transparent_address(
/// &B58_PUBKEY_ADDRESS_PREFIX,
/// &B58_SCRIPT_ADDRESS_PREFIX,
/// "t26YoyZ1iPgiMEWL4zGUm74eVWfhyDMXzY2",
/// ),
/// Ok(Some(TransparentAddress::Script([0; 20]))),
/// );
/// ```
pub fn decode_transparent_address(
pubkey_version: &[u8],
script_version: &[u8],
s: &str,
) -> Result<Option<TransparentAddress>, Bs58Error> {
bs58::decode(s).with_check(None).into_vec().map(|decoded| {
if decoded.starts_with(pubkey_version) {
decoded[pubkey_version.len()..]
.try_into()
.ok()
.map(TransparentAddress::PublicKey)
} else if decoded.starts_with(script_version) {
decoded[script_version.len()..]
.try_into()
.ok()
.map(TransparentAddress::Script)
} else {
None
}
})
}
#[cfg(test)]
mod tests {
use pairing::bls12_381::Bls12;