EspressoSystems / jellyfish

A Rust Implementation of the PLONK ZKP System and Extensions
https://jellyfish.docs.espressosys.com
MIT License
385 stars 93 forks source link

[bug]: incorrect lagrange evaluation when zeta is roots of unity #605

Closed alxiong closed 1 month ago

alxiong commented 1 month ago

Thanks to Shresth and CommonPrefix team for catching this bug (for an audit of the corresponding plonk verifier contract).

Currently the logic for computing lagrange evaluation is wrong when random challenge zeta is roots of unity (which results in vanishing_eval to be zero. In this case, $\mathcal{L}_1(\zeta) = 1$ if $\zeta$ is the first roots-of-unity, and zero otherwise. but our current code would simply panic due to division by zero.

    pub(crate) fn evaluate_lagrange_1_and_n(
        &self,
        zeta: &E::ScalarField,
        vanish_eval: &E::ScalarField,
    ) -> (E::ScalarField, E::ScalarField) {
        let divisor =
            E::ScalarField::from(self.domain.size() as u32) * (*zeta - E::ScalarField::one());
        let lagrange_1_eval = *vanish_eval / divisor;
        let divisor =
            E::ScalarField::from(self.domain.size() as u32) * (*zeta - self.domain.group_gen_inv);
        let lagrange_n_eval = *vanish_eval * self.domain.group_gen_inv / divisor;
        (lagrange_1_eval, lagrange_n_eval)
    }

this also affects evaluate_pi_poly() that internally uses lagrange_i_eval. We should further double check and fix prover-side code.

Note: we didn't catch this in test because:

Thus this issue should also aim to improve tests to guard against this bug

Note2: this is a hard-to-exploit bug (unless our FS is also broken), so current downstream relying on jellyfish shouldn't panic, but the PR that fix this bug should issue a new release and recommend all downstream to migrate over soon.

cc @mrain @chancharles92

alxiong commented 1 month ago

comments needed, I wanted to directly replace our usage with arkworks' API, unfortunately, they only have EvalDomain::evaluate_all_lagrange_coefficients()

~maybe I'll just mimic write a fn evaluate_lagrange_coeff_at(domain) for now, and submit a PR upstream for future arkworks to include this API directly in struct EvalDomain, okay?~

Here's my plan:

@mrain @chancharles92