From 1e717933571b94a1c0de7405110164ea02059624 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Fri, 13 Mar 2020 18:58:49 -0400 Subject: [PATCH] Filling out Sprout and Sapling Shielded Addresses --- zebra-chain/src/addresses/sapling.rs | 0 zebra-chain/src/addresses/sprout.rs | 85 ++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 zebra-chain/src/addresses/sapling.rs create mode 100644 zebra-chain/src/addresses/sprout.rs diff --git a/zebra-chain/src/addresses/sapling.rs b/zebra-chain/src/addresses/sapling.rs new file mode 100644 index 00000000..e69de29b diff --git a/zebra-chain/src/addresses/sprout.rs b/zebra-chain/src/addresses/sprout.rs new file mode 100644 index 00000000..573ed473 --- /dev/null +++ b/zebra-chain/src/addresses/sprout.rs @@ -0,0 +1,85 @@ +//! Sprout Shielded Payment Address types. + +use std::{fmt, io}; + +use bs58; +use ripemd160::{Digest, Ripemd160}; +use sha2::Sha256; +use x25519_dalek; + +#[cfg(test)] +use proptest::{arbitrary::Arbitrary, collection::vec, prelude::*}; + +use crate::{ + keys::sprout, + serialization::{ + ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize, ZcashSerialize, + }, + Network, +}; + +/// Sprout Shielded Payment Addresses +/// +/// In Bitcoin a single byte is used for the version field identifying +/// the address type. In Zcash two bytes are used. For addresses on +/// the production network, this and the encoded length cause the first +/// two characters of the Base58Check encoding to be xed as “t3” for +/// P2SH addresses, and as “t1” for P2PKH addresses. (This does not +/// imply that a transparent Zcash address can be parsed identically +/// to a Bitcoin address just by removing the “t”.) +/// +/// https://zips.z.cash/protocol/protocol.pdf#transparentaddrencoding +#[derive(Clone, Eq, PartialEq)] +pub struct SproutShieldedAddress { + network: Network, + paying_key: sprout::PayingKey, + transmission_key: x25519_dalek::PublicKey, +} + +impl fmt::Debug for SproutShieldedAddress { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut bytes = io::Cursor::new(Vec::new()); + let _ = self.zcash_serialize(&mut bytes); + + f.debug_tuple("SproutShieldedAddress") + .field(&bs58::encode(bytes.get_ref()).with_check().into_string()) + .finish() + } +} + +impl ZcashSerialize for SproutShieldedAddress { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + if self.network == Network::Mainnet { + writer.write_all(&[0x16, 0x9A][..])? + } else { + writer.write_all(&[0x16, 0xB6][..])? + } + writer.write_all(&self.paying_key.0[..])?; + // XXX revisit to see if we want to impl ZcashSerialize on + // x25519_dalek::PublicKey + writer.write_all(self.transmission_key.as_bytes())?; + + Ok(()) + } +} + +impl ZcashDeserialize for SproutShieldedAddress { + fn zcash_deserialize(mut reader: R) -> Result { + let mut version_bytes = [0; 2]; + reader.read_exact(&mut version_bytes)?; + + let network = match version_bytes { + [0x16, 0x9A] => Network::Mainnet, + [0x16, 0xB6] => Network::Testnet, + _ => panic!(SerializationError::Parse( + "bad sprout shielded addr version/type", + )), + }; + + Ok(SproutShieldedAddress { + network, + paying_key: sprout::PayingKey(reader.read_32_bytes()?), + transmission_key: sprout::TransmissionKey(reader.read_32_bytes()?), + }) + } +}