use ff::PrimeField;
use ff::PrimeFieldBits;
use nova_snark::frontend::{
gadgets::{boolean::Boolean, num::AllocatedNum},
ConstraintSystem, SynthesisError,
};
use super::poseidon::poseidon_hash_tagged_gadget;
use super::select::conditional_select;
use crate::poseidon::domain_tags;
pub fn verify_gated_merkle_path<F: PrimeField + PrimeFieldBits, CS: ConstraintSystem<F>>(
mut cs: CS,
leaf: &AllocatedNum<F>,
siblings: &[AllocatedNum<F>],
path_indices: &[Boolean],
is_active_flags: Option<&[Boolean]>,
max_depth: usize,
namespace_prefix: &str,
) -> Result<AllocatedNum<F>, SynthesisError> {
let mut current_hash = leaf.clone();
for i in 0..max_depth {
let mut step_cs = cs.namespace(|| format!("{}_step_{}", namespace_prefix, i));
let is_active = if let Some(flags) = is_active_flags {
flags.get(i).cloned().unwrap_or(Boolean::constant(false))
} else {
Boolean::constant(i < max_depth)
};
let sibling = if i < siblings.len() {
siblings[i].clone()
} else {
AllocatedNum::alloc(step_cs.namespace(|| "dummy_sibling"), || Ok(F::ZERO))?
};
let path_bit = if i < path_indices.len() {
path_indices[i].clone()
} else {
Boolean::constant(false)
};
let left = conditional_select(
step_cs.namespace(|| "select_left"),
&path_bit,
¤t_hash,
&sibling,
)?;
let right = conditional_select(
step_cs.namespace(|| "select_right"),
&path_bit,
&sibling,
¤t_hash,
)?;
let level_hash = poseidon_hash_tagged_gadget(
step_cs.namespace(|| "hash_nodes"),
domain_tags::node(),
&left,
&right,
)?;
current_hash = conditional_select(
step_cs.namespace(|| "select_output"),
&is_active,
¤t_hash, &level_hash, )?;
}
Ok(current_hash)
}
pub fn verify_merkle_path_gated<F: PrimeField + PrimeFieldBits, CS: ConstraintSystem<F>>(
cs: CS,
leaf: &AllocatedNum<F>,
siblings: &[AllocatedNum<F>],
path_indices: &[Boolean],
is_active_flags: Option<&[Boolean]>,
max_depth: usize,
) -> Result<AllocatedNum<F>, SynthesisError> {
verify_gated_merkle_path(
cs,
leaf,
siblings,
path_indices,
is_active_flags,
max_depth,
"merkle",
)
}
pub fn verify_aggregation_path_gated<F: PrimeField + PrimeFieldBits, CS: ConstraintSystem<F>>(
cs: CS,
leaf: &AllocatedNum<F>,
siblings: &[AllocatedNum<F>],
path_indices: &[Boolean],
depth: usize,
) -> Result<AllocatedNum<F>, SynthesisError> {
verify_gated_merkle_path(
cs,
leaf,
siblings,
path_indices,
None, depth,
"agg_merkle",
)
}