use anyhow::Result;
use std::collections::HashMap;
use zisk_common::{BuiltInHint, HintCode, PrecompileHint};
use ziskos_hints::handlers::bigint::modexp_hint;
use ziskos_hints::handlers::blake2b::blake2b_compress_hint;
use ziskos_hints::handlers::bls381::{
bls12_381_fp2_to_g2_hint, bls12_381_fp_to_g1_hint, bls12_381_g1_add_hint,
bls12_381_g1_msm_hint, bls12_381_g2_add_hint, bls12_381_g2_msm_hint,
bls12_381_pairing_check_hint,
};
use ziskos_hints::handlers::bn254::{
bn254_g1_add_hint, bn254_g1_mul_hint, bn254_pairing_check_hint,
};
use ziskos_hints::handlers::keccak256::keccak256_hint;
use ziskos_hints::handlers::kzg::verify_kzg_proof_hint;
use ziskos_hints::handlers::ripemd160::ripemd160_hint;
use ziskos_hints::handlers::secp256k1::{secp256k1_ecdsa_verify_hint, secp256k1_ecrecover_hint};
use ziskos_hints::handlers::secp256r1::secp256r1_ecdsa_verify_hint;
use ziskos_hints::handlers::sha256::sha256_hint;
use ziskos_hints::handlers::uint256::{
add_mod256_hint, inv_mod256_hint, mulmod256_hint, pow_mod256_hint, reduce_mod256_hint,
square_mod256_hint,
};
pub type CustomHintHandler = Box<dyn Fn(&[u64]) -> Result<Vec<u64>> + Send + Sync>;
#[derive(Default)]
pub struct HintHandlers {
custom: HashMap<u32, CustomHintHandler>,
}
impl HintHandlers {
pub fn register<F>(mut self, hint_code: u32, handler: F) -> Self
where
F: Fn(&[u64]) -> Result<Vec<u64>> + Send + Sync + 'static,
{
self.custom.insert(hint_code, Box::new(handler));
self
}
pub fn has_custom_hint_code(&self, code: u32) -> bool {
self.custom.contains_key(&code)
}
#[inline]
pub fn dispatch(&self, hint: PrecompileHint) -> Result<Vec<u64>> {
match hint.hint_code {
HintCode::BuiltIn(builtin) => {
Self::dispatch_builtin(builtin, hint.data, hint.data_len_bytes)
}
HintCode::Custom(code) => self
.custom
.get(&code)
.map(|handler| handler(&hint.data))
.unwrap_or_else(|| Err(anyhow::anyhow!("Unknown custom hint"))),
_ => unreachable!("Control hints handled before dispatch"),
}
}
#[inline]
fn dispatch_builtin(
hint: BuiltInHint,
data: Vec<u64>,
data_len_bytes: usize,
) -> Result<Vec<u64>> {
match hint {
BuiltInHint::Sha256 => sha256_hint(&data, data_len_bytes),
BuiltInHint::Bn254G1Add => bn254_g1_add_hint(&data),
BuiltInHint::Bn254G1Mul => bn254_g1_mul_hint(&data),
BuiltInHint::Bn254PairingCheck => bn254_pairing_check_hint(&data),
BuiltInHint::Secp256k1Ecrecover => secp256k1_ecrecover_hint(&data),
BuiltInHint::Secp256k1EcdsaVerify => secp256k1_ecdsa_verify_hint(&data),
BuiltInHint::Secp256r1EcdsaVerify => secp256r1_ecdsa_verify_hint(&data),
BuiltInHint::Bls12_381G1Add => bls12_381_g1_add_hint(&data),
BuiltInHint::Bls12_381G1Msm => bls12_381_g1_msm_hint(&data),
BuiltInHint::Bls12_381G2Add => bls12_381_g2_add_hint(&data),
BuiltInHint::Bls12_381G2Msm => bls12_381_g2_msm_hint(&data),
BuiltInHint::Bls12_381PairingCheck => bls12_381_pairing_check_hint(&data),
BuiltInHint::Bls12_381FpToG1 => bls12_381_fp_to_g1_hint(&data),
BuiltInHint::Bls12_381Fp2ToG2 => bls12_381_fp2_to_g2_hint(&data),
BuiltInHint::ModExp => modexp_hint(&data),
BuiltInHint::MulMod256 => mulmod256_hint(&data),
BuiltInHint::ReduceMod256 => reduce_mod256_hint(&data),
BuiltInHint::AddMod256 => add_mod256_hint(&data),
BuiltInHint::SquareMod256 => square_mod256_hint(&data),
BuiltInHint::PowMod256 => pow_mod256_hint(&data),
BuiltInHint::InvMod256 => inv_mod256_hint(&data),
BuiltInHint::VerifyKzgProof => verify_kzg_proof_hint(&data),
BuiltInHint::Keccak256 => keccak256_hint(&data, data_len_bytes),
BuiltInHint::Blake2bCompress => blake2b_compress_hint(&data),
BuiltInHint::Ripemd160 => ripemd160_hint(&data, data_len_bytes),
BuiltInHint::Input => unreachable!(
"Input hints should be handled separately and not dispatched to workers"
),
}
}
}