|
|
@@ -1,8 +1,34 @@
|
|
|
use core::str::FromStr;
|
|
|
-use std::io;
|
|
|
+use std::{io, iter};
|
|
|
|
|
|
use darkfi_serial::{SerialDecodable, SerialEncodable};
|
|
|
-use pasta_curves::{group::ff::PrimeField, pallas};
|
|
|
+use halo2_gadgets::sinsemilla::primitives::HashDomain;
|
|
|
+use incrementalmerkletree::{Altitude, Hashable};
|
|
|
+use lazy_static::lazy_static;
|
|
|
+use pasta_curves::{
|
|
|
+ group::ff::{PrimeField, PrimeFieldBits},
|
|
|
+ pallas,
|
|
|
+};
|
|
|
+use subtle::{Choice, ConditionallySelectable};
|
|
|
+
|
|
|
+use crate::crypto::constants::{
|
|
|
+ sinsemilla::{i2lebsp_k, L_ORCHARD_MERKLE, MERKLE_CRH_PERSONALIZATION},
|
|
|
+ MERKLE_DEPTH_ORCHARD,
|
|
|
+};
|
|
|
+
|
|
|
+lazy_static! {
|
|
|
+ static ref UNCOMMITTED_ORCHARD: pallas::Base = pallas::Base::from(2);
|
|
|
+ static ref EMPTY_ROOTS: Vec<MerkleNode> = {
|
|
|
+ iter::empty()
|
|
|
+ .chain(Some(MerkleNode::empty_leaf()))
|
|
|
+ .chain((0..MERKLE_DEPTH_ORCHARD).scan(MerkleNode::empty_leaf(), |state, l| {
|
|
|
+ let l = l as u8;
|
|
|
+ *state = MerkleNode::combine(l.into(), state, state);
|
|
|
+ Some(*state)
|
|
|
+ }))
|
|
|
+ .collect()
|
|
|
+ };
|
|
|
+}
|
|
|
|
|
|
/// The `MerkleNode` is represented as a base field element.
|
|
|
#[repr(C)]
|
|
|
@@ -58,3 +84,46 @@ impl FromStr for MerkleNode {
|
|
|
Err(io::Error::new(io::ErrorKind::Other, "Invalid bytes for MerkleNode"))
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+impl ConditionallySelectable for MerkleNode {
|
|
|
+ fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
|
|
+ Self(pallas::Base::conditional_select(&a.0, &b.0, choice))
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl Hashable for MerkleNode {
|
|
|
+ fn empty_leaf() -> Self {
|
|
|
+ Self(*UNCOMMITTED_ORCHARD)
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Implements `MerkleCRH^Orchard` as defined in
|
|
|
+ /// <https://zips.z.cash/protocol/protocol.pdf#orchardmerklecrh>
|
|
|
+ ///
|
|
|
+ /// The layer with 2^n nodes is called "layer n":
|
|
|
+ /// - leaves are at layer MERKLE_DEPTH_ORCHARD = 32;
|
|
|
+ /// - the root is at layer 0.
|
|
|
+ /// `l` is MERKLE_DEPTH_ORCHARD - layer - 1.
|
|
|
+ /// - when hashing two leaves, we produce a node on the layer
|
|
|
+ /// above the the leaves, i.e. layer = 31, l = 0
|
|
|
+ /// - when hashing to the final root, we produce the anchor
|
|
|
+ /// with layer = 0, l = 31.
|
|
|
+ fn combine(altitude: Altitude, left: &Self, right: &Self) -> Self {
|
|
|
+ // MerkleCRH Sinsemilla hash domain.
|
|
|
+ let domain = HashDomain::new(MERKLE_CRH_PERSONALIZATION);
|
|
|
+
|
|
|
+ Self(
|
|
|
+ domain
|
|
|
+ .hash(
|
|
|
+ iter::empty()
|
|
|
+ .chain(i2lebsp_k(altitude.into()).iter().copied())
|
|
|
+ .chain(left.inner().to_le_bits().iter().by_vals().take(L_ORCHARD_MERKLE))
|
|
|
+ .chain(right.inner().to_le_bits().iter().by_vals().take(L_ORCHARD_MERKLE)),
|
|
|
+ )
|
|
|
+ .unwrap_or(pallas::Base::zero()),
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ fn empty_root(altitude: Altitude) -> Self {
|
|
|
+ EMPTY_ROOTS[<usize>::from(altitude)]
|
|
|
+ }
|
|
|
+}
|