use ff::Field;
use midnight_proofs::{circuit::Layouter, plonk::Error, poly::CommitmentLabel};
use crate::{
field::AssignedNative,
instructions::ArithInstructions,
verifier::{
kzg::VerifierQuery,
msm::AssignedMsm,
transcript_gadget::TranscriptGadget,
utils::{mul_add, mul_bounded_scalars, try_reduce, AssignedBoundedScalar},
SelfEmulation,
},
};
#[derive(Clone, Debug)]
pub(crate) struct Committed<S: SelfEmulation> {
random_poly_commitment: S::AssignedPoint,
}
#[derive(Clone, Debug)]
pub(crate) struct Constructed<S: SelfEmulation> {
h_commitments: Vec<S::AssignedPoint>,
random_poly_commitment: S::AssignedPoint,
}
#[derive(Clone, Debug)]
pub(crate) struct PartiallyEvaluated<S: SelfEmulation> {
h_commitments: Vec<S::AssignedPoint>,
random_poly_commitment: S::AssignedPoint,
random_eval: AssignedNative<S::F>,
}
#[derive(Clone, Debug)]
pub(crate) struct Evaluated<S: SelfEmulation> {
h_commitment: AssignedMsm<S>,
random_poly_commitment: S::AssignedPoint,
expected_h_eval: AssignedNative<S::F>,
random_eval: AssignedNative<S::F>,
}
pub(crate) fn read_commitments_before_y<S: SelfEmulation>(
layouter: &mut impl Layouter<S::F>,
transcript_gadget: &mut TranscriptGadget<S>,
) -> Result<Committed<S>, Error> {
let random_poly_commitment = transcript_gadget.read_point(layouter)?;
Ok(Committed {
random_poly_commitment,
})
}
impl<S: SelfEmulation> Committed<S> {
pub(crate) fn read_commitment_after_y(
self,
layouter: &mut impl Layouter<S::F>,
transcript_gadget: &mut TranscriptGadget<S>,
quotient_poly_degree: usize,
) -> Result<Constructed<S>, Error> {
let h_commitments = (0..quotient_poly_degree)
.map(|_| transcript_gadget.read_point(layouter))
.collect::<Result<Vec<_>, Error>>()?;
Ok(Constructed {
h_commitments,
random_poly_commitment: self.random_poly_commitment,
})
}
}
impl<S: SelfEmulation> Constructed<S> {
pub(crate) fn evaluate_after_x(
self,
layouter: &mut impl Layouter<S::F>,
transcript_gadget: &mut TranscriptGadget<S>,
) -> Result<PartiallyEvaluated<S>, Error> {
let random_eval = transcript_gadget.read_scalar(layouter)?;
Ok(PartiallyEvaluated {
h_commitments: self.h_commitments,
random_poly_commitment: self.random_poly_commitment,
random_eval,
})
}
}
impl<S: SelfEmulation> PartiallyEvaluated<S> {
pub(crate) fn verify(
&self,
layouter: &mut impl Layouter<S::F>,
scalar_chip: &S::ScalarChip,
expressions: &[AssignedNative<S::F>],
y: &AssignedNative<S::F>,
xn: &AssignedNative<S::F>,
splitting_factor: &AssignedNative<S::F>,
) -> Result<Evaluated<S>, Error> {
let expected_h_eval = {
let num = try_reduce(expressions.iter().cloned(), |h_eval, v| {
mul_add(layouter, scalar_chip, &h_eval, y, &v)
})?;
let den = scalar_chip.add_constant(layouter, xn, -S::F::ONE)?;
scalar_chip.div(layouter, &num, &den)?
};
let splitting_factor = AssignedBoundedScalar::new(splitting_factor, None);
let mut acc = AssignedBoundedScalar::one(layouter, scalar_chip)?;
let mut h_commitment = AssignedMsm::from_term(&acc, &self.h_commitments[0]);
for h_com in self.h_commitments.iter().skip(1) {
acc = mul_bounded_scalars(layouter, scalar_chip, &acc, &splitting_factor)?;
h_commitment.add_term(&acc, h_com);
}
Ok(Evaluated {
h_commitment,
random_poly_commitment: self.random_poly_commitment.clone(),
expected_h_eval,
random_eval: self.random_eval.clone(),
})
}
}
impl<S: SelfEmulation> Evaluated<S> {
pub(crate) fn queries(
&self,
one: &AssignedBoundedScalar<S::F>, x: &AssignedNative<S::F>, ) -> Vec<VerifierQuery<S>> {
vec![
VerifierQuery::new_from_msm(
x,
CommitmentLabel::Custom("vanishing".into()),
&self.h_commitment,
&self.expected_h_eval,
),
VerifierQuery::new(
one,
x,
CommitmentLabel::Custom("random_poly".into()),
&self.random_poly_commitment,
&self.random_eval,
),
]
}
}