soft3/zheng/rs/src/spartan/verifier.rs

// ---
// tags: zheng, rust
// crystal-type: source
// crystal-domain: comp
// ---
//! SuperSpartan verifier: check sumcheck transcript and PCS opening.

use nebu::Goldilocks;

use lens::brakedown::Brakedown;
use lens::{Lens, Transcript as LensTranscript};

use crate::multilinear::{eq_evals, evaluate_multilinear};
use crate::sumcheck::verifier::SumcheckVerifier;
use crate::transcript::Transcript;
use crate::types::{CCSInstance, Proof, VerifyError};

/// SuperSpartan verifier for CCS instances (any number of constraint rows).
pub struct SpartanVerifier;

impl SpartanVerifier {
    /// Verify that `proof` attests to a satisfying witness for `instance`.
    ///
    /// The transcript must already have the statement and accumulator public
    /// data absorbed before this call (done by `lib.rs::verify()`).
    pub fn verify(
        instance: &CCSInstance,
        proof: &Proof,
        error_evals: &[Goldilocks],
        transcript: &mut Transcript,
    ) -> Result<(), VerifyError> {
        // โ”€โ”€ 1. Absorb commitment โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        transcript.absorb_commitment(&proof.commitment);

        // โ”€โ”€ 2. Check matrix eval count โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        if proof.matrix_evals.len() != instance.matrices.len() {
            return Err(VerifyError::EvaluationMismatch);
        }

        // โ”€โ”€ 3. Outer sumcheck (log m rounds) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        // For m=1: log_m=0, tau=[], e_claim=error_evals[0], 0 rounds, rho_x=[].
        let m = instance.num_rows;
        let log_m = m.trailing_zeros() as usize;
        let tau: Vec<Goldilocks> = transcript.squeeze_challenges(log_m);
        let e_claim = evaluate_multilinear(error_evals, &tau);

        let mut outer_verifier = SumcheckVerifier::new(e_claim, log_m);
        let (outer_final_claim, rho_x) =
            outer_verifier.verify_all(&proof.outer_sumcheck_polys, transcript)?;

        // โ”€โ”€ 4. Absorb claimed รป_i(ฯ_x) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        for &e in &proof.matrix_evals {
            transcript.absorb_eval(e);
        }

        // โ”€โ”€ 5. Check outer final claim: eq(ฯ„,ฯ_x) ยท G(ฯ_x) = outer_final_claim
        // G(ฯ_x) = ฮฃ_j c_j ยท โˆ_{i โˆˆ S_j} รป_i(ฯ_x)
        let mut constraint_val = Goldilocks::ZERO;
        for (multiset, &coeff) in instance.multisets.iter().zip(instance.coeffs.iter()) {
            let mut product = Goldilocks::ONE;
            for &idx in multiset {
                let e = proof.matrix_evals
                    .get(idx)
                    .copied()
                    .ok_or(VerifyError::EvaluationMismatch)?;
                product *= e;
            }
            constraint_val += coeff * product;
        }
        // eq(ฯ„, ฯ_x) โ€” the verifier computes this directly.
        // For m=1: tau=[], rho_x=[], eq_evals([])=[ONE], evaluate_multilinear([ONE],[])=ONE.
        let eq_val = evaluate_multilinear(&eq_evals(&tau), &rho_x);
        if eq_val * constraint_val != outer_final_claim {
            return Err(VerifyError::EvaluationMismatch);
        }

        // โ”€โ”€ 6. Squeeze ฮณ for batched inner sumcheck โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        let gamma = transcript.squeeze_challenge();

        // โ”€โ”€ 7. Compute batched claim: ฮฃ_i ฮณ^i ยท รป_i(ฯ_x) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        let batched_claim = {
            let mut c = Goldilocks::ZERO;
            let mut gp = Goldilocks::ONE;
            for &e in &proof.matrix_evals {
                c += gp * e;
                gp *= gamma;
            }
            c
        };

        // โ”€โ”€ 8. Inner sumcheck verification โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        let num_vars = proof.sumcheck_polys.len();
        let mut verifier = SumcheckVerifier::new(batched_claim, num_vars);
        let (final_claim, eval_point) =
            verifier.verify_all(&proof.sumcheck_polys, transcript)?;

        // โ”€โ”€ 9. Build w_combined using eq(ฯ_x, r) weights โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        // w_combined[col] = ฮฃ_i ฮณ^i ยท ฮฃ_r eq(ฯ_x,r) ยท M_i[r][col]
        // For m=1: eq_rox=[ONE], reduces to ฮฃ_i ฮณ^i ยท M_i[0][col] (same as before).
        let eq_rox = eq_evals(&rho_x);
        let z_size = 1usize << num_vars;
        let mut w_combined = vec![Goldilocks::ZERO; z_size];
        let mut gp = Goldilocks::ONE;
        for matrix in &instance.matrices {
            for (r, row) in matrix.entries.iter().enumerate() {
                let weight = gp * eq_rox.get(r).copied().unwrap_or(Goldilocks::ZERO);
                for &(col, coeff) in row {
                    if col < z_size {
                        w_combined[col] += weight * coeff;
                    }
                }
            }
            gp *= gamma;
        }
        let w_at_point = evaluate_multilinear(&w_combined, &eval_point);

        let expected_final = w_at_point * proof.eval_value;
        if final_claim != expected_final {
            return Err(VerifyError::SumcheckFailed { round: num_vars });
        }

        // โ”€โ”€ 10. Absorb eval_value, then PCS verify โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        let pcs_point: Vec<Goldilocks> = eval_point.iter().copied().rev().collect();
        transcript.absorb_eval(proof.eval_value);
        let seed = transcript.squeeze_hash();
        let mut lt = LensTranscript::new(&seed);
        if !Brakedown::verify(
            &proof.commitment,
            &pcs_point,
            proof.eval_value,
            &proof.pcs_opening,
            &mut lt,
        ) {
            return Err(VerifyError::LensFailed);
        }

        Ok(())
    }
}

Homonyms

soft3/zheng/rs/src/sumcheck/verifier.rs
soft3/radio/iroh/src/tls/verifier.rs

Graph