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