Implement TransparentAddress encoding and decoding

This commit is contained in:
Jack Grigg 2019-05-24 15:17:36 +01:00
parent 601e88c633
commit 1c60a79ec1
No known key found for this signature in database
GPG Key ID: 9E8255172BBF9898
5 changed files with 140 additions and 0 deletions

10
Cargo.lock generated
View File

@ -130,6 +130,14 @@ dependencies = [
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bs58"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "byte-tools"
version = "0.3.1"
@ -650,6 +658,7 @@ name = "zcash_client_backend"
version = "0.0.0"
dependencies = [
"bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bs58 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ff 0.4.0",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pairing 0.14.2",
@ -733,6 +742,7 @@ dependencies = [
"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774"
"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09"
"checksum bs58 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0d9644ad62ff4df43da2e057febbbce576f7124cb5cd8e90e0ce7027f38aa2dd"
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"

View File

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

View File

@ -26,3 +26,13 @@ pub const HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY: &str = "zxviews";
/// [`PaymentAddress`]: sapling_crypto::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

@ -26,3 +26,13 @@ pub const HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY: &str = "zxviewtestsapling";
/// [`PaymentAddress`]: sapling_crypto::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

@ -4,6 +4,7 @@
//! module.
use bech32::{self, Error, FromBase32, ToBase32};
use bs58::{self, decode::DecodeError};
use pairing::bls12_381::Bls12;
use std::io::{self, Write};
use zcash_primitives::{
@ -11,6 +12,7 @@ use zcash_primitives::{
primitives::{Diversifier, PaymentAddress},
};
use zcash_primitives::{
legacy::TransparentAddress,
zip32::{ExtendedFullViewingKey, ExtendedSpendingKey},
JUBJUB,
};
@ -182,6 +184,113 @@ 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>, DecodeError> {
let decoded = bs58::decode(s).with_check(None).into_vec()?;
if &decoded[..pubkey_version.len()] == pubkey_version {
if decoded.len() == pubkey_version.len() + 20 {
let mut data = [0; 20];
data.copy_from_slice(&decoded[pubkey_version.len()..]);
Ok(Some(TransparentAddress::PublicKey(data)))
} else {
Ok(None)
}
} else if &decoded[..script_version.len()] == script_version {
if decoded.len() == script_version.len() + 20 {
let mut data = [0; 20];
data.copy_from_slice(&decoded[script_version.len()..]);
Ok(Some(TransparentAddress::Script(data)))
} else {
Ok(None)
}
} else {
Ok(None)
}
}
#[cfg(test)]
mod tests {
use pairing::bls12_381::Bls12;