diff --git a/Cargo.lock b/Cargo.lock index 34b20d2..26def55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -553,6 +553,7 @@ dependencies = [ "pairing 0.14.2", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", + "zcash_primitives 0.0.0", ] [metadata] diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 20af7ed..96bb718 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -57,13 +57,14 @@ use std::os::windows::ffi::OsStringExt; use sapling_crypto::primitives::{ProofGenerationKey, ViewingKey}; use zcash_primitives::{ + merkle_tree::CommitmentTreeWitness, note_encryption::sapling_ka_agree, sapling::{merkle_hash, spend_sig}, zip32, JUBJUB, }; use zcash_proofs::{ load_parameters, - sapling::{CommitmentTreeWitness, SaplingProvingContext, SaplingVerificationContext}, + sapling::{SaplingProvingContext, SaplingVerificationContext}, }; pub mod equihash; diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 6e458e4..a715215 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -1,6 +1,7 @@ -use ff::PrimeField; +use byteorder::{LittleEndian, ReadBytesExt}; +use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; -use sapling_crypto::primitives::Note; +use sapling_crypto::{circuit::sapling::TREE_DEPTH, primitives::Note}; use std::collections::VecDeque; use sapling::merkle_hash; @@ -191,6 +192,76 @@ impl CommitmentTree { } } +/// A witness to a path from a position in a particular Sapling commitment tree +/// to the root of that tree. +pub struct CommitmentTreeWitness { + pub auth_path: Vec>, + pub position: u64, +} + +impl CommitmentTreeWitness { + pub fn from_slice(mut witness: &[u8]) -> Result { + // Skip the first byte, which should be "32" to signify the length of + // the following vector of Pedersen hashes. + assert_eq!(witness[0], TREE_DEPTH as u8); + witness = &witness[1..]; + + // Begin to construct the authentication path + let mut auth_path = vec![None; TREE_DEPTH]; + + // The vector works in reverse + for i in (0..TREE_DEPTH).rev() { + // skip length of inner vector + assert_eq!(witness[0], 32); // the length of a pedersen hash + witness = &witness[1..]; + + // Grab the sibling node at this depth in the tree + let mut sibling = [0u8; 32]; + sibling.copy_from_slice(&witness[0..32]); + 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) + } { + Ok(p) => p, + Err(_) => return Err(()), + }; + + // Set the value in the auth path; we put false here + // for now (signifying the position bit) which we'll + // fill in later. + auth_path[i] = Some((sibling, false)); + } + + // Read the position from the witness + let position = witness + .read_u64::() + .expect("should have had index at the end"); + + // Given the position, let's finish constructing the authentication + // path + let mut tmp = position; + for i in 0..TREE_DEPTH { + auth_path[i].as_mut().map(|p| p.1 = (tmp & 1) == 1); + + tmp >>= 1; + } + + // The witness should be empty now; if it wasn't, the caller would + // have provided more information than they should have, indicating + // a bug downstream + assert_eq!(witness.len(), 0); + + Ok(CommitmentTreeWitness { + auth_path, + position, + }) + } +} + #[cfg(test)] mod tests { use super::{CommitmentTree, Hashable, Node, PathFiller, EMPTY_ROOTS}; diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index 5bcdb26..85a7210 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -12,6 +12,7 @@ ff = { path = "../ff" } pairing = { path = "../pairing" } rand = "0.4" sapling-crypto = { path = "../sapling-crypto" } +zcash_primitives = { path = "../zcash_primitives" } [dependencies.blake2-rfc] git = "https://github.com/gtank/blake2-rfc" diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs index ca17a8b..97dd501 100644 --- a/zcash_proofs/src/lib.rs +++ b/zcash_proofs/src/lib.rs @@ -5,6 +5,7 @@ extern crate ff; extern crate pairing; extern crate rand; extern crate sapling_crypto; +extern crate zcash_primitives; use bellman::groth16::{prepare_verifying_key, Parameters, PreparedVerifyingKey, VerifyingKey}; use pairing::bls12_381::Bls12; diff --git a/zcash_proofs/src/sapling/mod.rs b/zcash_proofs/src/sapling/mod.rs index 2cfb2e9..4c37306 100644 --- a/zcash_proofs/src/sapling/mod.rs +++ b/zcash_proofs/src/sapling/mod.rs @@ -6,7 +6,7 @@ use sapling_crypto::jubjub::{ mod prover; mod verifier; -pub use self::prover::{CommitmentTreeWitness, SaplingProvingContext}; +pub use self::prover::SaplingProvingContext; pub use self::verifier::SaplingVerificationContext; // This function computes `value` in the exponent of the value commitment base diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index 3a3511c..feb1d2c 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -1,92 +1,22 @@ use bellman::groth16::{ create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof, }; -use byteorder::{LittleEndian, ReadBytesExt}; -use ff::{Field, PrimeField, PrimeFieldRepr}; -use pairing::bls12_381::{Bls12, Fr, FrRepr}; +use ff::Field; +use pairing::bls12_381::{Bls12, Fr}; use rand::{OsRng, Rand}; use sapling_crypto::{ circuit::{ multipack, - sapling::{Output, Spend, TREE_DEPTH}, + sapling::{Output, Spend}, }, jubjub::{edwards, fs::Fs, FixedGenerators, JubjubBls12, Unknown}, primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, redjubjub::{PrivateKey, PublicKey, Signature}, }; +use zcash_primitives::merkle_tree::CommitmentTreeWitness; use super::compute_value_balance; -/// A witness to a path from a postion in a particular Sapling commitment tree -/// to the root of that tree. -pub struct CommitmentTreeWitness { - auth_path: Vec>, - position: u64, -} - -impl CommitmentTreeWitness { - pub fn from_slice(mut witness: &[u8]) -> Result { - // Skip the first byte, which should be "32" to signify the length of - // the following vector of Pedersen hashes. - assert_eq!(witness[0], TREE_DEPTH as u8); - witness = &witness[1..]; - - // Begin to construct the authentication path - let mut auth_path = vec![None; TREE_DEPTH]; - - // The vector works in reverse - for i in (0..TREE_DEPTH).rev() { - // skip length of inner vector - assert_eq!(witness[0], 32); // the length of a pedersen hash - witness = &witness[1..]; - - // Grab the sibling node at this depth in the tree - let mut sibling = [0u8; 32]; - sibling.copy_from_slice(&witness[0..32]); - 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) - } { - Ok(p) => p, - Err(_) => return Err(()), - }; - - // Set the value in the auth path; we put false here - // for now (signifying the position bit) which we'll - // fill in later. - auth_path[i] = Some((sibling, false)); - } - - // Read the position from the witness - let position = witness - .read_u64::() - .expect("should have had index at the end"); - - // Given the position, let's finish constructing the authentication - // path - let mut tmp = position; - for i in 0..TREE_DEPTH { - auth_path[i].as_mut().map(|p| p.1 = (tmp & 1) == 1); - - tmp >>= 1; - } - - // The witness should be empty now; if it wasn't, the caller would - // have provided more information than they should have, indicating - // a bug downstream - assert_eq!(witness.len(), 0); - - Ok(CommitmentTreeWitness { - auth_path, - position, - }) - } -} - /// A context object for creating the Sapling components of a Zcash transaction. pub struct SaplingProvingContext { bsk: Fs,