Filling out Sprout and Sapling Shielded Addresses
This commit is contained in:
parent
7af9b80f3b
commit
1e71793357
|
@ -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<W: io::Write>(&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<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
|
||||||
|
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()?),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue