use ark_std::ops::Mul;
use crate::{
errors::UzkgeError,
poly_commit::{field_polynomial::FpPolynomial, pcs::PolyComScheme},
utils::transcript::Transcript,
};
use super::{
constraint_system::ConstraintSystem,
helpers::{eval_pi_poly, first_lagrange_poly, r_commitment, r_eval_zeta, PlonkChallenges},
indexer::{PlonkProof, PlonkVerifierParams},
transcript::transcript_init_plonk,
};
pub fn verifier<PCS: PolyComScheme, CS: ConstraintSystem<PCS::Field>>(
transcript: &mut Transcript,
pcs: &PCS,
cs: &CS,
verifier_params: &PlonkVerifierParams<PCS>,
pi: &[PCS::Field],
proof: &PlonkProof<PCS>,
) -> Result<(), UzkgeError> {
let domain = FpPolynomial::<PCS::Field>::evaluation_domain(cs.size())
.ok_or(UzkgeError::GroupNotFound(cs.size()))?;
let root = domain.group_gen;
transcript_init_plonk(transcript, verifier_params, pi, &root);
let mut challenges = PlonkChallenges::new();
compute_challenges::<PCS>(&mut challenges, transcript, &proof);
let (z_h_eval_zeta, first_lagrange_eval_zeta) =
first_lagrange_poly::<PCS>(&challenges, verifier_params.cs_size as u64);
let pi_eval_zeta = eval_pi_poly::<PCS>(
verifier_params,
pi,
&z_h_eval_zeta,
challenges.get_zeta().unwrap(),
&root,
);
let r_eval_zeta = r_eval_zeta::<PCS>(
proof,
&challenges,
&pi_eval_zeta,
&first_lagrange_eval_zeta,
verifier_params.anemoi_generator,
verifier_params.anemoi_generator_inv,
);
let w_polys_eval_zeta_as_ref: Vec<&PCS::Field> = proof.w_polys_eval_zeta.iter().collect();
#[cfg(feature = "shuffle")]
let w_polys_eval_zeta_omega_as_ref: Vec<&PCS::Field> =
proof.w_polys_eval_zeta_omega.iter().collect();
#[cfg(feature = "shuffle")]
let w_sel_polys_eval_zeta_as_ref: Vec<&PCS::Field> =
proof.w_sel_polys_eval_zeta.iter().collect();
let s_eval_zeta_as_ref: Vec<&PCS::Field> = proof.s_polys_eval_zeta.iter().collect();
let cm_r = r_commitment::<PCS, CS>(
verifier_params,
&proof.cm_z,
&w_polys_eval_zeta_as_ref[..],
#[cfg(feature = "shuffle")]
&w_sel_polys_eval_zeta_as_ref[..],
&s_eval_zeta_as_ref[..],
&proof.prk_3_poly_eval_zeta,
#[cfg(feature = "shuffle")]
&proof.q_ecc_poly_eval_zeta,
#[cfg(feature = "shuffle")]
&w_polys_eval_zeta_omega_as_ref[..],
&proof.z_eval_zeta_omega,
&challenges,
&proof.cm_t_vec[..],
&first_lagrange_eval_zeta,
&z_h_eval_zeta,
verifier_params.cs_size + 2,
);
let mut commitments: Vec<&PCS::Commitment> = proof
.cm_w_vec
.iter()
.chain(
verifier_params
.cm_s_vec
.iter()
.take(CS::n_wires_per_gate() - 1),
)
.collect();
commitments.push(&verifier_params.cm_prk_vec[2]);
commitments.push(&verifier_params.cm_prk_vec[3]);
#[cfg(feature = "shuffle")]
{
commitments.push(&verifier_params.cm_q_ecc);
for cm_w_sel in proof.cm_w_sel_vec.iter() {
commitments.push(cm_w_sel);
}
}
commitments.push(&cm_r);
let mut values: Vec<PCS::Field> = proof
.w_polys_eval_zeta
.iter()
.chain(proof.s_polys_eval_zeta.iter())
.cloned()
.collect();
values.push(proof.prk_3_poly_eval_zeta);
values.push(proof.prk_4_poly_eval_zeta);
#[cfg(feature = "shuffle")]
{
values.push(proof.q_ecc_poly_eval_zeta);
for w_sel_eval_zeta in proof.w_sel_polys_eval_zeta.iter() {
values.push(*w_sel_eval_zeta);
}
}
values.push(r_eval_zeta);
let zeta = challenges.get_zeta().unwrap();
let zeta_omega = zeta.mul(&root);
let (comm, val) = pcs.batch(
transcript,
&commitments[..],
verifier_params.cs_size + 2,
&zeta,
&values[..],
);
let (comm_omega, val_omega) = pcs.batch(
transcript,
&[
&proof.cm_z,
&proof.cm_w_vec[0],
&proof.cm_w_vec[1],
&proof.cm_w_vec[2],
],
verifier_params.cs_size + 2,
&zeta_omega,
&[
proof.z_eval_zeta_omega,
proof.w_polys_eval_zeta_omega[0],
proof.w_polys_eval_zeta_omega[1],
proof.w_polys_eval_zeta_omega[2],
],
);
pcs.batch_verify_diff_points(
&[comm, comm_omega],
&[zeta.clone(), zeta_omega.clone()],
&[val, val_omega],
&[
proof.opening_witness_zeta.clone(),
proof.opening_witness_zeta_omega.clone(),
],
challenges.get_u().unwrap(),
)
.map_err(|_| UzkgeError::VerificationError)
}
fn compute_challenges<PCS: PolyComScheme>(
challenges: &mut PlonkChallenges<PCS::Field>,
transcript: &mut Transcript,
proof: &PlonkProof<PCS>,
) {
for cm_w in proof.cm_w_vec.iter() {
transcript.append_commitment::<PCS::Commitment>(cm_w);
}
#[cfg(feature = "shuffle")]
for cm_w_sel in proof.cm_w_sel_vec.iter() {
transcript.append_commitment::<PCS::Commitment>(cm_w_sel);
}
let beta = transcript.get_challenge_field_elem(b"beta");
transcript.append_single_byte(b"gamma", 0x01);
let gamma = transcript.get_challenge_field_elem(b"gamma");
challenges.insert_beta_gamma(beta, gamma).unwrap();
transcript.append_commitment::<PCS::Commitment>(&proof.cm_z);
let alpha = transcript.get_challenge_field_elem(b"alpha");
challenges.insert_alpha(alpha).unwrap();
for cm_t in &proof.cm_t_vec {
transcript.append_commitment::<PCS::Commitment>(&cm_t);
}
let zeta = transcript.get_challenge_field_elem(b"zeta");
challenges.insert_zeta(zeta).unwrap();
for eval_zeta in proof
.w_polys_eval_zeta
.iter()
.chain(proof.s_polys_eval_zeta.iter())
{
transcript.append_challenge(eval_zeta);
}
#[cfg(feature = "shuffle")]
{
for eval_zeta in proof.w_sel_polys_eval_zeta.iter() {
transcript.append_challenge(eval_zeta);
}
}
transcript.append_challenge(&proof.prk_3_poly_eval_zeta);
transcript.append_challenge(&proof.prk_4_poly_eval_zeta);
transcript.append_challenge(&proof.z_eval_zeta_omega);
#[cfg(feature = "shuffle")]
transcript.append_challenge(&proof.q_ecc_poly_eval_zeta);
for eval_zeta_omega in proof.w_polys_eval_zeta_omega.iter() {
transcript.append_challenge(eval_zeta_omega);
}
let u = transcript.get_challenge_field_elem(b"u");
challenges.insert_u(u).unwrap();
}