Ver Fonte

crypto: Import new merkle code.

parazyd há 4 anos atrás
pai
commit
6a0000b160
8 ficheiros alterados com 601 adições e 436 exclusões
  1. 9 0
      Cargo.lock
  2. 4 0
      Cargo.toml
  3. 8 22
      src/crypto/coin.rs
  4. 1 2
      src/crypto/constants/sinsemilla.rs
  5. 102 410
      src/crypto/merkle.rs
  6. 455 0
      src/crypto/merkle_old.rs
  7. 5 2
      src/crypto/mod.rs
  8. 17 0
      src/crypto/nullifier.rs

+ 9 - 0
Cargo.lock

@@ -844,6 +844,7 @@ dependencies = [
  "halo2",
  "halo2_gadgets",
  "hex",
+ "incrementalmerkletree",
  "lazy_static",
  "log",
  "native-tls",
@@ -1450,6 +1451,14 @@ dependencies = [
  "png",
 ]
 
+[[package]]
+name = "incrementalmerkletree"
+version = "0.1.0"
+source = "git+https://github.com/zcash/incrementalmerkletree.git?rev=b7bd6246122a6e9ace8edb51553fbf5228906cbb#b7bd6246122a6e9ace8edb51553fbf5228906cbb"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "instant"
 version = "0.1.12"

+ 4 - 0
Cargo.toml

@@ -20,6 +20,10 @@ git = "https://github.com/parazyd/halo2_gadgets.git"
 rev = "8238cb3471b798c76dd53b278524fc80685c7d4f"
 features = ["dev-graph", "test-dependencies"]
 
+[dependencies.incrementalmerkletree]
+git = "https://github.com/zcash/incrementalmerkletree.git"
+rev = "b7bd6246122a6e9ace8edb51553fbf5228906cbb"
+
 [dependencies.rocksdb]
 git = "https://github.com/parazyd/rust-rocksdb"
 rev = "bd966750ec861d687913d59a9939a1408ac53131"

+ 8 - 22
src/crypto/coin.rs

@@ -1,31 +1,17 @@
-use std::io;
+use pasta_curves::{arithmetic::FieldExt, pallas};
 
-use crate::{
-    serial::{Decodable, Encodable},
-    Result,
-};
-
-#[derive(Clone, Debug, PartialEq)]
-pub struct Coin {
-    pub repr: [u8; 32],
-}
+pub struct Coin(pallas::Base);
 
 impl Coin {
-    pub fn new(repr: [u8; 32]) -> Self {
-        Self { repr }
+    pub fn from_bytes(bytes: &[u8; 32]) -> Self {
+        pallas::Base::from_bytes(bytes).map(Coin).unwrap()
     }
-}
 
-impl Encodable for Coin {
-    fn encode<S: io::Write>(&self, s: S) -> Result<usize> {
-        self.repr.encode(s)
+    pub fn to_bytes(self) -> [u8; 32] {
+        self.0.to_bytes()
     }
-}
 
-impl Decodable for Coin {
-    fn decode<D: io::Read>(d: D) -> Result<Self> {
-        Ok(Self {
-            repr: Decodable::decode(d)?,
-        })
+    pub(crate) fn inner(&self) -> pallas::Base {
+        self.0
     }
 }

+ 1 - 2
src/crypto/constants/sinsemilla.rs

@@ -86,8 +86,7 @@ fn lebs2ip_k(bits: &[bool]) -> u32 {
 
 /// The sequence of K bits in little-endian order representing an integer
 /// up to `2^K` - 1.
-#[allow(dead_code)]
-fn i2lebsp_k(int: usize) -> [bool; K] {
+pub(crate) fn i2lebsp_k(int: usize) -> [bool; K] {
     assert!(int < (1 << K));
     i2lebsp(int as u64)
 }

+ 102 - 410
src/crypto/merkle.rs

@@ -1,455 +1,147 @@
-//! Implementation of a Merkle tree of commitments used to prove the existence
-//! of notes.
-
-//use byteorder::{LittleEndian, ReadBytesExt};
-use crate::serial::{Decodable, Encodable, VarInt};
-use crate::{Error, Result};
-use std::collections::VecDeque;
-use std::io;
-use std::io::{Read, Write};
-
-//use super::serialize::{Optional, Vector};
-use super::merkle_node::SAPLING_COMMITMENT_TREE_DEPTH;
-
-/// A hashable node within a Merkle tree.
-pub trait Hashable: Clone + Copy + Encodable + Decodable {
-    /// Parses a node from the given byte source.
-    fn read<R: Read>(reader: R) -> Result<Self>;
-
-    /// Serializes this node.
-    fn write<W: Write>(&self, writer: W) -> Result<()>;
-
-    /// 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;
+use std::iter;
+
+use halo2_gadgets::primitives::sinsemilla::HashDomain;
+use incrementalmerkletree::{Altitude, Hashable};
+use lazy_static::lazy_static;
+use pasta_curves::{
+    arithmetic::FieldExt,
+    group::ff::{PrimeField, PrimeFieldBits},
+    pallas,
+};
+
+use super::{
+    coin::Coin,
+    constants::{
+        sinsemilla::{i2lebsp_k, MERKLE_CRH_PERSONALIZATION},
+        util::gen_const_array_with_default,
+    },
+};
+
+// TODO: to constants
+const MERKLE_DEPTH_ORCHARD: usize = 32;
+
+lazy_static! {
+    static ref UNCOMMITTED_ORCHARD: pallas::Base = pallas::Base::from_u64(2);
+    pub(crate) static ref EMPTY_ROOTS: Vec<MerkleHash> = {
+        iter::empty()
+            .chain(Some(MerkleHash::empty_leaf()))
+            .chain(
+                (0..MERKLE_DEPTH_ORCHARD).scan(MerkleHash::empty_leaf(), |state, l| {
+                    let l = l as u8;
+                    *state = MerkleHash::combine(l.into(), state, state);
+                    Some(*state)
+                }),
+            )
+            .collect()
+    };
 }
 
-struct PathFiller<Node: Hashable> {
-    queue: VecDeque<Node>,
-}
+#[derive(Copy, Clone, Debug)]
+pub struct MerkleHash(pallas::Base);
 
-impl<Node: Hashable> PathFiller<Node> {
-    fn empty() -> Self {
-        PathFiller {
-            queue: VecDeque::new(),
-        }
+impl MerkleHash {
+    pub fn from_coin(value: &Coin) -> Self {
+        MerkleHash(value.inner())
     }
 
-    fn next(&mut self, depth: usize) -> Node {
-        self.queue
-            .pop_front()
-            .unwrap_or_else(|| Node::empty_root(depth))
+    pub(crate) fn inner(&self) -> pallas::Base {
+        self.0
     }
-}
 
-/// A Merkle tree of note commitments.
-///
-/// The depth of the Merkle tree is fixed at 32, equal to the depth of the
-/// Sapling commitment tree.
-#[derive(Clone)]
-pub struct CommitmentTree<Node: Hashable> {
-    left: Option<Node>,
-    right: Option<Node>,
-    parents: Vec<Option<Node>>,
-}
-
-impl<Node: Hashable> CommitmentTree<Node> {
-    /// Creates an empty tree.
-    pub fn empty() -> Self {
-        CommitmentTree {
-            left: None,
-            right: None,
-            parents: vec![],
-        }
-    }
-
-    /// Returns the number of leaf nodes in the tree.
-    pub fn size(&self) -> usize {
-        self.parents.iter().enumerate().fold(
-            match (self.left, self.right) {
-                (None, None) => 0,
-                (Some(_), None) => 1,
-                (Some(_), Some(_)) => 2,
-                (None, Some(_)) => unreachable!(),
-            },
-            |acc, (i, p)| {
-                // Treat occupation of parents array as a binary number
-                // (right-shifted by 1)
-                acc + if p.is_some() { 1 << (i + 1) } else { 0 }
-            },
-        )
+    pub fn to_bytes(&self) -> [u8; 32] {
+        self.0.to_bytes()
     }
 
-    fn is_complete(&self, depth: usize) -> bool {
-        self.left.is_some()
-            && self.right.is_some()
-            && self.parents.len() == depth - 1
-            && self.parents.iter().all(|p| p.is_some())
+    pub fn from_bytes(bytes: &[u8; 32]) -> Self {
+        pallas::Base::from_bytes(bytes).map(MerkleHash).unwrap()
     }
+}
 
-    /// Adds a leaf node to the tree.
-    ///
-    /// Returns an error if the tree is full.
-    pub fn append(&mut self, node: Node) -> Result<()> {
-        self.append_inner(node, SAPLING_COMMITMENT_TREE_DEPTH)
+impl Hashable for MerkleHash {
+    fn empty_leaf() -> Self {
+        MerkleHash(*UNCOMMITTED_ORCHARD)
     }
 
-    fn append_inner(&mut self, node: Node, depth: usize) -> Result<()> {
-        if self.is_complete(depth) {
-            return Err(Error::TreeFull);
-        }
-
-        match (self.left, self.right) {
-            (None, _) => self.left = Some(node),
-            (_, None) => self.right = Some(node),
-            (Some(l), Some(r)) => {
-                let mut combined = Node::combine(0, &l, &r);
-                self.left = Some(node);
-                self.right = None;
-
-                for i in 0..depth {
-                    if i < self.parents.len() {
-                        if let Some(p) = self.parents[i] {
-                            combined = Node::combine(i + 1, &p, &combined);
-                            self.parents[i] = None;
-                        } else {
-                            self.parents[i] = Some(combined);
-                            break;
-                        }
-                    } else {
-                        self.parents.push(Some(combined));
-                        break;
-                    }
-                }
-            }
-        }
+    fn combine(altitude: Altitude, left: &Self, right: &Self) -> Self {
+        let domain = HashDomain::new(MERKLE_CRH_PERSONALIZATION);
 
-        Ok(())
+        MerkleHash(
+            domain
+                .hash(
+                    iter::empty()
+                        .chain(i2lebsp_k(altitude.into()).iter().copied())
+                        .chain(left.0.to_le_bits().iter().by_val().take(255))
+                        .chain(right.0.to_le_bits().iter().by_val().take(255)),
+                )
+                .unwrap_or(pallas::Base::zero()),
+        )
     }
 
-    /// Returns the current root of the tree.
-    pub fn root(&self) -> Node {
-        self.root_inner(SAPLING_COMMITMENT_TREE_DEPTH, PathFiller::empty())
-    }
-
-    fn root_inner(&self, depth: usize, mut filler: PathFiller<Node>) -> Node {
-        assert!(depth > 0);
-
-        // 1) Hash left and right leaves together.
-        //    - Empty leaves are used as needed.
-        let leaf_root = Node::combine(
-            0,
-            &self.left.unwrap_or_else(|| filler.next(0)),
-            &self.right.unwrap_or_else(|| filler.next(0)),
-        );
-
-        // 2) Hash in parents up to the currently-filled depth.
-        //    - Roots of the empty subtrees are used as needed.
-        let mid_root = self
-            .parents
-            .iter()
-            .enumerate()
-            .fold(leaf_root, |root, (i, p)| match p {
-                Some(node) => Node::combine(i + 1, node, &root),
-                None => Node::combine(i + 1, &root, &filler.next(i + 1)),
-            });
-
-        // 3) Hash in roots of the empty subtrees up to the final depth.
-        ((self.parents.len() + 1)..depth)
-            .fold(mid_root, |root, d| Node::combine(d, &root, &filler.next(d)))
+    fn empty_root(altitude: Altitude) -> Self {
+        EMPTY_ROOTS[<usize>::from(altitude)]
     }
 }
 
-impl<Node: Hashable> Encodable for CommitmentTree<Node> {
-    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        let mut len = 0;
-        len += self.left.encode(&mut s)?;
-        len += self.right.encode(&mut s)?;
-        len += self.parents.encode(&mut s)?;
-        Ok(len)
-    }
-}
+pub struct Anchor(pallas::Base);
 
-impl<Node: Hashable> Decodable for CommitmentTree<Node> {
-    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
-        Ok(Self {
-            left: Decodable::decode(&mut d)?,
-            right: Decodable::decode(&mut d)?,
-            parents: Decodable::decode(&mut d)?,
-        })
+impl From<pallas::Base> for Anchor {
+    fn from(anchor_field: pallas::Base) -> Anchor {
+        Anchor(anchor_field)
     }
 }
 
-/*
-/// An updatable witness to a path from a position in a particular
-/// [`CommitmentTree`].
-///
-/// Appending the same commitments in the same order to both the original
-/// [`CommitmentTree`] and this `IncrementalWitness` will result in a witness to
-/// the path from the target position to the root of the updated tree.
-///
-/// # Examples
-///
-/// ```
-/// use ff::{Field, PrimeField};
-/// use rand_core::OsRng;
-/// use zcash_primitives::{
-///     merkle_tree::{CommitmentTree, IncrementalWitness},
-///     sapling::Node,
-/// };
-///
-/// let mut rng = OsRng;
-///
-/// let mut tree = CommitmentTree::<Node>::empty();
-///
-/// tree.append(Node::new(bls12_381::Scalar::random(&mut rng).to_repr()));
-/// tree.append(Node::new(bls12_381::Scalar::random(&mut rng).to_repr()));
-/// let mut witness = IncrementalWitness::from_tree(&tree);
-/// assert_eq!(witness.position(), 1);
-/// assert_eq!(tree.root(), witness.root());
-///
-/// let cmu = Node::new(bls12_381::Scalar::random(&mut rng).to_repr());
-/// tree.append(cmu);
-/// witness.append(cmu);
-/// assert_eq!(tree.root(), witness.root());
-/// ```
-///
-*/
-
-#[derive(Clone)]
-pub struct IncrementalWitness<Node: Hashable> {
-    tree: CommitmentTree<Node>,
-    filled: Vec<Node>,
-    cursor_depth: usize,
-    cursor: Option<CommitmentTree<Node>>,
-}
-
-impl<Node: Hashable> Encodable for Vec<Node> {
-    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        let mut len = 0;
-        len += VarInt(self.len() as u64).encode(&mut s)?;
-        for c in self.iter() {
-            len += c.encode(&mut s)?;
-        }
-        Ok(len)
+impl From<MerkleHash> for Anchor {
+    fn from(anchor: MerkleHash) -> Anchor {
+        Anchor(anchor.0)
     }
 }
 
-impl<Node: Hashable> Decodable for Vec<Node> {
-    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
-        let len = VarInt::decode(&mut d)?.0;
-        let mut ret = Vec::with_capacity(len as usize);
-        for _ in 0..len {
-            ret.push(Decodable::decode(&mut d)?);
-        }
-        Ok(ret)
+impl Anchor {
+    pub fn from_bytes(bytes: [u8; 32]) -> Anchor {
+        pallas::Base::from_repr(bytes).map(Anchor).unwrap()
     }
-}
-
-impl<Node: Hashable> Encodable for IncrementalWitness<Node> {
-    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        let mut len = 0;
-        len += self.tree.encode(&mut s)?;
 
-        len += self.filled.encode(&mut s)?;
-
-        len += self.cursor_depth.encode(&mut s)?;
-        len += self.cursor.encode(&mut s)?;
-        Ok(len)
+    pub fn to_bytes(self) -> [u8; 32] {
+        self.0.to_repr()
     }
 }
 
-impl<Node: Hashable> Decodable for IncrementalWitness<Node> {
-    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
-        Ok(Self {
-            tree: Decodable::decode(&mut d)?,
-            filled: Decodable::decode(&mut d)?,
-            cursor_depth: Decodable::decode(&mut d)?,
-            cursor: Decodable::decode(d)?,
-        })
-    }
+#[derive(Debug)]
+pub struct MerklePath {
+    position: u32,
+    auth_path: [MerkleHash; MERKLE_DEPTH_ORCHARD],
 }
 
-impl<Node: Hashable> IncrementalWitness<Node> {
-    /// Creates an `IncrementalWitness` for the most recent commitment added to
-    /// the given [`CommitmentTree`].
-    pub fn from_tree(tree: &CommitmentTree<Node>) -> IncrementalWitness<Node> {
-        IncrementalWitness {
-            tree: tree.clone(),
-            filled: vec![],
-            cursor_depth: 0,
-            cursor: None,
-        }
-    }
-
-    /// Returns the position of the witnessed leaf node in the commitment tree.
-    pub fn position(&self) -> usize {
-        self.tree.size() - 1
-    }
-
-    fn filler(&self) -> PathFiller<Node> {
-        let cursor_root = self
-            .cursor
-            .as_ref()
-            .map(|c| c.root_inner(self.cursor_depth, PathFiller::empty()));
-
-        PathFiller {
-            queue: self.filled.iter().cloned().chain(cursor_root).collect(),
+impl MerklePath {
+    pub fn new(position: u32, auth_path: [pallas::Base; MERKLE_DEPTH_ORCHARD]) -> Self {
+        Self {
+            position,
+            auth_path: gen_const_array_with_default(MerkleHash::empty_leaf(), |i| {
+                MerkleHash(auth_path[i])
+            }),
         }
     }
 
-    /// Finds the next "depth" of an unfilled subtree.
-    fn next_depth(&self) -> usize {
-        let mut skip = self.filled.len();
-
-        if self.tree.left.is_none() {
-            if skip > 0 {
-                skip -= 1;
-            } else {
-                return 0;
-            }
-        }
-
-        if self.tree.right.is_none() {
-            if skip > 0 {
-                skip -= 1;
-            } else {
-                return 0;
-            }
-        }
-
-        let mut d = 1;
-        for p in &self.tree.parents {
-            if p.is_none() {
-                if skip > 0 {
-                    skip -= 1;
+    pub fn root(&self, coin: Coin) -> Anchor {
+        self.auth_path
+            .iter()
+            .enumerate()
+            .fold(MerkleHash::from_coin(&coin), |node, (l, sibling)| {
+                let l = l as u8;
+                if self.position & (1 << l) == 0 {
+                    MerkleHash::combine(l.into(), &node, sibling)
                 } else {
-                    return d;
+                    MerkleHash::combine(l.into(), sibling, &node)
                 }
-            }
-            d += 1;
-        }
-
-        d + skip
-    }
-
-    /// Tracks a leaf node that has been added to the underlying tree.
-    ///
-    /// Returns an error if the tree is full.
-    pub fn append(&mut self, node: Node) -> Result<()> {
-        self.append_inner(node, SAPLING_COMMITMENT_TREE_DEPTH)
-    }
-
-    fn append_inner(&mut self, node: Node, depth: usize) -> Result<()> {
-        if let Some(mut cursor) = self.cursor.take() {
-            cursor
-                .append_inner(node, depth)
-                .expect("cursor should not be full");
-            if cursor.is_complete(self.cursor_depth) {
-                self.filled
-                    .push(cursor.root_inner(self.cursor_depth, PathFiller::empty()));
-            } else {
-                self.cursor = Some(cursor);
-            }
-        } else {
-            self.cursor_depth = self.next_depth();
-            if self.cursor_depth >= depth {
-                return Err(Error::TreeFull);
-            }
-
-            if self.cursor_depth == 0 {
-                self.filled.push(node);
-            } else {
-                let mut cursor = CommitmentTree::empty();
-                cursor
-                    .append_inner(node, depth)
-                    .expect("cursor should not be full");
-                self.cursor = Some(cursor);
-            }
-        }
-
-        Ok(())
-    }
-
-    /// Returns the current root of the tree corresponding to the witness.
-    pub fn root(&self) -> Node {
-        self.root_inner(SAPLING_COMMITMENT_TREE_DEPTH)
-    }
-
-    fn root_inner(&self, depth: usize) -> Node {
-        self.tree.root_inner(depth, self.filler())
-    }
-
-    /// Returns the current witness, or None if the tree is empty.
-    pub fn path(&self) -> Option<MerklePath<Node>> {
-        self.path_inner(SAPLING_COMMITMENT_TREE_DEPTH)
-    }
-
-    fn path_inner(&self, depth: usize) -> Option<MerklePath<Node>> {
-        let mut filler = self.filler();
-        let mut auth_path = Vec::new();
-
-        if let Some(node) = self.tree.left {
-            if self.tree.right.is_some() {
-                auth_path.push((node, true));
-            } else {
-                auth_path.push((filler.next(0), false));
-            }
-        } else {
-            // Can't create an authentication path for the beginning of the tree
-            return None;
-        }
-
-        for (i, p) in self.tree.parents.iter().enumerate() {
-            auth_path.push(match p {
-                Some(node) => (*node, true),
-                None => (filler.next(i + 1), false),
-            });
-        }
-
-        for i in self.tree.parents.len()..(depth - 1) {
-            auth_path.push((filler.next(i + 1), false));
-        }
-        assert_eq!(auth_path.len(), depth);
-
-        Some(MerklePath::from_path(auth_path, self.position() as u64))
+            })
+            .into()
     }
-}
-
-/// A path from a position in a particular commitment tree to the root of that
-/// tree.
-#[derive(Clone, Debug, PartialEq)]
-pub struct MerklePath<Node: Hashable> {
-    pub auth_path: Vec<(Node, bool)>,
-    pub position: u64,
-}
 
-impl<Node: Hashable> MerklePath<Node> {
-    /// Constructs a Merkle path directly from a path and position.
-    pub fn from_path(auth_path: Vec<(Node, bool)>, position: u64) -> Self {
-        MerklePath {
-            auth_path,
-            position,
-        }
+    pub fn position(&self) -> u32 {
+        self.position
     }
 
-    /// Returns the root of the tree corresponding to this path applied to
-    /// `leaf`.
-    pub fn root(&self, leaf: Node) -> Node {
+    pub fn auth_path(&self) -> [MerkleHash; MERKLE_DEPTH_ORCHARD] {
         self.auth_path
-            .iter()
-            .enumerate()
-            .fold(
-                leaf,
-                |root, (i, (p, leaf_is_on_right))| match leaf_is_on_right {
-                    false => Node::combine(i, &root, p),
-                    true => Node::combine(i, p, &root),
-                },
-            )
     }
 }

+ 455 - 0
src/crypto/merkle_old.rs

@@ -0,0 +1,455 @@
+//! Implementation of a Merkle tree of commitments used to prove the existence
+//! of notes.
+
+/*
+//use byteorder::{LittleEndian, ReadBytesExt};
+use crate::serial::{Decodable, Encodable, VarInt};
+use crate::{Error, Result};
+use std::collections::VecDeque;
+use std::io;
+use std::io::{Read, Write};
+
+//use super::serialize::{Optional, Vector};
+use super::merkle_node::SAPLING_COMMITMENT_TREE_DEPTH;
+
+/// A hashable node within a Merkle tree.
+pub trait Hashable: Clone + Copy + Encodable + Decodable {
+    /// Parses a node from the given byte source.
+    fn read<R: Read>(reader: R) -> Result<Self>;
+
+    /// Serializes this node.
+    fn write<W: Write>(&self, writer: W) -> Result<()>;
+
+    /// 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;
+}
+
+struct PathFiller<Node: Hashable> {
+    queue: VecDeque<Node>,
+}
+
+impl<Node: Hashable> PathFiller<Node> {
+    fn empty() -> Self {
+        PathFiller {
+            queue: VecDeque::new(),
+        }
+    }
+
+    fn next(&mut self, depth: usize) -> Node {
+        self.queue
+            .pop_front()
+            .unwrap_or_else(|| Node::empty_root(depth))
+    }
+}
+
+/// A Merkle tree of note commitments.
+///
+/// The depth of the Merkle tree is fixed at 32, equal to the depth of the
+/// Sapling commitment tree.
+#[derive(Clone)]
+pub struct CommitmentTree<Node: Hashable> {
+    left: Option<Node>,
+    right: Option<Node>,
+    parents: Vec<Option<Node>>,
+}
+
+impl<Node: Hashable> CommitmentTree<Node> {
+    /// Creates an empty tree.
+    pub fn empty() -> Self {
+        CommitmentTree {
+            left: None,
+            right: None,
+            parents: vec![],
+        }
+    }
+
+    /// Returns the number of leaf nodes in the tree.
+    pub fn size(&self) -> usize {
+        self.parents.iter().enumerate().fold(
+            match (self.left, self.right) {
+                (None, None) => 0,
+                (Some(_), None) => 1,
+                (Some(_), Some(_)) => 2,
+                (None, Some(_)) => unreachable!(),
+            },
+            |acc, (i, p)| {
+                // Treat occupation of parents array as a binary number
+                // (right-shifted by 1)
+                acc + if p.is_some() { 1 << (i + 1) } else { 0 }
+            },
+        )
+    }
+
+    fn is_complete(&self, depth: usize) -> bool {
+        self.left.is_some()
+            && self.right.is_some()
+            && self.parents.len() == depth - 1
+            && self.parents.iter().all(|p| p.is_some())
+    }
+
+    /// Adds a leaf node to the tree.
+    ///
+    /// Returns an error if the tree is full.
+    pub fn append(&mut self, node: Node) -> Result<()> {
+        self.append_inner(node, SAPLING_COMMITMENT_TREE_DEPTH)
+    }
+
+    fn append_inner(&mut self, node: Node, depth: usize) -> Result<()> {
+        if self.is_complete(depth) {
+            return Err(Error::TreeFull);
+        }
+
+        match (self.left, self.right) {
+            (None, _) => self.left = Some(node),
+            (_, None) => self.right = Some(node),
+            (Some(l), Some(r)) => {
+                let mut combined = Node::combine(0, &l, &r);
+                self.left = Some(node);
+                self.right = None;
+
+                for i in 0..depth {
+                    if i < self.parents.len() {
+                        if let Some(p) = self.parents[i] {
+                            combined = Node::combine(i + 1, &p, &combined);
+                            self.parents[i] = None;
+                        } else {
+                            self.parents[i] = Some(combined);
+                            break;
+                        }
+                    } else {
+                        self.parents.push(Some(combined));
+                        break;
+                    }
+                }
+            }
+        }
+
+        Ok(())
+    }
+
+    /// Returns the current root of the tree.
+    pub fn root(&self) -> Node {
+        self.root_inner(SAPLING_COMMITMENT_TREE_DEPTH, PathFiller::empty())
+    }
+
+    fn root_inner(&self, depth: usize, mut filler: PathFiller<Node>) -> Node {
+        assert!(depth > 0);
+
+        // 1) Hash left and right leaves together.
+        //    - Empty leaves are used as needed.
+        let leaf_root = Node::combine(
+            0,
+            &self.left.unwrap_or_else(|| filler.next(0)),
+            &self.right.unwrap_or_else(|| filler.next(0)),
+        );
+
+        // 2) Hash in parents up to the currently-filled depth.
+        //    - Roots of the empty subtrees are used as needed.
+        let mid_root = self
+            .parents
+            .iter()
+            .enumerate()
+            .fold(leaf_root, |root, (i, p)| match p {
+                Some(node) => Node::combine(i + 1, node, &root),
+                None => Node::combine(i + 1, &root, &filler.next(i + 1)),
+            });
+
+        // 3) Hash in roots of the empty subtrees up to the final depth.
+        ((self.parents.len() + 1)..depth)
+            .fold(mid_root, |root, d| Node::combine(d, &root, &filler.next(d)))
+    }
+}
+
+impl<Node: Hashable> Encodable for CommitmentTree<Node> {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += self.left.encode(&mut s)?;
+        len += self.right.encode(&mut s)?;
+        len += self.parents.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl<Node: Hashable> Decodable for CommitmentTree<Node> {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        Ok(Self {
+            left: Decodable::decode(&mut d)?,
+            right: Decodable::decode(&mut d)?,
+            parents: Decodable::decode(&mut d)?,
+        })
+    }
+}
+
+/// An updatable witness to a path from a position in a particular
+/// [`CommitmentTree`].
+///
+/// Appending the same commitments in the same order to both the original
+/// [`CommitmentTree`] and this `IncrementalWitness` will result in a witness to
+/// the path from the target position to the root of the updated tree.
+///
+/// # Examples
+///
+/// ```
+/// use ff::{Field, PrimeField};
+/// use rand_core::OsRng;
+/// use zcash_primitives::{
+///     merkle_tree::{CommitmentTree, IncrementalWitness},
+///     sapling::Node,
+/// };
+///
+/// let mut rng = OsRng;
+///
+/// let mut tree = CommitmentTree::<Node>::empty();
+///
+/// tree.append(Node::new(bls12_381::Scalar::random(&mut rng).to_repr()));
+/// tree.append(Node::new(bls12_381::Scalar::random(&mut rng).to_repr()));
+/// let mut witness = IncrementalWitness::from_tree(&tree);
+/// assert_eq!(witness.position(), 1);
+/// assert_eq!(tree.root(), witness.root());
+///
+/// let cmu = Node::new(bls12_381::Scalar::random(&mut rng).to_repr());
+/// tree.append(cmu);
+/// witness.append(cmu);
+/// assert_eq!(tree.root(), witness.root());
+/// ```
+///
+
+#[derive(Clone)]
+pub struct IncrementalWitness<Node: Hashable> {
+    tree: CommitmentTree<Node>,
+    filled: Vec<Node>,
+    cursor_depth: usize,
+    cursor: Option<CommitmentTree<Node>>,
+}
+
+impl<Node: Hashable> Encodable for Vec<Node> {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += VarInt(self.len() as u64).encode(&mut s)?;
+        for c in self.iter() {
+            len += c.encode(&mut s)?;
+        }
+        Ok(len)
+    }
+}
+
+impl<Node: Hashable> Decodable for Vec<Node> {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        let len = VarInt::decode(&mut d)?.0;
+        let mut ret = Vec::with_capacity(len as usize);
+        for _ in 0..len {
+            ret.push(Decodable::decode(&mut d)?);
+        }
+        Ok(ret)
+    }
+}
+
+impl<Node: Hashable> Encodable for IncrementalWitness<Node> {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += self.tree.encode(&mut s)?;
+
+        len += self.filled.encode(&mut s)?;
+
+        len += self.cursor_depth.encode(&mut s)?;
+        len += self.cursor.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl<Node: Hashable> Decodable for IncrementalWitness<Node> {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        Ok(Self {
+            tree: Decodable::decode(&mut d)?,
+            filled: Decodable::decode(&mut d)?,
+            cursor_depth: Decodable::decode(&mut d)?,
+            cursor: Decodable::decode(d)?,
+        })
+    }
+}
+
+impl<Node: Hashable> IncrementalWitness<Node> {
+    /// Creates an `IncrementalWitness` for the most recent commitment added to
+    /// the given [`CommitmentTree`].
+    pub fn from_tree(tree: &CommitmentTree<Node>) -> IncrementalWitness<Node> {
+        IncrementalWitness {
+            tree: tree.clone(),
+            filled: vec![],
+            cursor_depth: 0,
+            cursor: None,
+        }
+    }
+
+    /// Returns the position of the witnessed leaf node in the commitment tree.
+    pub fn position(&self) -> usize {
+        self.tree.size() - 1
+    }
+
+    fn filler(&self) -> PathFiller<Node> {
+        let cursor_root = self
+            .cursor
+            .as_ref()
+            .map(|c| c.root_inner(self.cursor_depth, PathFiller::empty()));
+
+        PathFiller {
+            queue: self.filled.iter().cloned().chain(cursor_root).collect(),
+        }
+    }
+
+    /// Finds the next "depth" of an unfilled subtree.
+    fn next_depth(&self) -> usize {
+        let mut skip = self.filled.len();
+
+        if self.tree.left.is_none() {
+            if skip > 0 {
+                skip -= 1;
+            } else {
+                return 0;
+            }
+        }
+
+        if self.tree.right.is_none() {
+            if skip > 0 {
+                skip -= 1;
+            } else {
+                return 0;
+            }
+        }
+
+        let mut d = 1;
+        for p in &self.tree.parents {
+            if p.is_none() {
+                if skip > 0 {
+                    skip -= 1;
+                } else {
+                    return d;
+                }
+            }
+            d += 1;
+        }
+
+        d + skip
+    }
+
+    /// Tracks a leaf node that has been added to the underlying tree.
+    ///
+    /// Returns an error if the tree is full.
+    pub fn append(&mut self, node: Node) -> Result<()> {
+        self.append_inner(node, SAPLING_COMMITMENT_TREE_DEPTH)
+    }
+
+    fn append_inner(&mut self, node: Node, depth: usize) -> Result<()> {
+        if let Some(mut cursor) = self.cursor.take() {
+            cursor
+                .append_inner(node, depth)
+                .expect("cursor should not be full");
+            if cursor.is_complete(self.cursor_depth) {
+                self.filled
+                    .push(cursor.root_inner(self.cursor_depth, PathFiller::empty()));
+            } else {
+                self.cursor = Some(cursor);
+            }
+        } else {
+            self.cursor_depth = self.next_depth();
+            if self.cursor_depth >= depth {
+                return Err(Error::TreeFull);
+            }
+
+            if self.cursor_depth == 0 {
+                self.filled.push(node);
+            } else {
+                let mut cursor = CommitmentTree::empty();
+                cursor
+                    .append_inner(node, depth)
+                    .expect("cursor should not be full");
+                self.cursor = Some(cursor);
+            }
+        }
+
+        Ok(())
+    }
+
+    /// Returns the current root of the tree corresponding to the witness.
+    pub fn root(&self) -> Node {
+        self.root_inner(SAPLING_COMMITMENT_TREE_DEPTH)
+    }
+
+    fn root_inner(&self, depth: usize) -> Node {
+        self.tree.root_inner(depth, self.filler())
+    }
+
+    /// Returns the current witness, or None if the tree is empty.
+    pub fn path(&self) -> Option<MerklePath<Node>> {
+        self.path_inner(SAPLING_COMMITMENT_TREE_DEPTH)
+    }
+
+    fn path_inner(&self, depth: usize) -> Option<MerklePath<Node>> {
+        let mut filler = self.filler();
+        let mut auth_path = Vec::new();
+
+        if let Some(node) = self.tree.left {
+            if self.tree.right.is_some() {
+                auth_path.push((node, true));
+            } else {
+                auth_path.push((filler.next(0), false));
+            }
+        } else {
+            // Can't create an authentication path for the beginning of the tree
+            return None;
+        }
+
+        for (i, p) in self.tree.parents.iter().enumerate() {
+            auth_path.push(match p {
+                Some(node) => (*node, true),
+                None => (filler.next(i + 1), false),
+            });
+        }
+
+        for i in self.tree.parents.len()..(depth - 1) {
+            auth_path.push((filler.next(i + 1), false));
+        }
+        assert_eq!(auth_path.len(), depth);
+
+        Some(MerklePath::from_path(auth_path, self.position() as u64))
+    }
+}
+
+/// A path from a position in a particular commitment tree to the root of that
+/// tree.
+#[derive(Clone, Debug, PartialEq)]
+pub struct MerklePath<Node: Hashable> {
+    pub auth_path: Vec<(Node, bool)>,
+    pub position: u64,
+}
+
+impl<Node: Hashable> MerklePath<Node> {
+    /// Constructs a Merkle path directly from a path and position.
+    pub fn from_path(auth_path: Vec<(Node, bool)>, position: u64) -> Self {
+        MerklePath {
+            auth_path,
+            position,
+        }
+    }
+
+    /// Returns the root of the tree corresponding to this path applied to
+    /// `leaf`.
+    pub fn root(&self, leaf: Node) -> Node {
+        self.auth_path
+            .iter()
+            .enumerate()
+            .fold(
+                leaf,
+                |root, (i, (p, leaf_is_on_right))| match leaf_is_on_right {
+                    false => Node::combine(i, &root, p),
+                    true => Node::combine(i, p, &root),
+                },
+            )
+    }
+}
+*/

+ 5 - 2
src/crypto/mod.rs

@@ -1,15 +1,17 @@
+pub mod coin;
 pub mod constants;
 pub mod diffie_hellman;
-//pub mod merkle;
-//pub mod merkle_node;
+pub mod merkle;
 pub mod mint_proof;
 pub mod note;
+pub mod nullifier;
 pub mod pasta_serial;
 pub mod proof;
 pub mod schnorr;
 pub mod spend_proof;
 pub mod util;
 
+/*
 use crate::types::*;
 
 #[derive(Clone)]
@@ -22,3 +24,4 @@ pub struct OwnCoin {
 }
 
 pub type OwnCoins = Vec<OwnCoin>;
+*/

+ 17 - 0
src/crypto/nullifier.rs

@@ -0,0 +1,17 @@
+use pasta_curves::{arithmetic::FieldExt, pallas};
+
+pub struct Nullifier(pallas::Base);
+
+impl Nullifier {
+    pub fn from_bytes(bytes: &[u8; 32]) -> Self {
+        pallas::Base::from_bytes(bytes).map(Nullifier).unwrap()
+    }
+
+    pub fn to_bytes(self) -> [u8; 32] {
+        self.0.to_bytes()
+    }
+
+    pub(crate) fn inner(&self) -> pallas::Base {
+        self.0
+    }
+}