From aa18937b60c59f00475227c512efe7e7305edf0d Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Tue, 14 Apr 2020 19:25:34 -0400 Subject: [PATCH] Add network, impl Display and FromStr for SaplingShieldedAddress --- zebra-chain/src/addresses/sapling.rs | 95 +++++++++++++--------------- zebra-chain/src/keys/sapling.rs | 2 + 2 files changed, 47 insertions(+), 50 deletions(-) diff --git a/zebra-chain/src/addresses/sapling.rs b/zebra-chain/src/addresses/sapling.rs index dafe45ae..35dd5fc6 100644 --- a/zebra-chain/src/addresses/sapling.rs +++ b/zebra-chain/src/addresses/sapling.rs @@ -1,6 +1,9 @@ //! Sapling Shielded Payment Address types. -use std::{fmt, io}; +use std::{ + fmt, + io::{self, Read, Write}, +}; use bech32::{self, FromBase32, ToBase32}; @@ -9,7 +12,7 @@ use proptest::{arbitrary::Arbitrary, array, prelude::*}; use crate::{ keys::sapling, - serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize}, + serialization::{ReadZcashExt, SerializationError}, Network, }; @@ -25,8 +28,9 @@ mod human_readable_parts { /// defined in [ยง4.2.2][4.2.2]. /// /// [4.2.2]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, Eq, PartialEq)] pub struct SaplingShieldedAddress { + network: Network, diversifier: sapling::Diversifier, transmission_key: sapling::TransmissionKey, } @@ -34,50 +38,26 @@ pub struct SaplingShieldedAddress { impl fmt::Debug for SaplingShieldedAddress { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("SaplingShieldedAddress") + .field("network", &self.network) .field("diversifier", &self.diversifier) .field("transmission_key", &self.transmission_key) .finish() } } -impl SaplingShieldedAddress { - fn to_human_readable_address(&self, network: Network) -> Result { +impl fmt::Display for SaplingShieldedAddress { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut bytes = io::Cursor::new(Vec::new()); - let _ = self.zcash_serialize(&mut bytes); - let hrp; + let _ = bytes.write_all(&self.diversifier.0[..]); + let _ = bytes.write_all(&self.transmission_key.to_bytes()); - match network { - Network::Mainnet => hrp = human_readable_parts::MAINNET, - _ => hrp = human_readable_parts::TESTNET, - } + let hrp = match self.network { + Network::Mainnet => human_readable_parts::MAINNET, + _ => human_readable_parts::TESTNET, + }; - bech32::encode(hrp, bytes.get_ref().to_base32()) - } -} - -impl Eq for SaplingShieldedAddress {} - -impl ZcashSerialize for SaplingShieldedAddress { - fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { - writer.write_all(&self.diversifier.0[..])?; - writer.write_all(&self.transmission_key.to_bytes())?; - - Ok(()) - } -} - -impl ZcashDeserialize for SaplingShieldedAddress { - fn zcash_deserialize(mut reader: R) -> Result { - let mut diversifier_bytes = [0; 11]; - reader.read_exact(&mut diversifier_bytes)?; - - let transmission_key_bytes = reader.read_32_bytes()?; - - Ok(SaplingShieldedAddress { - diversifier: sapling::Diversifier(diversifier_bytes), - transmission_key: sapling::TransmissionKey::from_bytes(transmission_key_bytes), - }) + bech32::encode_to_fmt(f, hrp, bytes.get_ref().to_base32()).unwrap() } } @@ -86,9 +66,22 @@ impl std::str::FromStr for SaplingShieldedAddress { fn from_str(s: &str) -> Result { match bech32::decode(s) { - Ok((_, bytes)) => { - let decoded = Vec::::from_base32(&bytes).unwrap(); - Self::zcash_deserialize(io::Cursor::new(decoded)) + Ok((hrp, bytes)) => { + let mut decoded_bytes = io::Cursor::new(Vec::::from_base32(&bytes).unwrap()); + + let mut diversifier_bytes = [0; 11]; + decoded_bytes.read_exact(&mut diversifier_bytes)?; + + let transmission_key_bytes = decoded_bytes.read_32_bytes()?; + + Ok(SaplingShieldedAddress { + network: match hrp.as_str() { + human_readable_parts::MAINNET => Network::Mainnet, + _ => Network::Testnet, + }, + diversifier: sapling::Diversifier(diversifier_bytes), + transmission_key: sapling::TransmissionKey::from_bytes(transmission_key_bytes), + }) } Err(_) => Err(SerializationError::Parse("bech32 decoding error")), } @@ -100,9 +93,14 @@ impl Arbitrary for SaplingShieldedAddress { type Parameters = (); fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { - (array::uniform11(any::()), array::uniform32(any::())) - .prop_map(|(diversifier_bytes, transmission_key_bytes)| { + ( + any::(), + array::uniform11(any::()), + array::uniform32(any::()), + ) + .prop_map(|(network, diversifier_bytes, transmission_key_bytes)| { return Self { + network, diversifier: sapling::Diversifier(diversifier_bytes), transmission_key: sapling::TransmissionKey::from_bytes(transmission_key_bytes), }; @@ -122,15 +120,13 @@ mod tests { use super::*; #[test] - fn to_human_readable_address() { + fn from_str_display() { let zs_addr = SaplingShieldedAddress::from_str( "zs1qqqqqqqqqqqqqqqqqrjq05nyfku05msvu49mawhg6kr0wwljahypwyk2h88z6975u563j8nfaxd", ) .expect("sapling z-addr string to parse"); - let address = zs_addr - .to_human_readable_address(Network::Mainnet) - .expect("z-addr to serialize in a human-readable way"); + let address = zs_addr.to_string(); assert_eq!( format!("{}", address), @@ -154,6 +150,7 @@ mod tests { let transmission_key = sapling::TransmissionKey::from(incoming_viewing_key, diversifier); let _sapling_shielded_address = SaplingShieldedAddress { + network: Network::Mainnet, diversifier, transmission_key, }; @@ -167,11 +164,9 @@ proptest! { // #[test] // fn sapling_address_roundtrip(zaddr in any::()) { - // let mut data = Vec::new(); + // let string = zaddr.to_string(); - // zaddr.zcash_serialize(&mut data).expect("sapling z-addr should serialize"); - - // let zaddr2 = SaplingShieldedAddress::zcash_deserialize(&data[..]) + // let zaddr2 = string.parse::() // .expect("randomized sapling z-addr should deserialize"); // prop_assert_eq![zaddr, zaddr2]; diff --git a/zebra-chain/src/keys/sapling.rs b/zebra-chain/src/keys/sapling.rs index 54171927..4488039a 100644 --- a/zebra-chain/src/keys/sapling.rs +++ b/zebra-chain/src/keys/sapling.rs @@ -480,6 +480,8 @@ impl Diversifier { #[derive(Copy, Clone, PartialEq)] pub struct TransmissionKey(pub jubjub::AffinePoint); +impl Eq for TransmissionKey {} + impl Deref for TransmissionKey { type Target = jubjub::AffinePoint;