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) =
 49                ProductCircuit::compute_layer(&left_vec[i], &right_vec[i]);
 50            left_vec.push(outp_left);
 51            right_vec.push(outp_right);
 52        }
 53
 54        ProductCircuit {
 55            left_vec,
 56            right_vec,
 57        }
 58    }
 59
 60    pub fn evaluate(&self) -> Scalar {
 61        let len = self.left_vec.len();
 62        assert_eq!(self.left_vec[len - 1].get_num_vars(), 0);
 63        assert_eq!(self.right_vec[len - 1].get_num_vars(), 0);
 64        self.left_vec[len - 1][0] * self.right_vec[len - 1][0]
 65    }
 66}
 67
 68pub struct DotProductCircuit {
 69    left: DensePolynomial,
 70    right: DensePolynomial,
 71    weight: DensePolynomial,
 72}
 73
 74impl DotProductCircuit {
 75    pub fn new(left: DensePolynomial, right: DensePolynomial, weight: DensePolynomial) -> Self {
 76        assert_eq!(left.len(), right.len());
 77        assert_eq!(left.len(), weight.len());
 78        DotProductCircuit {
 79            left,
 80            right,
 81            weight,
 82        }
 83    }
 84
 85    pub fn evaluate(&self) -> Scalar {
 86        (0..self.left.len())
 87            .map(|i| self.left[i] * self.right[i] * self.weight[i])
 88            .sum()
 89    }
 90
 91    pub fn split(&mut self) -> (DotProductCircuit, DotProductCircuit) {
 92        let idx = self.left.len() / 2;
 93        assert_eq!(idx * 2, self.left.len());
 94        let (l1, l2) = self.left.split(idx);
 95        let (r1, r2) = self.right.split(idx);
 96        let (w1, w2) = self.weight.split(idx);
 97        (
 98            DotProductCircuit {
 99                left: l1,
100                right: r1,
101                weight: w1,
102            },
103            DotProductCircuit {
104                left: l2,
105                right: r2,
106                weight: w2,
107            },
108        )
109    }
110}
111
112#[allow(dead_code)]
113#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
114pub struct LayerProof {
115    pub proof: SumcheckInstanceProof,
116    pub claims: Vec<Scalar>,
117}
118
119#[allow(dead_code)]
120impl LayerProof {
121    pub fn verify(
122        &self,
123        claim: Scalar,
124        num_rounds: usize,
125        degree_bound: usize,
126        transcript: &mut PoseidonTranscript,
127    ) -> (Scalar, Vec<Scalar>) {
128        self.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.proof
152            .verify(claim, num_rounds, degree_bound, transcript)
153            .unwrap()
154    }
155}
156
157#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
158pub struct ProductCircuitEvalProof {
159    proof: Vec<LayerProof>,
160}
161
162#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
163pub struct ProductCircuitEvalProofBatched {
164    proof: Vec<LayerProofBatched>,
165    claims_dotp: (Vec<Scalar>, Vec<Scalar>, Vec<Scalar>),
166}
167
168impl ProductCircuitEvalProof {
169    #![allow(dead_code)]
170    pub fn prove(
171        circuit: &mut ProductCircuit,
172        transcript: &mut PoseidonTranscript,
173    ) -> (Self, Scalar, Vec<Scalar>) {
174        let mut proof: Vec<LayerProof> = Vec::new();
175        let num_layers = circuit.left_vec.len();
176
177        let mut claim = circuit.evaluate();
178        let mut rand = Vec::new();
179        for layer_id in (0..num_layers).rev() {
180            let len = circuit.left_vec[layer_id].len() + circuit.right_vec[layer_id].len();
181
182            let mut poly_C = DensePolynomial::new(EqPolynomial::new(rand.clone()).evals());
183            assert_eq!(poly_C.len(), len / 2);
184
185            let num_rounds_prod = poly_C.len().log_2();
186            let comb_func_prod =
187                |poly_A_comp: &Scalar, poly_B_comp: &Scalar, poly_C_comp: &Scalar| -> Scalar {
188                    (*poly_A_comp) * poly_B_comp * poly_C_comp
189                };
190            let (proof_prod, rand_prod, claims_prod) = SumcheckInstanceProof::prove_cubic(
191                &claim,
192                num_rounds_prod,
193                &mut circuit.left_vec[layer_id],
194                &mut circuit.right_vec[layer_id],
195                &mut poly_C,
196                comb_func_prod,
197                transcript,
198            );
199
200            transcript.append_scalar(&claims_prod[0]);
201            transcript.append_scalar(&claims_prod[1]);
202
203            // produce a random challenge
204            let r_layer = transcript.challenge_scalar();
205            claim = claims_prod[0] + r_layer * (claims_prod[1] - claims_prod[0]);
206
207            let mut ext = vec![r_layer];
208            ext.extend(rand_prod);
209            rand = ext;
210
211            proof.push(LayerProof {
212                proof: proof_prod,
213                claims: claims_prod[0..claims_prod.len() - 1].to_vec(),
214            });
215        }
216
217        (ProductCircuitEvalProof { proof }, claim, rand)
218    }
219
220    pub fn verify(
221        &self,
222        eval: Scalar,
223        len: usize,
224        transcript: &mut PoseidonTranscript,
225    ) -> (Scalar, Vec<Scalar>) {
226        let num_layers = len.log_2();
227        let mut claim = eval;
228        let mut rand: Vec<Scalar> = Vec::new();
229        //let mut num_rounds = 0;
230        assert_eq!(self.proof.len(), num_layers);
231        for (num_rounds, i) in (0..num_layers).enumerate() {
232            let (claim_last, rand_prod) = self.proof[i].verify(claim, num_rounds, 3, transcript);
233
234            let claims_prod = &self.proof[i].claims;
235            transcript.append_scalar(&claims_prod[0]);
236            transcript.append_scalar(&claims_prod[1]);
237
238            assert_eq!(rand.len(), rand_prod.len());
239            let eq: Scalar = (0..rand.len())
240                .map(|i| {
241                    rand[i] * rand_prod[i]
242                        + (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 =
285                |poly_A_comp: &Scalar, poly_B_comp: &Scalar, poly_C_comp: &Scalar| -> Scalar {
286                    (*poly_A_comp) * poly_B_comp * poly_C_comp
287                };
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) =
333                SumcheckInstanceProof::prove_cubic_batched(
334                    &claim,
335                    num_rounds_prod,
336                    poly_vec_par,
337                    poly_vec_seq,
338                    &coeff_vec,
339                    comb_func_prod,
340                    transcript,
341                );
342
343            let (claims_prod_left, claims_prod_right, _claims_eq) = claims_prod;
344            for i in 0..prod_circuit_vec.len() {
345                transcript.append_scalar(&claims_prod_left[i]);
346                transcript.append_scalar(&claims_prod_right[i]);
347            }
348
349            if layer_id == 0 && !dotp_circuit_vec.is_empty() {
350                let (claims_dotp_left, claims_dotp_right, claims_dotp_weight) = claims_dotp;
351                for i in 0..dotp_circuit_vec.len() {
352                    transcript.append_scalar(&claims_dotp_left[i]);
353                    transcript.append_scalar(&claims_dotp_right[i]);
354                    transcript.append_scalar(&claims_dotp_weight[i]);
355                }
356                claims_dotp_final = (claims_dotp_left, claims_dotp_right, claims_dotp_weight);
357            }
358
359            // produce a random challenge to condense two claims into a single claim
360            let r_layer = transcript.challenge_scalar();
361
362            claims_to_verify = (0..prod_circuit_vec.len())
363                .map(|i| {
364                    claims_prod_left[i] + r_layer * (claims_prod_right[i] - claims_prod_left[i])
365                })
366                .collect::<Vec<Scalar>>();
367
368            let mut ext = vec![r_layer];
369            ext.extend(rand_prod);
370            rand = ext;
371
372            proof_layers.push(LayerProofBatched {
373                proof,
374                claims_prod_left,
375                claims_prod_right,
376            });
377        }
378
379        (
380            ProductCircuitEvalProofBatched {
381                proof: proof_layers,
382                claims_dotp: claims_dotp_final,
383            },
384            rand,
385        )
386    }
387
388    pub fn verify(
389        &self,
390        claims_prod_vec: &[Scalar],
391        claims_dotp_vec: &[Scalar],
392        len: usize,
393        transcript: &mut PoseidonTranscript,
394    ) -> (Vec<Scalar>, Vec<Scalar>, Vec<Scalar>) {
395        let num_layers = len.log_2();
396        let mut rand: Vec<Scalar> = Vec::new();
397        //let mut num_rounds = 0;
398        assert_eq!(self.proof.len(), num_layers);
399
400        let mut claims_to_verify = claims_prod_vec.to_owned();
401        let mut claims_to_verify_dotp: Vec<Scalar> = Vec::new();
402        for (num_rounds, i) in (0..num_layers).enumerate() {
403            if i == num_layers - 1 {
404                claims_to_verify.extend(claims_dotp_vec);
405            }
406
407            // produce random coefficients, one for each instance
408            let coeff_vec = transcript.challenge_vector(claims_to_verify.len());
409
410            // produce a joint claim
411            let claim = (0..claims_to_verify.len())
412                .map(|i| claims_to_verify[i] * coeff_vec[i])
413                .sum();
414
415            let (claim_last, rand_prod) = self.proof[i].verify(claim, num_rounds, 3, transcript);
416
417            let claims_prod_left = &self.proof[i].claims_prod_left;
418            let claims_prod_right = &self.proof[i].claims_prod_right;
419            assert_eq!(claims_prod_left.len(), claims_prod_vec.len());
420            assert_eq!(claims_prod_right.len(), claims_prod_vec.len());
421
422            for i in 0..claims_prod_vec.len() {
423                transcript.append_scalar(&claims_prod_left[i]);
424                transcript.append_scalar(&claims_prod_right[i]);
425            }
426
427            assert_eq!(rand.len(), rand_prod.len());
428            let eq: Scalar = (0..rand.len())
429                .map(|i| {
430                    rand[i] * rand_prod[i]
431                        + (Scalar::one() - rand[i]) * (Scalar::one() - rand_prod[i])
432                })
433                .product();
434            let mut claim_expected: Scalar = (0..claims_prod_vec.len())
435                .map(|i| coeff_vec[i] * (claims_prod_left[i] * claims_prod_right[i] * eq))
436                .sum();
437
438            // add claims from the dotp instances
439            if i == num_layers - 1 {
440                let num_prod_instances = claims_prod_vec.len();
441                let (claims_dotp_left, claims_dotp_right, claims_dotp_weight) = &self.claims_dotp;
442                for i in 0..claims_dotp_left.len() {
443                    transcript.append_scalar(&claims_dotp_left[i]);
444                    transcript.append_scalar(&claims_dotp_right[i]);
445                    transcript.append_scalar(&claims_dotp_weight[i]);
446
447                    claim_expected += coeff_vec[i + num_prod_instances]
448                        * claims_dotp_left[i]
449                        * claims_dotp_right[i]
450                        * claims_dotp_weight[i];
451                }
452            }
453
454            assert_eq!(claim_expected, claim_last);
455
456            // produce a random challenge
457            let r_layer = transcript.challenge_scalar();
458
459            claims_to_verify = (0..claims_prod_left.len())
460                .map(|i| {
461                    claims_prod_left[i] + r_layer * (claims_prod_right[i] - claims_prod_left[i])
462                })
463                .collect();
464
465            // add claims to verify for dotp circuit
466            if i == num_layers - 1 {
467                let (claims_dotp_left, claims_dotp_right, claims_dotp_weight) = &self.claims_dotp;
468
469                for i in 0..claims_dotp_vec.len() / 2 {
470                    // combine left claims
471                    let claim_left = claims_dotp_left[2 * i]
472                        + r_layer * (claims_dotp_left[2 * i + 1] - claims_dotp_left[2 * i]);
473
474                    let claim_right = claims_dotp_right[2 * i]
475                        + r_layer * (claims_dotp_right[2 * i + 1] - claims_dotp_right[2 * i]);
476
477                    let claim_weight = claims_dotp_weight[2 * i]
478                        + r_layer * (claims_dotp_weight[2 * i + 1] - claims_dotp_weight[2 * i]);
479                    claims_to_verify_dotp.push(claim_left);
480                    claims_to_verify_dotp.push(claim_right);
481                    claims_to_verify_dotp.push(claim_weight);
482                }
483            }
484
485            let mut ext = vec![r_layer];
486            ext.extend(rand_prod);
487            rand = ext;
488        }
489        (claims_to_verify, claims_to_verify_dotp, rand)
490    }
491}