use hashbrown::HashMap;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use std_shims::{vec, BTreeMap, Vec};
use thiserror::Error;
use crate::core::fields::m31::BaseField;
use crate::core::vcs_lifted::merkle_hasher::MerkleHasherLifted;
use crate::core::ColumnVec;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Default)]
pub struct MerkleDecommitmentLifted<H: MerkleHasherLifted> {
pub hash_witness: Vec<H::Hash>,
}
impl<H: MerkleHasherLifted> MerkleDecommitmentLifted<H> {
pub const fn empty() -> Self {
Self {
hash_witness: Vec::new(),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MerkleDecommitmentLiftedAux<H: MerkleHasherLifted> {
pub all_node_values: Vec<HashMap<usize, H::Hash>>,
}
pub struct ExtendedMerkleDecommitmentLifted<H: MerkleHasherLifted> {
pub decommitment: MerkleDecommitmentLifted<H>,
pub aux: MerkleDecommitmentLiftedAux<H>,
}
pub struct MerkleVerifierLifted<H: MerkleHasherLifted> {
pub root: H::Hash,
pub column_log_sizes: Vec<u32>,
pub n_columns_per_log_size: BTreeMap<u32, usize>,
}
impl<H: MerkleHasherLifted> MerkleVerifierLifted<H> {
pub fn new(root: H::Hash, column_log_sizes: Vec<u32>) -> Self {
let mut n_columns_per_log_size = BTreeMap::new();
for log_size in &column_log_sizes {
*n_columns_per_log_size.entry(*log_size).or_insert(0) += 1;
}
Self {
root,
column_log_sizes,
n_columns_per_log_size,
}
}
pub fn verify(
&self,
query_positions: &[usize],
queried_values: ColumnVec<Vec<BaseField>>,
decommitment: MerkleDecommitmentLifted<H>,
) -> Result<(), MerkleVerificationError> {
let Some(max_log_size) = self.column_log_sizes.iter().max() else {
return Ok(());
};
for (i, j) in (0..query_positions.len()).tuple_windows() {
if query_positions[i] == query_positions[j] {
assert_eq!(queried_values[i], queried_values[j]);
}
}
let mut sorted_queries_iter = queried_values
.iter()
.zip_eq(self.column_log_sizes.iter())
.sorted_by_key(|(_, col_size)| *col_size)
.map(|(vals, _)| {
vals.iter()
.enumerate()
.dedup_by(|(idx1, _), (idx2, _)| {
query_positions[*idx1] == query_positions[*idx2]
})
.map(|(_, val)| val)
})
.collect_vec();
let mut prev_layer_hashes: Vec<(usize, H::Hash)> = vec![];
for pos in query_positions.iter() {
let row: Vec<_> = sorted_queries_iter
.iter_mut()
.map(|col_iter| *col_iter.next().unwrap())
.collect();
let mut hasher = H::default_with_initial_state();
hasher.update_leaf(&row);
prev_layer_hashes.push((*pos, hasher.finalize()));
}
assert!(sorted_queries_iter
.iter_mut()
.all(|cols_iter| cols_iter.next().is_none()));
let mut hash_witness = decommitment.hash_witness.into_iter();
for _ in 0..*max_log_size {
let mut curr_layer_hashes: Vec<(usize, H::Hash)> = vec![];
for chunk in prev_layer_hashes.as_slice().chunk_by(|a, b| a.0 ^ 1 == b.0) {
let (idx_0, hash_0) = chunk[0];
let children = if chunk.len() == 1 {
let witness = hash_witness
.next()
.ok_or(MerkleVerificationError::WitnessTooShort)?;
match idx_0 & 1 {
0 => (hash_0, witness),
1 => (witness, hash_0),
_ => unreachable!(),
}
} else {
let (_, hash_1) = chunk[1];
(hash_0, hash_1)
};
curr_layer_hashes.push((idx_0 >> 1, H::hash_children(children)));
}
prev_layer_hashes = curr_layer_hashes;
}
if hash_witness.next().is_some() {
return Err(MerkleVerificationError::WitnessTooLong);
}
let [(_, computed_root)] = prev_layer_hashes.try_into().unwrap();
if computed_root != self.root {
return Err(MerkleVerificationError::RootMismatch);
}
Ok(())
}
}
#[derive(Clone, Copy, Debug, Error, PartialEq, Eq)]
pub enum MerkleVerificationError {
#[error("Witness is too short.")]
WitnessTooShort,
#[error("Witness is too long.")]
WitnessTooLong,
#[error("Root mismatch.")]
RootMismatch,
}
#[cfg(all(test, feature = "prover"))]
mod tests {
use num_traits::Zero;
use crate::core::fields::m31::BaseField;
use crate::core::vcs::blake2_hash::Blake2sHash;
use crate::core::vcs_lifted::blake2_merkle::Blake2sMerkleHasher;
use crate::core::vcs_lifted::test_utils::prepare_merkle;
use crate::core::vcs_lifted::verifier::MerkleVerificationError;
#[test]
fn test_merkle_success() {
let (queries, decommitment, values, verifier) = prepare_merkle::<Blake2sMerkleHasher>();
verifier.verify(&queries, values, decommitment).unwrap();
}
#[test]
#[cfg(not(target_arch = "wasm32"))]
fn test_merkle_success_poseidon() {
use crate::core::vcs_lifted::poseidon252_merkle::Poseidon252MerkleHasher;
let (queries, decommitment, values, verifier) = prepare_merkle::<Poseidon252MerkleHasher>();
verifier.verify(&queries, values, decommitment).unwrap();
}
#[test]
fn test_merkle_invalid_witness() {
let (queries, mut decommitment, values, verifier) = prepare_merkle::<Blake2sMerkleHasher>();
decommitment.hash_witness[4] = Blake2sHash::default();
assert_eq!(
verifier.verify(&queries, values, decommitment).unwrap_err(),
MerkleVerificationError::RootMismatch
);
}
#[test]
fn test_merkle_invalid_witness_poseidon() {
let (queries, mut decommitment, values, verifier) = prepare_merkle::<Blake2sMerkleHasher>();
decommitment.hash_witness[4] = Blake2sHash::default();
assert_eq!(
verifier.verify(&queries, values, decommitment).unwrap_err(),
MerkleVerificationError::RootMismatch
);
}
#[test]
fn test_merkle_invalid_value() {
let (queries, decommitment, mut values, verifier) = prepare_merkle::<Blake2sMerkleHasher>();
values[0][2] = BaseField::zero();
assert_eq!(
verifier.verify(&queries, values, decommitment).unwrap_err(),
MerkleVerificationError::RootMismatch
);
}
#[test]
fn test_merkle_witness_too_short() {
let (queries, mut decommitment, values, verifier) = prepare_merkle::<Blake2sMerkleHasher>();
decommitment.hash_witness.pop();
assert_eq!(
verifier.verify(&queries, values, decommitment).unwrap_err(),
MerkleVerificationError::WitnessTooShort
);
}
#[test]
fn test_merkle_witness_too_long() {
let (queries, mut decommitment, values, verifier) = prepare_merkle::<Blake2sMerkleHasher>();
decommitment.hash_witness.push(Blake2sHash::default());
assert_eq!(
verifier.verify(&queries, values, decommitment).unwrap_err(),
MerkleVerificationError::WitnessTooLong
);
}
}