use std::collections::BTreeMap;
use group::Group;
use midnight_circuits::{
hash::poseidon::{PoseidonChip, PoseidonState},
instructions::{hash::HashCPU, *},
types::AssignedNative,
verifier::SelfEmulation,
};
use midnight_proofs::{
circuit::{Layouter, Value},
plonk::{ConstraintSystem, Error},
transcript::Hashable,
};
use midnight_zk_stdlib::{MidnightVK, ZkStdLib};
use crate::ivc::{C, F, S};
pub type VkHashAndBases = (
AssignedNative<F>,
BTreeMap<String, <S as SelfEmulation>::AssignedPoint>,
);
pub fn compute_vk_hash(vk: &MidnightVK) -> F {
let vk = vk.vk();
let to_raw = Hashable::<PoseidonState<F>>::to_input;
let vk_repr = vec![vk.transcript_repr()];
let fixed_coms: Vec<F> = vk.fixed_commitments().iter().flat_map(to_raw).collect();
let perm_coms: Vec<F> = vk.permutation().commitments().iter().flat_map(to_raw).collect();
<PoseidonChip<F> as HashCPU<F, F>>::hash(&[vk_repr, fixed_coms, perm_coms].concat())
}
pub fn assign_and_hash_vk(
layouter: &mut impl Layouter<F>,
std_lib: &ZkStdLib,
cs: &ConstraintSystem<F>,
vk: Value<&MidnightVK>,
) -> Result<VkHashAndBases, Error> {
let curve_chip = std_lib.bls12_381();
let nb_fixed = cs.num_fixed_columns() + cs.num_selectors();
let nb_perm = cs.permutation().columns.len();
let base_values: Vec<Value<C>> = (0..nb_fixed)
.map(|i| vk.map(|vk| vk.vk().fixed_commitments()[i]))
.chain((0..nb_perm).map(|i| vk.map(|vk| vk.vk().permutation().commitments()[i])))
.collect();
let assigned_bases = base_values
.into_iter()
.map(|val| curve_chip.assign_without_subgroup_check(layouter, val))
.collect::<Result<Vec<_>, _>>()?;
let transcript_repr = std_lib.assign(layouter, vk.map(|vk| vk.vk().transcript_repr()))?;
let mut input = vec![transcript_repr];
for base in &assigned_bases {
input.extend(curve_chip.as_public_input(layouter, base)?);
}
let hash = std_lib.poseidon(layouter, &input)?;
let mut named_map: BTreeMap<String, _> = assigned_bases
.iter()
.enumerate()
.map(|(i, base)| {
let name = if i < nb_fixed {
midnight_circuits::verifier::fixed_commitment_name("inner_vk", i)
} else {
midnight_circuits::verifier::perm_commitment_name("inner_vk", i - nb_fixed)
};
(name, base.clone())
})
.collect();
let neg_g = curve_chip.assign_fixed(layouter, -C::generator())?;
named_map.insert("-G".into(), neg_g);
Ok((hash, named_map))
}