use std::{any::Any, collections::HashMap, iter};
use anyhow::{anyhow, bail, Result};
use ethers_core::{types::H256, utils::keccak256};
use zkevm_hashes::keccak::{
component::{
circuit::shard::KeccakComponentShardCircuit,
output::{calculate_circuit_outputs_commit, multi_inputs_to_circuit_outputs},
},
vanilla::keccak_packed_multi::get_num_keccak_f,
};
use crate::{
halo2_proofs::plonk::Circuit,
utils::{
component::{
types::ComponentPublicInstances, ComponentCircuit, ComponentPromiseResult,
ComponentPromiseResultsInMerkle, GroupedPromiseCalls, GroupedPromiseResults,
LogicalResult, PromiseShardMetadata,
},
encode_h256_to_hilo,
},
Field,
};
use super::types::{ComponentTypeKeccak, CoreInputKeccak, KeccakLogicalInput, KeccakVirtualOutput};
impl<F: Field> ComponentCircuit<F> for KeccakComponentShardCircuit<F> {
fn clear_witnesses(&self) {
self.base_circuit_builder().borrow_mut().clear();
self.hasher().borrow_mut().clear();
}
fn compute_promise_calls(&self) -> Result<GroupedPromiseCalls> {
Ok(HashMap::new())
}
fn feed_input(&self, input: Box<dyn Any>) -> Result<()> {
let typed_input =
input.downcast::<CoreInputKeccak>().map_err(|_| anyhow!("invalid input type"))?;
let params_cap = self.params().capacity();
let input_cap =
typed_input.iter().map(|input| get_num_keccak_f(input.len())).sum::<usize>();
if input_cap > params_cap {
bail!("Input capacity {input_cap} > configured capacity {params_cap}");
}
let mut inputs = *typed_input;
inputs.extend(iter::repeat(vec![]).take(params_cap - input_cap));
*self.inputs().borrow_mut() = inputs;
Ok(())
}
fn compute_outputs(&self) -> Result<ComponentPromiseResultsInMerkle<F>> {
let capacity = self.params().capacity();
let vt = multi_inputs_to_circuit_outputs::<F>(&self.inputs().borrow(), capacity);
let output_commit_val = calculate_circuit_outputs_commit(&vt);
let pr: Vec<ComponentPromiseResult<F>> = self
.inputs()
.borrow()
.iter()
.map(|bytes| {
let output = H256(keccak256(bytes));
LogicalResult::<F, ComponentTypeKeccak<F>>::new(
KeccakLogicalInput::new(bytes.clone()),
KeccakVirtualOutput::new(encode_h256_to_hilo(&output)),
)
.into()
})
.collect();
Ok(ComponentPromiseResultsInMerkle::<F>::new(
vec![PromiseShardMetadata { commit: output_commit_val, capacity }],
vec![(0, pr)],
))
}
fn get_public_instances(&self) -> ComponentPublicInstances<F> {
unreachable!("keccak does not follow ComponentPublicInstances")
}
fn fulfill_promise_results(&self, _: &GroupedPromiseResults<F>) -> anyhow::Result<()> {
Ok(())
}
}