Fix up TransparentAddresses

This commit is contained in:
Deirdre Connolly 2020-03-05 20:19:10 -05:00 committed by Deirdre Connolly
parent 16ee53a909
commit 9887b7c8b7
4 changed files with 97 additions and 42 deletions

7
Cargo.lock generated
View File

@ -191,6 +191,12 @@ dependencies = [
"subtle",
]
[[package]]
name = "bs58"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b170cd256a3f9fa6b9edae3e44a7dfdfc77e8124dbc3e2612d75f9c3e2396dae"
[[package]]
name = "byte-tools"
version = "0.3.1"
@ -2036,6 +2042,7 @@ dependencies = [
name = "zebra-chain"
version = "0.1.0"
dependencies = [
"bs58",
"byteorder",
"chrono",
"ed25519-zebra",

View File

@ -8,6 +8,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bs58 = "0.3.0"
byteorder = "1.3"
chrono = "0.4"
futures = "0.3"

View File

@ -1,13 +1,16 @@
//! Address types.
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use ripemd160::Ripdemd160;
use std::{fmt, io};
use bs58;
use ripemd160::{Digest, Ripemd160};
use secp256k1::PublicKey;
use sha2::Sha256;
use crate::serialization::{
ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize, ZcashSerialize,
};
#[cfg(test)]
use proptest_derive::Arbitrary;
use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize};
use crate::types::Script;
@ -19,11 +22,15 @@ use crate::types::Script;
/// https://en.bitcoin.it/Base58Check_encoding#Encoding_a_Bitcoin_address
#[derive(Copy, Clone, Eq, PartialEq)]
#[cfg_attr(test, derive(Arbitrary))]
struct AddressPayloadHash(pub [u8; 20]);
pub struct AddressPayloadHash(pub [u8; 20]);
impl<'a> From<&'a [u8]> for AddressPayloadHash {
fn from(bytes: &'a [u8]) -> Self {
Self(Ripdemd160::digest(Sha256::digest(bytes)))
let sha_hash = Sha256::digest(bytes);
let ripe_hash = Ripemd160::digest(&sha_hash);
let mut payload = [0u8; 20];
payload[..].copy_from_slice(&ripe_hash[..]);
Self(payload)
}
}
@ -37,7 +44,7 @@ impl fmt::Debug for AddressPayloadHash {
/// An enum describing the possible network choices.
// XXX Stolen from zebra-network for now.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum Network {
/// The production mainnet.
Mainnet,
@ -57,42 +64,89 @@ pub enum Network {
///
/// https://zips.z.cash/protocol/protocol.pdf#transparentaddrencoding
#[derive(Copy, Clone, Eq, PartialEq)]
#[cfg_attr(test, derive(Arbitrary))]
// #[cfg_attr(test, derive(Arbitrary))]
pub enum TransparentAddress {
/// P2SH (Pay to Script Hash) addresses
PayToScriptHash {
/// Production, test, or other network
network: Network,
script: AddressPayloadHash,
/// 20 bytes specifying a script hash.
script_hash: AddressPayloadHash,
},
/// P2PKH (Pay to Public Key Hash) addresses
PayToPublicKeyHash {
/// Production, test, or other network
network: Network,
pub_key: AddressPayloadHash,
/// 20 bytes specifying a public key hash, which is a RIPEMD-160
/// hash of a SHA-256 hash of a compressed ECDSA key encoding.
pub_key_hash: AddressPayloadHash,
},
}
impl From<Script> for TransparentAddress {
fn from(script: Script) -> Self {
TransparentAddress::PayToScriptHash {
network: Network::Mainnet,
script_hash: AddressPayloadHash::from(&script.0[..]),
}
}
}
impl From<PublicKey> for TransparentAddress {
fn from(pub_key: PublicKey) -> Self {
TransparentAddress::PayToPublicKeyHash {
network: Network::Mainnet,
pub_key_hash: AddressPayloadHash::from(&pub_key.serialize()[..]),
}
}
}
impl fmt::Debug for TransparentAddress {
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("TransparentAddress")
.field(&bs58::encode(bytes.get_ref()).into_vec())
.finish()
}
}
impl ZcashSerialize for TransparentAddress {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
match self {
TransparentAddress::PayToScriptHash { network, script_hash } => {
if network == Network::Mainnet {
TransparentAddress::PayToScriptHash {
network,
script_hash,
} => {
if *network == Network::Mainnet {
writer.write_all(&[0x1C, 0xBD][..])?
} else {
// Dev network doesn't have a recommendation so we
// default to testnet bytes.
writer.write_all(&[0x1C, 0xBA][..])?
}
writer.write_all::<BigEndian>(script_hash[..])?
// XXX I'm asuming this is BigEndian because we're not
// explicitly making it LittleEndian?
writer.write_all(&script_hash.0)?
}
TransparentAddress::PayToPublicKeyHash{network, pub_key_hash) => {
if network == Network::Mainnet {
TransparentAddress::PayToPublicKeyHash {
network,
pub_key_hash,
} => {
if *network == Network::Mainnet {
writer.write_all(&[0x1C, 0xB8][..])?
} else {
// Dev network doesn't have a recommendation so we
// default to testnet bytes.
writer.write_all(&[0x1D, 0x25][..])?
}
writer.write_all::<BigEndian>(hash[..])?
// XXX I'm asuming this is BigEndian because we're not
// explicitly making it LittleEndian?
writer.write_all(&pub_key_hash.0)?
}
}
Ok(())
}
}
@ -105,32 +159,25 @@ impl ZcashDeserialize for TransparentAddress {
reader.read_exact(&mut hash_bytes)?;
match version_bytes {
[0x1c, 0xbd] => {
Ok(TransparentAddress::PayToScriptHash {
network: Network::Mainnet,
script: AddressPayloadHash(hash_bytes)
})
},
[0x1c, 0xbd] => Ok(TransparentAddress::PayToScriptHash {
network: Network::Mainnet,
script_hash: AddressPayloadHash(hash_bytes),
}),
// Currently only reading !mainnet versions as testnet.
[0x1c, 0xba] => {
Ok(TransparentAddress::PayToScriptHash {
network: Network::Testnet,
script: AddressPayloadHash(hash_bytes)
})
},
[0x1c, 0xb8] => {
Ok(TransparentAddress::PayToPublicKeyHash {
network: Network::Mainnet,
pub_key: AddressPayloadHash(hash_bytes)
})
},
[0x1c, 0xba] => Ok(TransparentAddress::PayToScriptHash {
network: Network::Testnet,
script_hash: AddressPayloadHash(hash_bytes),
}),
[0x1c, 0xb8] => Ok(TransparentAddress::PayToPublicKeyHash {
network: Network::Mainnet,
pub_key_hash: AddressPayloadHash(hash_bytes),
}),
// Currently only reading !mainnet versions as testnet.
[0x1d, 0x25] => {
Ok(TransparentAddress::PayToPublicKeyHash {
network: Network::Testnet,
pub_key: AddressPayloadHash(hash_bytes)
})
}
[0x1d, 0x25] => Ok(TransparentAddress::PayToPublicKeyHash {
network: Network::Testnet,
pub_key_hash: AddressPayloadHash(hash_bytes),
}),
_ => Err(SerializationError::Parse("bad t-addr version/type")),
}
}
}

View File

@ -2,12 +2,12 @@
#![doc(html_logo_url = "https://www.zfnd.org/images/zebra-icon.png")]
#![doc(html_root_url = "https://doc.zebra.zfnd.org/zebra_chain")]
#![deny(missing_docs)]
mod merkle_tree;
mod sha256d_writer;
pub mod addresses;
pub mod block;
pub mod equihash_solution;
pub mod keys;