use std::marker::PhantomData;
use anyhow::{Context, anyhow};
use blake2::digest::{Digest, FixedOutput};
use serde::{Deserialize, Serialize};
use crate::StmResult;
#[cfg(feature = "future_snark")]
#[allow(dead_code)]
use super::MerklePath;
use super::{MerkleBatchPath, MerkleTreeError, MerkleTreeLeaf, parent, sibling};
#[cfg(feature = "future_snark")]
#[allow(dead_code)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MerkleTreeCommitment<D: Digest, L: MerkleTreeLeaf> {
pub root: Vec<u8>,
hasher: PhantomData<D>,
#[serde(skip)]
leaf_type: PhantomData<L>,
}
#[cfg(feature = "future_snark")]
#[allow(dead_code)]
impl<D: Digest + FixedOutput, L: MerkleTreeLeaf> MerkleTreeCommitment<D, L> {
pub(crate) fn new(root: Vec<u8>) -> Self {
MerkleTreeCommitment {
root,
hasher: PhantomData,
leaf_type: PhantomData,
}
}
pub(crate) fn verify_leaf_membership_from_path(
&self,
val: &L,
proof: &MerklePath<D>,
) -> StmResult<()>
where
D: FixedOutput + Clone,
L: MerkleTreeLeaf,
{
let mut idx = proof.index;
let mut h = D::digest(val.as_bytes_for_merkle_tree()).to_vec();
for p in &proof.values {
if (idx & 0b1) == 0 {
h = D::new().chain_update(h).chain_update(p).finalize().to_vec();
} else {
h = D::new().chain_update(p).chain_update(h).finalize().to_vec();
}
idx >>= 1;
}
if h == self.root {
return Ok(());
}
Err(anyhow!(MerkleTreeError::PathInvalid(proof.to_bytes())))
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut output = Vec::new();
output.extend_from_slice(&self.root);
output
}
pub fn from_bytes(bytes: &[u8]) -> StmResult<MerkleTreeCommitment<D, L>> {
let root = bytes.to_vec();
Ok(Self {
root,
hasher: PhantomData,
leaf_type: PhantomData,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MerkleTreeBatchCommitment<D: Digest, L: MerkleTreeLeaf> {
pub root: Vec<u8>,
nr_leaves: usize,
hasher: PhantomData<D>,
#[serde(skip)]
leaf_type: PhantomData<L>,
}
impl<D: Digest + FixedOutput, L: MerkleTreeLeaf> MerkleTreeBatchCommitment<D, L> {
pub(crate) fn new(root: Vec<u8>, nr_leaves: usize) -> Self {
Self {
root,
nr_leaves,
hasher: Default::default(),
leaf_type: PhantomData,
}
}
#[cfg(feature = "future_snark")]
#[allow(dead_code)]
pub(crate) fn get_number_of_leaves(&self) -> usize {
self.nr_leaves
}
pub(crate) fn concatenate_with_message(&self, msg: &[u8]) -> Vec<u8> {
let mut msgp = msg.to_vec();
let mut bytes = self.root.clone();
msgp.append(&mut bytes);
msgp
}
pub(crate) fn verify_leaves_membership_from_batch_path(
&self,
batch_val: &[L],
proof: &MerkleBatchPath<D>,
) -> StmResult<()>
where
D: FixedOutput + Clone,
L: MerkleTreeLeaf,
{
if batch_val.len() != proof.indices.len() {
return Err(anyhow!(MerkleTreeError::BatchPathInvalid(proof.to_bytes())));
}
let mut ordered_indices: Vec<usize> = proof.indices.clone();
ordered_indices.sort_unstable();
if ordered_indices != proof.indices {
return Err(anyhow!(MerkleTreeError::BatchPathInvalid(proof.to_bytes())));
}
let nr_nodes = self.nr_leaves + self.nr_leaves.next_power_of_two() - 1;
ordered_indices = ordered_indices
.into_iter()
.map(|i| i + self.nr_leaves.next_power_of_two() - 1)
.collect();
let mut idx = ordered_indices[0];
let mut leaves: Vec<Vec<u8>> = batch_val
.iter()
.map(|val| D::digest(val.as_bytes_for_merkle_tree()).to_vec())
.collect();
let mut values = proof.values.clone();
while idx > 0 {
let mut new_hashes = Vec::with_capacity(ordered_indices.len());
let mut new_indices = Vec::with_capacity(ordered_indices.len());
let mut i = 0;
idx = parent(idx);
while i < ordered_indices.len() {
new_indices.push(parent(ordered_indices[i]));
if ordered_indices[i] & 1 == 0 {
new_hashes.push(
D::new()
.chain(
values
.first()
.ok_or(MerkleTreeError::SerializationError)
.with_context(|| {
format!("Could not verify leave membership from batch path for idx = {} and ordered_indices[{}]", idx, i)
})?,
)
.chain(&leaves[i])
.finalize()
.to_vec(),
);
values.remove(0);
} else {
let sibling = sibling(ordered_indices[i]);
if i < ordered_indices.len() - 1 && ordered_indices[i + 1] == sibling {
new_hashes.push(
D::new().chain(&leaves[i]).chain(&leaves[i + 1]).finalize().to_vec(),
);
i += 1;
} else if sibling < nr_nodes {
new_hashes.push(
D::new()
.chain(&leaves[i])
.chain(
values
.first()
.ok_or(MerkleTreeError::SerializationError)
.with_context(|| {
format!(
"Could not verify leave membership from batch path for idx = {} where sibling < nr_nodes", idx
)
})?,
)
.finalize()
.to_vec(),
);
values.remove(0);
} else {
new_hashes.push(
D::new().chain(&leaves[i]).chain(D::digest([0u8])).finalize().to_vec(),
);
}
}
i += 1;
}
leaves.clone_from(&new_hashes);
ordered_indices.clone_from(&new_indices);
}
if leaves.len() == 1 && leaves[0] == self.root {
return Ok(());
}
Err(anyhow!(MerkleTreeError::BatchPathInvalid(proof.to_bytes())))
}
#[cfg(feature = "future_snark")]
#[allow(dead_code)]
pub fn to_bytes(&self) -> Vec<u8> {
let mut output = Vec::new();
output.extend_from_slice(&u64::try_from(self.nr_leaves).unwrap().to_be_bytes());
output.extend_from_slice(&self.root);
output
}
#[cfg(feature = "future_snark")]
#[allow(dead_code)]
pub fn from_bytes(bytes: &[u8]) -> StmResult<MerkleTreeBatchCommitment<D, L>> {
let mut u64_bytes = [0u8; 8];
u64_bytes.copy_from_slice(bytes.get(..8).ok_or(MerkleTreeError::SerializationError)?);
let nr_leaves = usize::try_from(u64::from_be_bytes(u64_bytes))
.map_err(|_| MerkleTreeError::SerializationError)?;
let mut root = Vec::new();
root.extend_from_slice(bytes.get(8..).ok_or(MerkleTreeError::SerializationError)?);
Ok(MerkleTreeBatchCommitment {
root,
nr_leaves,
hasher: PhantomData,
leaf_type: Default::default(),
})
}
}
impl<D: Digest, L: MerkleTreeLeaf> PartialEq for MerkleTreeBatchCommitment<D, L> {
fn eq(&self, other: &Self) -> bool {
self.root == other.root && self.nr_leaves == other.nr_leaves
}
}
impl<D: Digest, L: MerkleTreeLeaf> Eq for MerkleTreeBatchCommitment<D, L> {}