#[allow(clippy::useless_attribute)]
#[allow(clippy::wildcard_imports)]
use std::prelude::v1::*;
use crate::{Commitment, Error, Index, Node, Result};
use itertools::Itertools;
use std::collections::VecDeque;
use zkp_error_utils::require;
use zkp_hash::{Hash, Hashable};
#[derive(Clone)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct Proof {
commitment: Commitment,
indices: Vec<usize>,
hashes: Vec<Hash>,
}
impl Proof {
pub fn from_hashes(
commitment: &Commitment,
indices: &[usize],
hashes: &[Hash],
) -> Result<Self> {
let _ = commitment.sort_indices(indices)?;
require!(
hashes.len() == commitment.proof_size(indices)?,
Error::NotEnoughHashes
);
Ok(Self {
commitment: commitment.clone(),
indices: indices.to_vec(),
hashes: hashes.to_vec(),
})
}
pub fn hashes(&self) -> &[Hash] {
&self.hashes
}
pub fn verify<Leaf: Hashable>(&self, leafs: &[(usize, Leaf)]) -> Result<()> {
let mut nodes = leafs
.iter()
.map(|(index, leaf)| {
Index::from_size_offset(self.commitment.size(), *index)
.map(|index| (index, leaf.hash()))
})
.collect::<Result<Vec<_>>>()?;
nodes.sort_unstable_by_key(|(index, _)| *index);
require!(
nodes
.iter()
.tuple_windows()
.all(|(a, b)| a.0 != b.0 || a.1 == b.1),
Error::DuplicateLeafMismatch
);
nodes.dedup_by_key(|(index, _)| *index);
let mut nodes: VecDeque<(Index, Hash)> = nodes.into_iter().collect();
let mut hashes_iter = self.hashes.iter();
let mut pop = move || hashes_iter.next().ok_or(Error::NotEnoughHashes);
while let Some((current, hash)) = nodes.pop_front() {
if let Some(parent) = current.parent() {
let node = if current.is_left() {
if let Some((next, next_hash)) = nodes.front() {
let next_hash = next_hash.clone();
if current.sibling().unwrap() == *next {
let _ = nodes.pop_front();
Node(&hash, &next_hash).hash()
} else {
Node(&hash, pop()?).hash()
}
} else {
Node(&hash, pop()?).hash()
}
} else {
Node(pop()?, &hash).hash()
};
nodes.push_back((parent, node))
} else {
require!(hash == *self.commitment.hash(), Error::RootHashMismatch);
}
}
Ok(())
}
}