Move CommitmentTreeWitness into zcash_primitives

This commit is contained in:
Jack Grigg
2018-11-09 00:07:25 +13:00
parent f4059a5faa
commit bf74915053
7 changed files with 83 additions and 78 deletions

View File

@@ -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<Option<(Fr, bool)>>,
pub position: u64,
}
impl CommitmentTreeWitness {
pub fn from_slice(mut witness: &[u8]) -> Result<Self, ()> {
// 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::<LittleEndian>()
.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};