diff --git a/zebra-chain/src/sapling/tree.rs b/zebra-chain/src/sapling/tree.rs index 1190f6fe8..4728d4d96 100644 --- a/zebra-chain/src/sapling/tree.rs +++ b/zebra-chain/src/sapling/tree.rs @@ -25,13 +25,11 @@ use super::commitment::pedersen_hashes::pedersen_hash; /// MerkleCRH^Sapling Hash Function /// -/// MerkleCRH^Sapling(layer, left, right) := PedersenHash(“Zcash_PH”, l || left ||right) +/// MerkleCRH^Sapling(layer, left, right) := PedersenHash(“Zcash_PH”, l || left || right) /// where l = I2LEBSP_6(MerkleDepth^Sapling − 1 − layer) /// /// https://zips.z.cash/protocol/protocol.pdf#merklecrh -// TODO: refine layer as a wrapper type around a bitvec/bitslice? -// TODO: refine output type as *NodeHash, combine with RootHash -fn merkle_crh_sapling(layer: u8, left: [u8; 32], right: [u8; 32]) -> jubjub::Fq { +fn merkle_crh_sapling(layer: u8, left: [u8; 32], right: [u8; 32]) -> [u8; 32] { let mut s: BitVec = BitVec::new(); // Prefix: l = I2LEBSP_6(MerkleDepth^Sapling − 1 − layer) @@ -39,7 +37,7 @@ fn merkle_crh_sapling(layer: u8, left: [u8; 32], right: [u8; 32]) -> jubjub::Fq s.append(&mut BitVec::::from_slice(&left[..])); s.append(&mut BitVec::::from_slice(&right[..])); - pedersen_hash(*b"Zcash_PH", &s) + pedersen_hash(*b"Zcash_PH", &s).to_bytes() } /// The index of a note’s commitment at the leafmost layer of its Note @@ -54,7 +52,7 @@ pub struct Position(pub(crate) u64); /// Sapling Note Commitment Tree #[derive(Clone, Debug, Default, Eq, PartialEq)] #[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] -struct SaplingNoteCommitmentTree; +struct NoteCommitmentTree; /// Sapling note commitment tree root node hash. /// @@ -72,8 +70,8 @@ impl fmt::Debug for Root { } } -impl From for Root { - fn from(_tree: SaplingNoteCommitmentTree) -> Self { +impl From for Root { + fn from(_tree: NoteCommitmentTree) -> Self { // TODO: The Sapling note commitment tree requires a Pedersen // hash function, not SHA256. @@ -87,7 +85,7 @@ impl From for Root { } } -impl SaplingNoteCommitmentTree { +impl NoteCommitmentTree { /// Get the Jubjub-based Pedersen hash of root node of this merkle /// tree of commitment notes. pub fn hash(&self) -> [u8; 32] { @@ -95,13 +93,13 @@ impl SaplingNoteCommitmentTree { } } -impl ZcashSerialize for SaplingNoteCommitmentTree { +impl ZcashSerialize for NoteCommitmentTree { fn zcash_serialize(&self, _writer: W) -> Result<(), io::Error> { unimplemented!(); } } -impl ZcashDeserialize for SaplingNoteCommitmentTree { +impl ZcashDeserialize for NoteCommitmentTree { fn zcash_deserialize(_reader: R) -> Result { unimplemented!(); } diff --git a/zebra-chain/src/sprout/tree.rs b/zebra-chain/src/sprout/tree.rs index 220e48ee7..0334c50de 100644 --- a/zebra-chain/src/sprout/tree.rs +++ b/zebra-chain/src/sprout/tree.rs @@ -10,11 +10,36 @@ //! //! A root of a note commitment tree is associated with each treestate. #![allow(clippy::unit_arg)] +#![allow(dead_code)] use std::fmt; +use byteorder::{ByteOrder, LittleEndian}; #[cfg(any(test, feature = "proptest-impl"))] use proptest_derive::Arbitrary; +use sha2::digest::generic_array::{typenum::U64, GenericArray}; + +/// MerkleCRH^Sprout Hash Function +/// +/// MerkleCRH^Sprout(layer, left, right) := SHA256Compress(left || right) +/// +/// `layer` is unused for Sprout but used for the Sapling equivalent. +/// +/// https://zips.z.cash/protocol/protocol.pdf#merklecrh +fn merkle_crh_sprout(left: [u8; 32], right: [u8; 32]) -> [u8; 32] { + let mut state = [0u32; 8]; + let mut block = GenericArray::::default(); + + block.as_mut_slice()[0..32].copy_from_slice(&left[..]); + block.as_mut_slice()[32..63].copy_from_slice(&right[..]); + + sha2::compress256(&mut state, &[block]); + + let mut derived_bytes = [0u8; 32]; + LittleEndian::write_u32_into(&state, &mut derived_bytes); + + derived_bytes +} /// Sprout note commitment tree root node hash. ///