arnaucube
arnaucube/testudoPublic Self-hosted repository
testudo/src/product_tree.rs
src/product_tree.rsRaw
  1#![allow(dead_code)]
  2use super::dense_mlpoly::DensePolynomial;
  3use super::dense_mlpoly::EqPolynomial;
  4use super::math::Math;
  5use super::sumcheck::SumcheckInstanceProof;
  6use crate::poseidon_transcript::PoseidonTranscript;
  7use crate::transcript::Transcript;
  8use ark_crypto_primitives::sponge::Absorb;
  9use ark_ff::PrimeField;
 10use ark_serialize::*;
 11
 12#[derive(Debug)]
 13pub struct ProductCircuit<F: PrimeField> {
 14  left_vec: Vec<DensePolynomial<F>>,
 15  right_vec: Vec<DensePolynomial<F>>,
 16}
 17
 18impl<F: PrimeField> ProductCircuit<F> {
 19  fn compute_layer(
 20    inp_left: &DensePolynomial<F>,
 21    inp_right: &DensePolynomial<F>,
 22  ) -> (DensePolynomial<F>, DensePolynomial<F>) {
 23    let len = inp_left.len() + inp_right.len();
 24    let outp_left = (0..len / 4)
 25      .map(|i| inp_left[i] * inp_right[i])
 26      .collect::<Vec<_>>();
 27    let outp_right = (len / 4..len / 2)
 28      .map(|i| inp_left[i] * inp_right[i])
 29      .collect::<Vec<_>>();
 30    (
 31      DensePolynomial::new(outp_left),
 32      DensePolynomial::new(outp_right),
 33    )
 34  }
 35
 36  pub fn new(poly: &DensePolynomial<F>) -> Self {
 37    let mut left_vec: Vec<DensePolynomial<F>> = Vec::new();
 38    let mut right_vec: Vec<DensePolynomial<F>> = Vec::new();
 39
 40    let num_layers = poly.len().log_2();
 41    let (outp_left, outp_right) = poly.split(poly.len() / 2);
 42
 43    left_vec.push(outp_left);
 44    right_vec.push(outp_right);
 45
 46    for i in 0..num_layers - 1 {
 47      let (outp_left, outp_right) = ProductCircuit::compute_layer(&left_vec[i], &right_vec[i]);
 48      left_vec.push(outp_left);
 49      right_vec.push(outp_right);
 50    }
 51
 52    ProductCircuit {
 53      left_vec,
 54      right_vec,
 55    }
 56  }
 57
 58  pub fn evaluate(&self) -> F {
 59    let len = self.left_vec.len();
 60    assert_eq!(self.left_vec[len - 1].get_num_vars(), 0);
 61    assert_eq!(self.right_vec[len - 1].get_num_vars(), 0);
 62    self.left_vec[len - 1][0] * self.right_vec[len - 1][0]
 63  }
 64}
 65
 66pub struct DotProductCircuit<F: PrimeField> {
 67  left: DensePolynomial<F>,
 68  right: DensePolynomial<F>,
 69  weight: DensePolynomial<F>,
 70}
 71
 72impl<F: PrimeField> DotProductCircuit<F> {
 73  pub fn new(
 74    left: DensePolynomial<F>,
 75    right: DensePolynomial<F>,
 76    weight: DensePolynomial<F>,
 77  ) -> Self {
 78    assert_eq!(left.len(), right.len());
 79    assert_eq!(left.len(), weight.len());
 80    DotProductCircuit {
 81      left,
 82      right,
 83      weight,
 84    }
 85  }
 86
 87  pub fn evaluate(&self) -> F {
 88    (0..self.left.len())
 89      .map(|i| self.left[i] * self.right[i] * self.weight[i])
 90      .sum()
 91  }
 92
 93  pub fn split(&mut self) -> (Self, Self) {
 94    let idx = self.left.len() / 2;
 95    assert_eq!(idx * 2, self.left.len());
 96    let (l1, l2) = self.left.split(idx);
 97    let (r1, r2) = self.right.split(idx);
 98    let (w1, w2) = self.weight.split(idx);
 99    (
100      DotProductCircuit {
101        left: l1,
102        right: r1,
103        weight: w1,
104      },
105      DotProductCircuit {
106        left: l2,
107        right: r2,
108        weight: w2,
109      },
110    )
111  }
112}
113
114#[allow(dead_code)]
115#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
116pub struct LayerProof<F: PrimeField> {
117  pub proof: SumcheckInstanceProof<F>,
118  pub claims: Vec<F>,
119}
120
121#[allow(dead_code)]
122impl<F: PrimeField + Absorb> LayerProof<F> {
123  pub fn verify(
124    &self,
125    claim: F,
126    num_rounds: usize,
127    degree_bound: usize,
128    transcript: &mut PoseidonTranscript<F>,
129  ) -> (F, Vec<F>) {
130    self
131      .proof
132      .verify(claim, num_rounds, degree_bound, transcript)
133      .unwrap()
134  }
135}
136
137#[allow(dead_code)]
138#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
139pub struct LayerProofBatched<F: PrimeField> {
140  pub proof: SumcheckInstanceProof<F>,
141  pub claims_prod_left: Vec<F>,
142  pub claims_prod_right: Vec<F>,
143}
144
145#[allow(dead_code)]
146impl<F: PrimeField + Absorb> LayerProofBatched<F> {
147  pub fn verify(
148    &self,
149    claim: F,
150    num_rounds: usize,
151    degree_bound: usize,
152    transcript: &mut PoseidonTranscript<F>,
153  ) -> (F, Vec<F>) {
154    self
155      .proof
156      .verify(claim, num_rounds, degree_bound, transcript)
157      .unwrap()
158  }
159}
160
161#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
162pub struct ProductCircuitEvalProof<F: PrimeField> {
163  proof: Vec<LayerProof<F>>,
164}
165
166#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
167pub struct ProductCircuitEvalProofBatched<F: PrimeField> {
168  proof: Vec<LayerProofBatched<F>>,
169  claims_dotp: (Vec<F>, Vec<F>, Vec<F>),
170}
171
172impl<F: PrimeField + Absorb> ProductCircuitEvalProof<F> {
173  #![allow(dead_code)]
174  pub fn prove(
175    circuit: &mut ProductCircuit<F>,
176    transcript: &mut PoseidonTranscript<F>,
177  ) -> (Self, F, Vec<F>) {
178    let mut proof: Vec<LayerProof<F>> = Vec::new();
179    let num_layers = circuit.left_vec.len();
180
181    let mut claim = circuit.evaluate();
182    let mut rand = Vec::new();
183    for layer_id in (0..num_layers).rev() {
184      let len = circuit.left_vec[layer_id].len() + circuit.right_vec[layer_id].len();
185
186      let mut poly_C = DensePolynomial::new(EqPolynomial::new(rand.clone()).evals());
187      assert_eq!(poly_C.len(), len / 2);
188
189      let num_rounds_prod = poly_C.len().log_2();
190      let comb_func_prod = |poly_A_comp: &F, poly_B_comp: &F, poly_C_comp: &F| -> F {
191        (*poly_A_comp) * poly_B_comp * poly_C_comp
192      };
193      let (proof_prod, rand_prod, claims_prod) = SumcheckInstanceProof::prove_cubic(
194        &claim,
195        num_rounds_prod,
196        &mut circuit.left_vec[layer_id],
197        &mut circuit.right_vec[layer_id],
198        &mut poly_C,
199        comb_func_prod,
200        transcript,
201      );
202
203      transcript.append_scalar(b"", &claims_prod[0]);
204      transcript.append_scalar(b"", &claims_prod[1]);
205
206      // produce a random challenge
207      let r_layer = transcript.challenge_scalar(b"");
208      claim = claims_prod[0] + r_layer * (claims_prod[1] - claims_prod[0]);
209
210      let mut ext = vec![r_layer];
211      ext.extend(rand_prod);
212      rand = ext;
213
214      proof.push(LayerProof {
215        proof: proof_prod,
216        claims: claims_prod[0..claims_prod.len() - 1].to_vec(),
217      });
218    }
219
220    (ProductCircuitEvalProof { proof }, claim, rand)
221  }
222
223  pub fn verify(&self, eval: F, len: usize, transcript: &mut PoseidonTranscript<F>) -> (F, Vec<F>) {
224    let num_layers = len.log_2();
225    let mut claim = eval;
226    let mut rand: Vec<F> = Vec::new();
227    //let mut num_rounds = 0;
228    assert_eq!(self.proof.len(), num_layers);
229    for (num_rounds, i) in (0..num_layers).enumerate() {
230      let (claim_last, rand_prod) = self.proof[i].verify(claim, num_rounds, 3, transcript);
231
232      let claims_prod = &self.proof[i].claims;
233      transcript.append_scalar(b"", &claims_prod[0]);
234      transcript.append_scalar(b"", &claims_prod[1]);
235
236      assert_eq!(rand.len(), rand_prod.len());
237      let eq: F = (0..rand.len())
238        .map(|i| rand[i] * rand_prod[i] + (F::one() - rand[i]) * (F::one() - rand_prod[i]))
239        .product();
240      assert_eq!(claims_prod[0] * claims_prod[1] * eq, claim_last);
241
242      // produce a random challenge
243      let r_layer = transcript.challenge_scalar(b"");
244      claim = (F::one() - r_layer) * claims_prod[0] + r_layer * claims_prod[1];
245      let mut ext = vec![r_layer];
246      ext.extend(rand_prod);
247      rand = ext;
248    }
249
250    (claim, rand)
251  }
252}
253
254impl<F: PrimeField + Absorb> ProductCircuitEvalProofBatched<F> {
255  pub fn prove(
256    prod_circuit_vec: &mut Vec<&mut ProductCircuit<F>>,
257    dotp_circuit_vec: &mut Vec<&mut DotProductCircuit<F>>,
258    transcript: &mut PoseidonTranscript<F>,
259  ) -> (Self, Vec<F>) {
260    assert!(!prod_circuit_vec.is_empty());
261
262    let mut claims_dotp_final = (Vec::new(), Vec::new(), Vec::new());
263
264    let mut proof_layers: Vec<LayerProofBatched<F>> = Vec::new();
265    let num_layers = prod_circuit_vec[0].left_vec.len();
266    let mut claims_to_verify = (0..prod_circuit_vec.len())
267      .map(|i| prod_circuit_vec[i].evaluate())
268      .collect::<Vec<F>>();
269    let mut rand = Vec::new();
270    for layer_id in (0..num_layers).rev() {
271      // prepare paralell instance that share poly_C first
272      let len = prod_circuit_vec[0].left_vec[layer_id].len()
273        + prod_circuit_vec[0].right_vec[layer_id].len();
274
275      let mut poly_C_par = DensePolynomial::new(EqPolynomial::new(rand.clone()).evals());
276      assert_eq!(poly_C_par.len(), len / 2);
277
278      let num_rounds_prod = poly_C_par.len().log_2();
279      let comb_func_prod = |poly_A_comp: &F, poly_B_comp: &F, poly_C_comp: &F| -> F {
280        (*poly_A_comp) * poly_B_comp * poly_C_comp
281      };
282
283      let mut poly_A_batched_par: Vec<&mut DensePolynomial<F>> = Vec::new();
284      let mut poly_B_batched_par: Vec<&mut DensePolynomial<F>> = Vec::new();
285      for prod_circuit in prod_circuit_vec.iter_mut() {
286        poly_A_batched_par.push(&mut prod_circuit.left_vec[layer_id]);
287        poly_B_batched_par.push(&mut prod_circuit.right_vec[layer_id])
288      }
289      let poly_vec_par = (
290        &mut poly_A_batched_par,
291        &mut poly_B_batched_par,
292        &mut poly_C_par,
293      );
294
295      // prepare sequential instances that don't share poly_C
296      let mut poly_A_batched_seq: Vec<&mut DensePolynomial<F>> = Vec::new();
297      let mut poly_B_batched_seq: Vec<&mut DensePolynomial<F>> = Vec::new();
298      let mut poly_C_batched_seq: Vec<&mut DensePolynomial<F>> = Vec::new();
299      if layer_id == 0 && !dotp_circuit_vec.is_empty() {
300        // add additional claims
301        for item in dotp_circuit_vec.iter() {
302          claims_to_verify.push(item.evaluate());
303          assert_eq!(len / 2, item.left.len());
304          assert_eq!(len / 2, item.right.len());
305          assert_eq!(len / 2, item.weight.len());
306        }
307
308        for dotp_circuit in dotp_circuit_vec.iter_mut() {
309          poly_A_batched_seq.push(&mut dotp_circuit.left);
310          poly_B_batched_seq.push(&mut dotp_circuit.right);
311          poly_C_batched_seq.push(&mut dotp_circuit.weight);
312        }
313      }
314      let poly_vec_seq = (
315        &mut poly_A_batched_seq,
316        &mut poly_B_batched_seq,
317        &mut poly_C_batched_seq,
318      );
319
320      // produce a fresh set of coeffs and a joint claim
321      let coeff_vec = transcript.challenge_scalar_vec(b"", claims_to_verify.len());
322      let claim = (0..claims_to_verify.len())
323        .map(|i| claims_to_verify[i] * coeff_vec[i])
324        .sum();
325
326      let (proof, rand_prod, claims_prod, claims_dotp) = SumcheckInstanceProof::prove_cubic_batched(
327        &claim,
328        num_rounds_prod,
329        poly_vec_par,
330        poly_vec_seq,
331        &coeff_vec,
332        comb_func_prod,
333        transcript,
334      );
335
336      let (claims_prod_left, claims_prod_right, _claims_eq) = claims_prod;
337      for i in 0..prod_circuit_vec.len() {
338        transcript.append_scalar(b"", &claims_prod_left[i]);
339        transcript.append_scalar(b"", &claims_prod_right[i]);
340      }
341
342      if layer_id == 0 && !dotp_circuit_vec.is_empty() {
343        let (claims_dotp_left, claims_dotp_right, claims_dotp_weight) = claims_dotp;
344        for i in 0..dotp_circuit_vec.len() {
345          transcript.append_scalar(b"", &claims_dotp_left[i]);
346          transcript.append_scalar(b"", &claims_dotp_right[i]);
347          transcript.append_scalar(b"", &claims_dotp_weight[i]);
348        }
349        claims_dotp_final = (claims_dotp_left, claims_dotp_right, claims_dotp_weight);
350      }
351
352      // produce a random challenge to condense two claims into a single claim
353      let r_layer = transcript.challenge_scalar(b"");
354
355      claims_to_verify = (0..prod_circuit_vec.len())
356        .map(|i| claims_prod_left[i] + r_layer * (claims_prod_right[i] - claims_prod_left[i]))
357        .collect::<Vec<F>>();
358
359      let mut ext = vec![r_layer];
360      ext.extend(rand_prod);
361      rand = ext;
362
363      proof_layers.push(LayerProofBatched {
364        proof,
365        claims_prod_left,
366        claims_prod_right,
367      });
368    }
369
370    (
371      ProductCircuitEvalProofBatched {
372        proof: proof_layers,
373        claims_dotp: claims_dotp_final,
374      },
375      rand,
376    )
377  }
378
379  pub fn verify(
380    &self,
381    claims_prod_vec: &[F],
382    claims_dotp_vec: &[F],
383    len: usize,
384    transcript: &mut PoseidonTranscript<F>,
385  ) -> (Vec<F>, Vec<F>, Vec<F>) {
386    let num_layers = len.log_2();
387    let mut rand: Vec<F> = Vec::new();
388    //let mut num_rounds = 0;
389    assert_eq!(self.proof.len(), num_layers);
390
391    let mut claims_to_verify = claims_prod_vec.to_owned();
392    let mut claims_to_verify_dotp: Vec<F> = Vec::new();
393    for (num_rounds, i) in (0..num_layers).enumerate() {
394      if i == num_layers - 1 {
395        claims_to_verify.extend(claims_dotp_vec);
396      }
397
398      // produce random coefficients, one for each instance
399      let coeff_vec: Vec<F> = transcript.challenge_scalar_vec(b"", claims_to_verify.len());
400
401      // produce a joint claim
402      let claim = (0..claims_to_verify.len())
403        .map(|i| claims_to_verify[i] * coeff_vec[i])
404        .sum();
405
406      let (claim_last, rand_prod) = self.proof[i].verify(claim, num_rounds, 3, transcript);
407
408      let claims_prod_left = &self.proof[i].claims_prod_left;
409      let claims_prod_right = &self.proof[i].claims_prod_right;
410      assert_eq!(claims_prod_left.len(), claims_prod_vec.len());
411      assert_eq!(claims_prod_right.len(), claims_prod_vec.len());
412
413      for i in 0..claims_prod_vec.len() {
414        transcript.append_scalar(b"", &claims_prod_left[i]);
415        transcript.append_scalar(b"", &claims_prod_right[i]);
416      }
417
418      assert_eq!(rand.len(), rand_prod.len());
419      let eq: F = (0..rand.len())
420        .map(|i| rand[i] * rand_prod[i] + (F::one() - rand[i]) * (F::one() - rand_prod[i]))
421        .product();
422      let mut claim_expected: F = (0..claims_prod_vec.len())
423        .map(|i| coeff_vec[i] * (claims_prod_left[i] * claims_prod_right[i] * eq))
424        .sum();
425
426      // add claims from the dotp instances
427      if i == num_layers - 1 {
428        let num_prod_instances = claims_prod_vec.len();
429        let (claims_dotp_left, claims_dotp_right, claims_dotp_weight) = &self.claims_dotp;
430        for i in 0..claims_dotp_left.len() {
431          transcript.append_scalar(b"", &claims_dotp_left[i]);
432          transcript.append_scalar(b"", &claims_dotp_right[i]);
433          transcript.append_scalar(b"", &claims_dotp_weight[i]);
434
435          claim_expected += coeff_vec[i + num_prod_instances]
436            * claims_dotp_left[i]
437            * claims_dotp_right[i]
438            * claims_dotp_weight[i];
439        }
440      }
441
442      assert_eq!(claim_expected, claim_last);
443
444      // produce a random challenge
445      let r_layer = transcript.challenge_scalar(b"");
446
447      claims_to_verify = (0..claims_prod_left.len())
448        .map(|i| claims_prod_left[i] + r_layer * (claims_prod_right[i] - claims_prod_left[i]))
449        .collect();
450
451      // add claims to verify for dotp circuit
452      if i == num_layers - 1 {
453        let (claims_dotp_left, claims_dotp_right, claims_dotp_weight) = &self.claims_dotp;
454
455        for i in 0..claims_dotp_vec.len() / 2 {
456          // combine left claims
457          let claim_left = claims_dotp_left[2 * i]
458            + r_layer * (claims_dotp_left[2 * i + 1] - claims_dotp_left[2 * i]);
459
460          let claim_right = claims_dotp_right[2 * i]
461            + r_layer * (claims_dotp_right[2 * i + 1] - claims_dotp_right[2 * i]);
462
463          let claim_weight = claims_dotp_weight[2 * i]
464            + r_layer * (claims_dotp_weight[2 * i + 1] - claims_dotp_weight[2 * i]);
465          claims_to_verify_dotp.push(claim_left);
466          claims_to_verify_dotp.push(claim_right);
467          claims_to_verify_dotp.push(claim_weight);
468        }
469      }
470
471      let mut ext = vec![r_layer];
472      ext.extend(rand_prod);
473      rand = ext;
474    }
475    (claims_to_verify, claims_to_verify_dotp, rand)
476  }
477}