From b9cea33804fa5fb8390162ba2e8a54744b55485e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 16 Apr 2019 00:27:44 +0100 Subject: [PATCH] Move merkle_tree::Node into sapling module This makes the merkle_tree module properly generic over the tree hash. It still hard-codes a depth 32 tree, because Rust doesn't yet support generic sizes, and we are unlikely to need to alter the tree depth in future circuit changes. --- zcash_primitives/src/merkle_tree.rs | 153 +++++++++------------------- zcash_primitives/src/sapling.rs | 64 +++++++++++- zcash_proofs/src/sapling/prover.rs | 10 +- 3 files changed, 118 insertions(+), 109 deletions(-) diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 0a830ba..08bf992 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -1,81 +1,35 @@ use byteorder::{LittleEndian, ReadBytesExt}; -use ff::{PrimeField, PrimeFieldRepr}; -use pairing::bls12_381::{Bls12, Fr, FrRepr}; -use sapling_crypto::{circuit::sapling::TREE_DEPTH, primitives::Note}; +use sapling_crypto::circuit::sapling::TREE_DEPTH; use std::collections::VecDeque; use std::io::{self, Read, Write}; use std::iter; -use sapling::merkle_hash; +use sapling::SAPLING_COMMITMENT_TREE_DEPTH; use serialize::{Optional, Vector}; -const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32; +/// A hashable node within a Merkle tree. +pub trait Hashable: Clone + Copy { + /// Parses a node from the given byte source. + fn read(reader: R) -> io::Result; + + /// Serializes this node. + fn write(&self, writer: W) -> io::Result<()>; -trait Hashable: Clone + Copy { /// Returns the parent node within the tree of the two given nodes. fn combine(usize, &Self, &Self) -> Self; /// Returns a blank leaf node. fn blank() -> Self; + + /// Returns the empty root for the given depth. + fn empty_root(usize) -> Self; } -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Node { - repr: FrRepr, -} - -impl Node { - pub fn new(repr: FrRepr) -> Self { - Node { repr } - } - - pub fn read(mut reader: R) -> io::Result { - let mut repr = FrRepr::default(); - repr.read_le(&mut reader)?; - Ok(Node::new(repr)) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - self.repr.write_le(&mut writer) - } -} - -impl Hashable for Node { - fn combine(depth: usize, lhs: &Self, rhs: &Self) -> Self { - Node { - repr: merkle_hash(depth, &lhs.repr, &rhs.repr), - } - } - - fn blank() -> Self { - Node { - repr: Note::::uncommitted().into_repr(), - } - } -} - -impl From for Fr { - fn from(node: Node) -> Self { - Fr::from_repr(node.repr).expect("Tree nodes should be in the prime field") - } -} - -lazy_static! { - static ref EMPTY_ROOTS: Vec = { - let mut v = vec![Node::blank()]; - for d in 0..SAPLING_COMMITMENT_TREE_DEPTH { - let next = Node::combine(d, &v[d], &v[d]); - v.push(next); - } - v - }; -} - -struct PathFiller { +struct PathFiller { queue: VecDeque, } -impl PathFiller { +impl PathFiller { fn empty() -> Self { PathFiller { queue: VecDeque::new(), @@ -83,19 +37,21 @@ impl PathFiller { } fn next(&mut self, depth: usize) -> Node { - self.queue.pop_front().unwrap_or_else(|| EMPTY_ROOTS[depth]) + self.queue + .pop_front() + .unwrap_or_else(|| Node::empty_root(depth)) } } /// A Merkle tree of Sapling note commitments. #[derive(Clone)] -pub struct CommitmentTree { +pub struct CommitmentTree { left: Option, right: Option, parents: Vec>, } -impl CommitmentTree { +impl CommitmentTree { /// Creates an empty tree. pub fn new() -> Self { CommitmentTree { @@ -192,7 +148,7 @@ impl CommitmentTree { self.root_inner(SAPLING_COMMITMENT_TREE_DEPTH, PathFiller::empty()) } - fn root_inner(&self, depth: usize, mut filler: PathFiller) -> Node { + fn root_inner(&self, depth: usize, mut filler: PathFiller) -> Node { assert!(depth > 0); // 1) Hash left and right leaves together. @@ -227,15 +183,15 @@ impl CommitmentTree { } #[derive(Clone)] -pub struct IncrementalWitness { - tree: CommitmentTree, +pub struct IncrementalWitness { + tree: CommitmentTree, filled: Vec, cursor_depth: usize, - cursor: Option, + cursor: Option>, } -impl IncrementalWitness { - pub fn from_tree(tree: &CommitmentTree) -> IncrementalWitness { +impl IncrementalWitness { + pub fn from_tree(tree: &CommitmentTree) -> IncrementalWitness { IncrementalWitness { tree: tree.clone(), filled: vec![], @@ -272,7 +228,7 @@ impl IncrementalWitness { self.tree.size() - 1 } - fn filler(&self) -> PathFiller { + fn filler(&self) -> PathFiller { let cursor_root = self .cursor .as_ref() @@ -374,11 +330,11 @@ impl IncrementalWitness { } /// Returns the current witness, or None if the tree is empty. - pub fn path(&self) -> Option { + pub fn path(&self) -> Option> { self.path_inner(SAPLING_COMMITMENT_TREE_DEPTH) } - fn path_inner(&self, depth: usize) -> Option { + fn path_inner(&self, depth: usize) -> Option> { let mut filler = self.filler(); let mut auth_path = Vec::new(); @@ -406,10 +362,7 @@ impl IncrementalWitness { assert_eq!(auth_path.len(), depth); Some(CommitmentTreeWitness::from_path( - auth_path - .iter() - .map(|n| n.map(|(node, b)| (node.into(), b))) - .collect(), + auth_path, self.position() as u64, )) } @@ -418,13 +371,13 @@ impl IncrementalWitness { /// A witness to a path from a position in a particular Sapling commitment tree /// to the root of that tree. #[derive(Debug, PartialEq)] -pub struct CommitmentTreeWitness { - pub auth_path: Vec>, +pub struct CommitmentTreeWitness { + pub auth_path: Vec>, pub position: u64, } -impl CommitmentTreeWitness { - pub fn from_path(auth_path: Vec>, position: u64) -> Self { +impl CommitmentTreeWitness { + pub fn from_path(auth_path: Vec>, position: u64) -> Self { CommitmentTreeWitness { auth_path, position, @@ -449,7 +402,8 @@ impl CommitmentTreeWitness { // The vector works in reverse for i in (0..depth).rev() { // skip length of inner vector - if witness[0] != 32 { // the length of a pedersen hash + if witness[0] != 32 { + // the length of a pedersen hash return Err(()); } witness = &witness[1..]; @@ -460,11 +414,7 @@ impl CommitmentTreeWitness { witness = &witness[32..]; // Sibling node should be an element of Fr - let sibling = match { - let mut repr = FrRepr::default(); - repr.read_le(&sibling[..]).expect("length is 32 bytes"); - Fr::from_repr(repr) - } { + let sibling = match Node::read(&sibling[..]) { Ok(p) => p, Err(_) => return Err(()), }; @@ -506,10 +456,8 @@ impl CommitmentTreeWitness { #[cfg(test)] mod tests { - use super::{ - CommitmentTree, CommitmentTreeWitness, Hashable, IncrementalWitness, Node, PathFiller, - EMPTY_ROOTS, - }; + use super::{CommitmentTree, CommitmentTreeWitness, Hashable, IncrementalWitness, PathFiller}; + use sapling::Node; use ff::PrimeFieldRepr; use hex; @@ -554,7 +502,7 @@ mod tests { const TESTING_DEPTH: usize = 4; - struct TestCommitmentTree(CommitmentTree); + struct TestCommitmentTree(CommitmentTree); impl TestCommitmentTree { fn new() -> Self { @@ -583,7 +531,7 @@ mod tests { } } - struct TestIncrementalWitness(IncrementalWitness); + struct TestIncrementalWitness(IncrementalWitness); impl TestIncrementalWitness { fn from_tree(tree: &TestCommitmentTree) -> Self { @@ -607,7 +555,7 @@ mod tests { self.0.root_inner(TESTING_DEPTH) } - fn path(&self) -> Option { + fn path(&self) -> Option> { self.0.path_inner(TESTING_DEPTH) } } @@ -616,9 +564,8 @@ mod tests { fn empty_root_test_vectors() { let mut tmp = [0u8; 32]; for i in 0..HEX_EMPTY_ROOTS.len() { - EMPTY_ROOTS[i] - .repr - .write_le(&mut tmp[..]) + Node::empty_root(i) + .write(&mut tmp[..]) .expect("length is 32 bytes"); assert_eq!(hex::encode(tmp), HEX_EMPTY_ROOTS[i]); } @@ -627,10 +574,9 @@ mod tests { #[test] fn sapling_empty_root() { let mut tmp = [0u8; 32]; - CommitmentTree::new() + CommitmentTree::::new() .root() - .repr - .write_le(&mut tmp[..]) + .write(&mut tmp[..]) .expect("length is 32 bytes"); assert_eq!( hex::encode(tmp), @@ -640,12 +586,11 @@ mod tests { #[test] fn empty_commitment_tree_roots() { - let tree = CommitmentTree::new(); + let tree = CommitmentTree::::new(); let mut tmp = [0u8; 32]; for i in 1..HEX_EMPTY_ROOTS.len() { tree.root_inner(i, PathFiller::empty()) - .repr - .write_le(&mut tmp[..]) + .write(&mut tmp[..]) .expect("length is 32 bytes"); assert_eq!(hex::encode(tmp), HEX_EMPTY_ROOTS[i]); } @@ -980,9 +925,7 @@ mod tests { fn assert_root_eq(root: Node, expected: &str) { let mut tmp = [0u8; 32]; - root.repr - .write_le(&mut tmp[..]) - .expect("length is 32 bytes"); + root.write(&mut tmp[..]).expect("length is 32 bytes"); assert_eq!(hex::encode(tmp), expected); } diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index 62f5118..356f072 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -1,14 +1,19 @@ -use ff::{BitIterator, PrimeField}; +use ff::{BitIterator, PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use rand::OsRng; use sapling_crypto::{ jubjub::{fs::Fs, FixedGenerators, JubjubBls12}, pedersen_hash::{pedersen_hash, Personalization}, + primitives::Note, redjubjub::{PrivateKey, PublicKey, Signature}, }; +use std::io::{self, Read, Write}; +use crate::merkle_tree::Hashable; use JUBJUB; +pub(crate) const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32; + /// Compute a parent node in the Sapling commitment tree given its two children. pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr { let lhs = { @@ -40,6 +45,63 @@ pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr { .into_repr() } +/// A node within a Merkle tree. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Node { + repr: FrRepr, +} + +impl Node { + pub fn new(repr: FrRepr) -> Self { + Node { repr } + } +} + +impl Hashable for Node { + fn read(mut reader: R) -> io::Result { + let mut repr = FrRepr::default(); + repr.read_le(&mut reader)?; + Ok(Node::new(repr)) + } + + fn write(&self, mut writer: W) -> io::Result<()> { + self.repr.write_le(&mut writer) + } + + fn combine(depth: usize, lhs: &Self, rhs: &Self) -> Self { + Node { + repr: merkle_hash(depth, &lhs.repr, &rhs.repr), + } + } + + fn blank() -> Self { + Node { + repr: Note::::uncommitted().into_repr(), + } + } + + fn empty_root(depth: usize) -> Self { + EMPTY_ROOTS[depth] + } +} + +impl From for Fr { + fn from(node: Node) -> Self { + Fr::from_repr(node.repr).expect("Tree nodes should be in the prime field") + } +} + +lazy_static! { + static ref EMPTY_ROOTS: Vec = { + let mut v = vec![Node::blank()]; + for d in 0..SAPLING_COMMITMENT_TREE_DEPTH { + let next = Node::combine(d, &v[d], &v[d]); + v.push(next); + } + v + }; +} + /// Create the spendAuthSig for a Sapling SpendDescription. pub fn spend_sig( ask: PrivateKey, diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index feb1d2c..4d63033 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -13,7 +13,7 @@ use sapling_crypto::{ primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, redjubjub::{PrivateKey, PublicKey, Signature}, }; -use zcash_primitives::merkle_tree::CommitmentTreeWitness; +use zcash_primitives::{merkle_tree::CommitmentTreeWitness, sapling::Node}; use super::compute_value_balance; @@ -43,7 +43,7 @@ impl SaplingProvingContext { ar: Fs, value: u64, anchor: Fr, - witness: CommitmentTreeWitness, + witness: CommitmentTreeWitness, proving_key: &Parameters, verifying_key: &PreparedVerifyingKey, params: &JubjubBls12, @@ -112,7 +112,11 @@ impl SaplingProvingContext { payment_address: Some(payment_address), commitment_randomness: Some(rcm), ar: Some(ar), - auth_path: witness.auth_path, + auth_path: witness + .auth_path + .iter() + .map(|n| n.map(|(node, b)| (node.into(), b))) + .collect(), anchor: Some(anchor), };