Просмотр исходного кода

Merge branch 'master' of github.com:darkrenaissance/darkfi

lunar-mining 4 лет назад
Родитель
Сommit
f62304565f
1 измененных файлов с 103 добавлено и 0 удалено
  1. 103 0
      src/crypto/merkle_node2.rs

+ 103 - 0
src/crypto/merkle_node2.rs

@@ -0,0 +1,103 @@
+use halo2_gadgets::primitives::sinsemilla::HashDomain;
+use halo2_gadgets::utilities::Var;
+use incrementalmerkletree::Altitude;
+use incrementalmerkletree::Hashable;
+use lazy_static::lazy_static;
+use pasta_curves::{
+    arithmetic::{Field, FieldExt},
+    group::ff::PrimeFieldBits,
+    pallas,
+};
+use std::io;
+use std::iter;
+use subtle::ConstantTimeEq;
+
+use crate::{
+    crypto::constants::{
+        sinsemilla::{i2lebsp_k, MERKLE_CRH_PERSONALIZATION},
+        L_ORCHARD_MERKLE, MERKLE_DEPTH_ORCHARD,
+    },
+    error::Result,
+    serial::{Decodable, Encodable},
+};
+
+lazy_static! {
+    static ref UNCOMMITTED_ORCHARD: pallas::Base = pallas::Base::from_u64(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.clone())
+                }),
+            )
+            .collect()
+    };
+}
+
+#[derive(Debug, Clone, std::cmp::Eq)]
+pub struct MerkleNode(pub pallas::Base);
+
+impl std::cmp::PartialEq for MerkleNode {
+    fn eq(&self, other: &Self) -> bool {
+        self.0.ct_eq(&other.0).into()
+    }
+}
+
+impl std::hash::Hash for MerkleNode {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        <Option<pallas::Base>>::from(self.0)
+            .map(|b| b.to_bytes())
+            .hash(state)
+    }
+}
+
+impl Hashable for MerkleNode {
+    fn empty_leaf() -> Self {
+        MerkleNode(UNCOMMITTED_ORCHARD.clone())
+    }
+
+    /// 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 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);
+
+        MerkleNode(
+            domain
+                .hash(
+                    iter::empty()
+                        .chain(i2lebsp_k(altitude.into()).iter().copied())
+                        .chain(left.0.to_le_bits().iter().by_val().take(L_ORCHARD_MERKLE))
+                        .chain(right.0.to_le_bits().iter().by_val().take(L_ORCHARD_MERKLE)),
+                )
+                .unwrap_or(pallas::Base::zero()),
+        )
+    }
+
+    fn empty_root(altitude: Altitude) -> Self {
+        EMPTY_ROOTS[<usize>::from(altitude)].clone()
+    }
+}
+
+impl Encodable for MerkleNode {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        Ok(self.0.encode(&mut s)?)
+    }
+}
+
+impl Decodable for MerkleNode {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        Ok(Self(Decodable::decode(&mut d)?))
+    }
+}