use axiom_eth::{
halo2_base::{
gates::{GateInstructions, RangeChip, RangeInstructions},
poseidon::hasher::PoseidonHasher,
safe_types::SafeBool,
utils::log2_ceil,
AssignedValue, Context,
},
utils::circuit_utils::{log2_ceil as circuit_log2_ceil, unsafe_lt_mask},
};
use ethers_core::{types::H256, utils::keccak256};
use itertools::Itertools;
use crate::utils::codec::{get_num_fe_from_subquery_key, AssignedSubqueryResult};
use crate::Field;
pub fn get_results_root<F: Field, const T: usize, const RATE: usize>(
ctx: &mut Context<F>,
range: &RangeChip<F>,
poseidon: &PoseidonHasher<F, T, RATE>,
results: &[AssignedSubqueryResult<F>],
num_subqueries: AssignedValue<F>,
) -> AssignedValue<F> {
let gate = range.gate();
let subquery_mask = unsafe_lt_mask(ctx, gate, num_subqueries, results.len());
get_results_root_poseidon(ctx, range, poseidon, results, num_subqueries, &subquery_mask)
}
pub fn get_results_root_poseidon<F: Field, const T: usize, const RATE: usize>(
ctx: &mut Context<F>,
range: &RangeChip<F>,
initialized_hasher: &PoseidonHasher<F, T, RATE>,
subquery_results: &[AssignedSubqueryResult<F>],
num_subqueries: AssignedValue<F>,
subquery_mask: &[SafeBool<F>],
) -> AssignedValue<F> {
let gate = range.gate();
let tree_depth = log2_ceil(subquery_results.len() as u64);
let depth = circuit_log2_ceil(ctx, gate, num_subqueries, tree_depth + 1);
let depth_indicator = gate.idx_to_indicator(ctx, depth, tree_depth + 1);
let const_zero = ctx.load_zero();
let mut leaves = Vec::with_capacity(1 << tree_depth);
for (subquery_result, &mask) in subquery_results.iter().zip_eq(subquery_mask) {
let key = &subquery_result.key;
let key_len = get_num_fe_from_subquery_key(ctx, gate, key);
let subquery_hash = initialized_hasher.hash_var_len_array(ctx, range, &key.0, key_len);
let concat = [&[subquery_hash], &subquery_result.value[..]].concat();
let mut leaf = initialized_hasher.hash_fix_len_array(ctx, gate, &concat);
leaf = gate.mul(ctx, leaf, mask);
leaves.push(leaf);
}
leaves.resize(1 << tree_depth, const_zero);
let mut layers = Vec::with_capacity(tree_depth + 1);
layers.push(leaves);
for i in 0..tree_depth {
let prev_layer = &layers[i];
let layer = (0..(prev_layer.len() + 1) / 2)
.map(|j| {
initialized_hasher.hash_fix_len_array(
ctx,
gate,
&[prev_layer[2 * j], prev_layer[2 * j + 1]],
)
})
.collect();
layers.push(layer);
}
let root_candidates = layers.iter().map(|layer| layer[0]).collect_vec();
gate.select_by_indicator(ctx, root_candidates, depth_indicator.to_vec())
}
fn generate_keccak_empty_roots(len: usize) -> Vec<H256> {
let mut empty_roots = Vec::with_capacity(len);
let mut root = H256::zero();
empty_roots.push(root);
for _ in 1..len {
root = H256(keccak256([root.as_bytes(), root.as_bytes()].concat()));
empty_roots.push(root);
}
empty_roots
}
lazy_static::lazy_static! {
pub static ref KECCAK_EMPTY_ROOTS: Vec<H256> = generate_keccak_empty_roots(32);
}