arnaucube
arnaucube/shockwave-plusPublic Self-hosted repository
shockwave-plus/shockwave_plus/src/sumcheck/sc_phase_1.rs
shockwave_plus/src/sumcheck/sc_phase_1.rsRaw
  1use crate::polynomial::ml_poly::MlPoly;
  2use crate::sumcheck::unipoly::UniPoly;
  3use serde::{Deserialize, Serialize};
  4use tensor_pcs::{EqPoly, Transcript};
  5
  6use crate::FieldExt;
  7
  8#[derive(Serialize, Deserialize)]
  9pub struct SCPhase1Proof<F: FieldExt> {
 10    pub blinder_poly_sum: F,
 11    pub blinder_poly_eval_claim: F,
 12    pub round_polys: Vec<UniPoly<F>>,
 13}
 14
 15pub struct SumCheckPhase1<F: FieldExt> {
 16    Az_evals: Vec<F>,
 17    Bz_evals: Vec<F>,
 18    Cz_evals: Vec<F>,
 19    bound_eq_poly: EqPoly<F>,
 20    challenge: Vec<F>,
 21}
 22
 23impl<F: FieldExt> SumCheckPhase1<F> {
 24    pub fn new(
 25        Az_evals: Vec<F>,
 26        Bz_evals: Vec<F>,
 27        Cz_evals: Vec<F>,
 28        tau: Vec<F>,
 29        challenge: Vec<F>,
 30    ) -> Self {
 31        let bound_eq_poly = EqPoly::new(tau);
 32        Self {
 33            Az_evals,
 34            Bz_evals,
 35            Cz_evals,
 36            bound_eq_poly,
 37            challenge,
 38        }
 39    }
 40
 41    pub fn prove(&self, transcript: &mut Transcript<F>) -> (SCPhase1Proof<F>, (F, F, F)) {
 42        let num_vars = (self.Az_evals.len() as f64).log2() as usize;
 43        let mut round_polys = Vec::<UniPoly<F>>::with_capacity(num_vars - 1);
 44
 45        let mut rng = rand::thread_rng();
 46        // Sample a blinding polynomial g(x_1, ..., x_m) of degree 3
 47        let random_evals = (0..2usize.pow(num_vars as u32))
 48            .map(|_| F::random(&mut rng))
 49            .collect::<Vec<F>>();
 50        let blinder_poly_sum = random_evals.iter().fold(F::ZERO, |acc, x| acc + x);
 51        let blinder_poly = MlPoly::new(random_evals);
 52
 53        transcript.append_fe(&blinder_poly_sum);
 54        let rho = transcript.challenge_fe();
 55
 56        // Compute the sum of g(x_1, ... x_m) over the boolean hypercube
 57
 58        // Do the sum check for f + \rho g
 59
 60        let mut A_table = self.Az_evals.clone();
 61        let mut B_table = self.Bz_evals.clone();
 62        let mut C_table = self.Cz_evals.clone();
 63        let mut blinder_table = blinder_poly.evals.clone();
 64        let mut eq_table = self.bound_eq_poly.evals();
 65
 66        let zero = F::ZERO;
 67        let one = F::ONE;
 68        let two = F::from(2);
 69        let three = F::from(3);
 70
 71        for j in 0..num_vars {
 72            let r_i = self.challenge[j];
 73
 74            let high_index = 2usize.pow((num_vars - j - 1) as u32);
 75
 76            let mut evals = [F::ZERO; 4];
 77
 78            // https://eprint.iacr.org/2019/317.pdf#subsection.3.2
 79            for b in 0..high_index {
 80                for (i, eval_at) in [zero, one, two, three].iter().enumerate() {
 81                    let a_eval = A_table[b] + (A_table[b + high_index] - A_table[b]) * eval_at;
 82                    let b_eval = B_table[b] + (B_table[b + high_index] - B_table[b]) * eval_at;
 83                    let c_eval = C_table[b] + (C_table[b + high_index] - C_table[b]) * eval_at;
 84                    let eq_eval = eq_table[b] + (eq_table[b + high_index] - eq_table[b]) * eval_at;
 85                    let blinder_eval = blinder_table[b]
 86                        + (blinder_table[b + high_index] - blinder_table[b]) * eval_at;
 87                    evals[i] += ((a_eval * b_eval - c_eval) * eq_eval) + rho * blinder_eval;
 88                }
 89
 90                A_table[b] = A_table[b] + (A_table[b + high_index] - A_table[b]) * r_i;
 91                B_table[b] = B_table[b] + (B_table[b + high_index] - B_table[b]) * r_i;
 92                C_table[b] = C_table[b] + (C_table[b + high_index] - C_table[b]) * r_i;
 93                eq_table[b] = eq_table[b] + (eq_table[b + high_index] - eq_table[b]) * r_i;
 94                blinder_table[b] =
 95                    blinder_table[b] + (blinder_table[b + high_index] - blinder_table[b]) * r_i;
 96            }
 97
 98            let round_poly = UniPoly::interpolate(&evals);
 99
100            round_polys.push(round_poly);
101        }
102
103        let v_A = A_table[0];
104        let v_B = B_table[0];
105        let v_C = C_table[0];
106
107        let rx = self.challenge.clone();
108        let blinder_poly_eval_claim = blinder_poly.eval(&rx);
109
110        // Prove the evaluation of the blinder polynomial at rx.
111
112        (
113            SCPhase1Proof {
114                blinder_poly_sum,
115                round_polys,
116                blinder_poly_eval_claim,
117            },
118            (v_A, v_B, v_C),
119        )
120    }
121
122    pub fn verify_round_polys(proof: &SCPhase1Proof<F>, challenge: &[F], rho: F) -> F {
123        debug_assert_eq!(proof.round_polys.len(), challenge.len());
124
125        let zero = F::ZERO;
126        let one = F::ONE;
127
128        // target = 0 + rho * blinder_poly_sum
129        let mut target = rho * proof.blinder_poly_sum;
130        for (i, round_poly) in proof.round_polys.iter().enumerate() {
131            assert_eq!(
132                round_poly.eval(zero) + round_poly.eval(one),
133                target,
134                "round poly {} failed",
135                i
136            );
137            target = round_poly.eval(challenge[i]);
138        }
139
140        target
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147    use halo2curves::secp256k1::Fp;
148    type F = Fp;
149    use halo2curves::ff::Field;
150
151    #[test]
152    fn test_unipoly_3() {
153        let coeffs = [F::from(1u64), F::from(2u64), F::from(3u64), F::from(4u64)];
154        let eval_at = Fp::from(33);
155
156        let mut expected_eval = F::ZERO;
157        for i in 0..coeffs.len() {
158            expected_eval += coeffs[i] * eval_at.pow(&[3 - i as u64, 0, 0, 0]);
159        }
160
161        let mut evals = [F::ZERO; 4];
162        for i in 0..4 {
163            let eval_at = F::from(i as u64);
164            let mut eval_i = F::ZERO;
165            for j in 0..coeffs.len() {
166                eval_i += coeffs[j] * eval_at.pow(&[3 - j as u64, 0, 0, 0]);
167            }
168            evals[i] = eval_i;
169        }
170
171        let uni_poly = UniPoly::interpolate(&evals);
172        let eval = uni_poly.eval(eval_at);
173        assert_eq!(eval, expected_eval);
174    }
175}