arnaucube
arnaucube/testudoPublic Self-hosted repository
testudo/src/r1csproof.rs
src/r1csproof.rsRaw
  1use super::commitments::{Commitments, MultiCommitGens};
  2use super::dense_mlpoly::{
  3  DensePolynomial, EqPolynomial, PolyCommitment, PolyCommitmentGens, PolyEvalProof,
  4};
  5use super::errors::ProofVerifyError;
  6use super::group::{CompressedGroup, GroupElement, VartimeMultiscalarMul};
  7use super::math::Math;
  8use super::nizk::{EqualityProof, KnowledgeProof, ProductProof};
  9use super::r1csinstance::{R1CSInstance, R1CSInstanceEvals};
 10use super::scalar::Scalar;
 11use super::sparse_mlpoly::{SparsePolyEntry, SparsePolynomial};
 12use super::sumcheck::ZKSumcheckInstanceProof;
 13use super::timer::Timer;
 14use super::transcript::{AppendToTranscript, ProofTranscript};
 15use merlin::Transcript;
 16use serde::{Deserialize, Serialize};
 17use std::iter;
 18
 19#[cfg(test)]
 20use super::sparse_mlpoly::{SparseMatEntry, SparseMatPolynomial};
 21
 22#[derive(Serialize, Deserialize, Debug)]
 23pub struct R1CSProof {
 24  comm_vars: PolyCommitment,
 25  sc_proof_phase1: ZKSumcheckInstanceProof,
 26  claims_phase2: (
 27    CompressedGroup,
 28    CompressedGroup,
 29    CompressedGroup,
 30    CompressedGroup,
 31  ),
 32  pok_claims_phase2: (KnowledgeProof, ProductProof),
 33  proof_eq_sc_phase1: EqualityProof,
 34  sc_proof_phase2: ZKSumcheckInstanceProof,
 35  comm_vars_at_ry: CompressedGroup,
 36  proof_eval_vars_at_ry: PolyEvalProof,
 37  proof_eq_sc_phase2: EqualityProof,
 38}
 39
 40pub struct R1CSSumcheckGens {
 41  gens_1: MultiCommitGens,
 42  gens_3: MultiCommitGens,
 43  gens_4: MultiCommitGens,
 44}
 45
 46// TODO: fix passing gens_1_ref
 47impl R1CSSumcheckGens {
 48  pub fn new(label: &'static [u8], gens_1_ref: &MultiCommitGens) -> Self {
 49    let gens_1 = gens_1_ref.clone();
 50    let gens_3 = MultiCommitGens::new(3, label);
 51    let gens_4 = MultiCommitGens::new(4, label);
 52
 53    R1CSSumcheckGens {
 54      gens_1,
 55      gens_3,
 56      gens_4,
 57    }
 58  }
 59}
 60
 61pub struct R1CSGens {
 62  gens_sc: R1CSSumcheckGens,
 63  gens_pc: PolyCommitmentGens,
 64}
 65
 66impl R1CSGens {
 67  pub fn new(_num_cons: usize, num_vars: usize, label: &'static [u8]) -> Self {
 68    let num_poly_vars = num_vars.log2();
 69    let gens_pc = PolyCommitmentGens::new(num_poly_vars, label);
 70    let gens_sc = R1CSSumcheckGens::new(label, &gens_pc.gens.gens_1);
 71    R1CSGens { gens_sc, gens_pc }
 72  }
 73}
 74
 75impl R1CSProof {
 76  fn prove_phase_one(
 77    num_rounds: usize,
 78    evals_tau: &mut DensePolynomial,
 79    evals_Az: &mut DensePolynomial,
 80    evals_Bz: &mut DensePolynomial,
 81    evals_Cz: &mut DensePolynomial,
 82    gens: &R1CSSumcheckGens,
 83    transcript: &mut Transcript,
 84    random_tape: &mut Transcript,
 85  ) -> (ZKSumcheckInstanceProof, Vec<Scalar>, Vec<Scalar>, Scalar) {
 86    let comb_func = |poly_A_comp: &Scalar,
 87                     poly_B_comp: &Scalar,
 88                     poly_C_comp: &Scalar,
 89                     poly_D_comp: &Scalar|
 90     -> Scalar { poly_A_comp * (poly_B_comp * poly_C_comp - poly_D_comp) };
 91
 92    let (sc_proof_phase_one, r, claims, blind_claim_postsc) =
 93      ZKSumcheckInstanceProof::prove_cubic_with_additive_term(
 94        &Scalar::zero(), // claim is zero
 95        &Scalar::zero(), // blind for claim is also zero
 96        num_rounds,
 97        evals_tau,
 98        evals_Az,
 99        evals_Bz,
100        evals_Cz,
101        comb_func,
102        &gens.gens_1,
103        &gens.gens_4,
104        transcript,
105        random_tape,
106      );
107
108    (sc_proof_phase_one, r, claims, blind_claim_postsc)
109  }
110
111  fn prove_phase_two(
112    num_rounds: usize,
113    claim: &Scalar,
114    blind_claim: &Scalar,
115    evals_z: &mut DensePolynomial,
116    evals_ABC: &mut DensePolynomial,
117    gens: &R1CSSumcheckGens,
118    transcript: &mut Transcript,
119    random_tape: &mut Transcript,
120  ) -> (ZKSumcheckInstanceProof, Vec<Scalar>, Vec<Scalar>, Scalar) {
121    let comb_func =
122      |poly_A_comp: &Scalar, poly_B_comp: &Scalar| -> Scalar { poly_A_comp * poly_B_comp };
123    let (sc_proof_phase_two, r, claims, blind_claim_postsc) = ZKSumcheckInstanceProof::prove_quad(
124      claim,
125      blind_claim,
126      num_rounds,
127      evals_z,
128      evals_ABC,
129      comb_func,
130      &gens.gens_1,
131      &gens.gens_3,
132      transcript,
133      random_tape,
134    );
135
136    (sc_proof_phase_two, r, claims, blind_claim_postsc)
137  }
138
139  fn protocol_name() -> &'static [u8] {
140    b"R1CS proof"
141  }
142
143  pub fn prove(
144    inst: &R1CSInstance,
145    vars: Vec<Scalar>,
146    input: &Vec<Scalar>,
147    gens: &R1CSGens,
148    transcript: &mut Transcript,
149    random_tape: &mut Transcript,
150  ) -> (R1CSProof, Vec<Scalar>, Vec<Scalar>) {
151    let timer_prove = Timer::new("R1CSProof::prove");
152    transcript.append_protocol_name(R1CSProof::protocol_name());
153
154    // we currently require the number of |inputs| + 1 to be at most number of vars
155    assert!(input.len() + 1 <= vars.len());
156
157    let timer_commit = Timer::new("polycommit");
158    let (poly_vars, comm_vars, blinds_vars) = {
159      // create a multilinear polynomial using the supplied assignment for variables
160      let poly_vars = DensePolynomial::new(vars.clone());
161
162      // produce a commitment to the satisfying assignment
163      let (comm_vars, blinds_vars) = poly_vars.commit(true, &gens.gens_pc, Some(random_tape));
164
165      // add the commitment to the prover's transcript
166      comm_vars.append_to_transcript(b"poly_commitment", transcript);
167      (poly_vars, comm_vars, blinds_vars)
168    };
169    timer_commit.stop();
170
171    let timer_sc_proof_phase1 = Timer::new("prove_sc_phase_one");
172
173    // append input to variables to create a single vector z
174    let z = {
175      let num_inputs = input.len();
176      let num_vars = vars.len();
177      let mut z = vars;
178      z.extend(&vec![Scalar::one()]); // add constant term in z
179      z.extend(input);
180      z.extend(&vec![Scalar::zero(); num_vars - num_inputs - 1]); // we will pad with zeros
181      z
182    };
183
184    // derive the verifier's challenge tau
185    let (num_rounds_x, num_rounds_y) = (inst.get_num_cons().log2(), z.len().log2());
186    let tau = transcript.challenge_vector(b"challenge_tau", num_rounds_x);
187    // compute the initial evaluation table for R(\tau, x)
188    let mut poly_tau = DensePolynomial::new(EqPolynomial::new(tau.clone()).evals());
189    let (mut poly_Az, mut poly_Bz, mut poly_Cz) =
190      inst.multiply_vec(inst.get_num_cons(), z.len(), &z);
191
192    let (sc_proof_phase1, rx, _claims_phase1, blind_claim_postsc1) = R1CSProof::prove_phase_one(
193      num_rounds_x,
194      &mut poly_tau,
195      &mut poly_Az,
196      &mut poly_Bz,
197      &mut poly_Cz,
198      &gens.gens_sc,
199      transcript,
200      random_tape,
201    );
202    assert_eq!(poly_tau.len(), 1);
203    assert_eq!(poly_Az.len(), 1);
204    assert_eq!(poly_Bz.len(), 1);
205    assert_eq!(poly_Cz.len(), 1);
206    timer_sc_proof_phase1.stop();
207
208    let (tau_claim, Az_claim, Bz_claim, Cz_claim) =
209      (&poly_tau[0], &poly_Az[0], &poly_Bz[0], &poly_Cz[0]);
210    let (Az_blind, Bz_blind, Cz_blind, prod_Az_Bz_blind) = (
211      random_tape.challenge_scalar(b"Az_blind"),
212      random_tape.challenge_scalar(b"Bz_blind"),
213      random_tape.challenge_scalar(b"Cz_blind"),
214      random_tape.challenge_scalar(b"prod_Az_Bz_blind"),
215    );
216
217    let (pok_Cz_claim, comm_Cz_claim) = {
218      KnowledgeProof::prove(
219        &gens.gens_sc.gens_1,
220        transcript,
221        random_tape,
222        &Cz_claim,
223        &Cz_blind,
224      )
225    };
226
227    let (proof_prod, comm_Az_claim, comm_Bz_claim, comm_prod_Az_Bz_claims) = {
228      let prod = Az_claim * Bz_claim;
229      ProductProof::prove(
230        &gens.gens_sc.gens_1,
231        transcript,
232        random_tape,
233        &Az_claim,
234        &Az_blind,
235        &Bz_claim,
236        &Bz_blind,
237        &prod,
238        &prod_Az_Bz_blind,
239      )
240    };
241
242    comm_Az_claim.append_to_transcript(b"comm_Az_claim", transcript);
243    comm_Bz_claim.append_to_transcript(b"comm_Bz_claim", transcript);
244    comm_Cz_claim.append_to_transcript(b"comm_Cz_claim", transcript);
245    comm_prod_Az_Bz_claims.append_to_transcript(b"comm_prod_Az_Bz_claims", transcript);
246
247    // prove the final step of sum-check #1
248    let taus_bound_rx = tau_claim;
249    let blind_expected_claim_postsc1 = taus_bound_rx * (&prod_Az_Bz_blind - &Cz_blind);
250    let claim_post_phase1 = (Az_claim * Bz_claim - Cz_claim) * taus_bound_rx;
251    let (proof_eq_sc_phase1, _C1, _C2) = EqualityProof::prove(
252      &gens.gens_sc.gens_1,
253      transcript,
254      random_tape,
255      &claim_post_phase1,
256      &blind_expected_claim_postsc1,
257      &claim_post_phase1,
258      &blind_claim_postsc1,
259    );
260
261    let timer_sc_proof_phase2 = Timer::new("prove_sc_phase_two");
262    // combine the three claims into a single claim
263    let r_A = transcript.challenge_scalar(b"challenege_Az");
264    let r_B = transcript.challenge_scalar(b"challenege_Bz");
265    let r_C = transcript.challenge_scalar(b"challenege_Cz");
266    let claim_phase2 = &r_A * Az_claim + &r_B * Bz_claim + &r_C * Cz_claim;
267    let blind_claim_phase2 = &r_A * Az_blind + &r_B * Bz_blind + &r_C * Cz_blind;
268
269    let evals_ABC = {
270      // compute the initial evaluation table for R(\tau, x)
271      let evals_rx = EqPolynomial::new(rx.clone()).evals();
272      let (evals_A, evals_B, evals_C) =
273        inst.compute_eval_table_sparse(inst.get_num_cons(), z.len(), &evals_rx);
274
275      assert_eq!(evals_A.len(), evals_B.len());
276      assert_eq!(evals_A.len(), evals_C.len());
277      (0..evals_A.len())
278        .map(|i| &r_A * &evals_A[i] + &r_B * &evals_B[i] + &r_C * &evals_C[i])
279        .collect::<Vec<Scalar>>()
280    };
281
282    // another instance of the sum-check protocol
283    let (sc_proof_phase2, ry, claims_phase2, blind_claim_postsc2) = R1CSProof::prove_phase_two(
284      num_rounds_y,
285      &claim_phase2,
286      &blind_claim_phase2,
287      &mut DensePolynomial::new(z),
288      &mut DensePolynomial::new(evals_ABC),
289      &gens.gens_sc,
290      transcript,
291      random_tape,
292    );
293    timer_sc_proof_phase2.stop();
294
295    let timer_polyeval = Timer::new("polyeval");
296    let eval_vars_at_ry = poly_vars.evaluate(&ry[1..].to_vec());
297    let blind_eval = random_tape.challenge_scalar(b"blind_eval");
298    let (proof_eval_vars_at_ry, comm_vars_at_ry) = PolyEvalProof::prove(
299      &poly_vars,
300      Some(&blinds_vars),
301      &ry[1..].to_vec(),
302      &eval_vars_at_ry,
303      Some(&blind_eval),
304      &gens.gens_pc,
305      transcript,
306      random_tape,
307    );
308    timer_polyeval.stop();
309
310    // prove the final step of sum-check #2
311    let blind_eval_Z_at_ry = (Scalar::one() - &ry[0]) * blind_eval;
312    let blind_expected_claim_postsc2 = &claims_phase2[1] * &blind_eval_Z_at_ry;
313    let claim_post_phase2 = &claims_phase2[0] * &claims_phase2[1];
314    let (proof_eq_sc_phase2, _C1, _C2) = EqualityProof::prove(
315      &gens.gens_pc.gens.gens_1,
316      transcript,
317      random_tape,
318      &claim_post_phase2,
319      &blind_expected_claim_postsc2,
320      &claim_post_phase2,
321      &blind_claim_postsc2,
322    );
323
324    timer_prove.stop();
325
326    (
327      R1CSProof {
328        comm_vars,
329        sc_proof_phase1,
330        claims_phase2: (
331          comm_Az_claim,
332          comm_Bz_claim,
333          comm_Cz_claim,
334          comm_prod_Az_Bz_claims,
335        ),
336        pok_claims_phase2: (pok_Cz_claim, proof_prod),
337        proof_eq_sc_phase1,
338        sc_proof_phase2,
339        comm_vars_at_ry,
340        proof_eval_vars_at_ry,
341        proof_eq_sc_phase2,
342      },
343      rx,
344      ry,
345    )
346  }
347
348  pub fn verify(
349    &self,
350    num_vars: usize,
351    num_cons: usize,
352    input: &Vec<Scalar>,
353    evals: &R1CSInstanceEvals,
354    transcript: &mut Transcript,
355    gens: &R1CSGens,
356  ) -> Result<(Vec<Scalar>, Vec<Scalar>), ProofVerifyError> {
357    transcript.append_protocol_name(R1CSProof::protocol_name());
358
359    let n = num_vars;
360    // add the commitment to the verifier's transcript
361    self
362      .comm_vars
363      .append_to_transcript(b"poly_commitment", transcript);
364
365    let (num_rounds_x, num_rounds_y) = (num_cons.log2(), (2 * num_vars).log2());
366
367    // derive the verifier's challenge tau
368    let tau = transcript.challenge_vector(b"challenge_tau", num_rounds_x);
369
370    // verify the first sum-check instance
371    let claim_phase1 = Scalar::zero()
372      .commit(&Scalar::zero(), &gens.gens_sc.gens_1)
373      .compress();
374    let (comm_claim_post_phase1, rx) = self
375      .sc_proof_phase1
376      .verify(
377        &claim_phase1,
378        num_rounds_x,
379        3,
380        &gens.gens_sc.gens_1,
381        &gens.gens_sc.gens_4,
382        transcript,
383      )
384      .unwrap();
385
386    // perform the intermediate sum-check test with claimed Az, Bz, and Cz
387    let (comm_Az_claim, comm_Bz_claim, comm_Cz_claim, comm_prod_Az_Bz_claims) = &self.claims_phase2;
388    let (pok_Cz_claim, proof_prod) = &self.pok_claims_phase2;
389
390    assert!(pok_Cz_claim
391      .verify(&gens.gens_sc.gens_1, transcript, &comm_Cz_claim)
392      .is_ok());
393    assert!(proof_prod
394      .verify(
395        &gens.gens_sc.gens_1,
396        transcript,
397        &comm_Az_claim,
398        &comm_Bz_claim,
399        &comm_prod_Az_Bz_claims
400      )
401      .is_ok());
402
403    comm_Az_claim.append_to_transcript(b"comm_Az_claim", transcript);
404    comm_Bz_claim.append_to_transcript(b"comm_Bz_claim", transcript);
405    comm_Cz_claim.append_to_transcript(b"comm_Cz_claim", transcript);
406    comm_prod_Az_Bz_claims.append_to_transcript(b"comm_prod_Az_Bz_claims", transcript);
407
408    let taus_bound_rx: Scalar = (0..rx.len())
409      .map(|i| &rx[i] * &tau[i] + (&Scalar::one() - &rx[i]) * (&Scalar::one() - &tau[i]))
410      .product();
411    let expected_claim_post_phase1 = (&taus_bound_rx
412      * (comm_prod_Az_Bz_claims.decompress().unwrap() - comm_Cz_claim.decompress().unwrap()))
413    .compress();
414
415    // verify proof that expected_claim_post_phase1 == claim_post_phase1
416    assert!(self
417      .proof_eq_sc_phase1
418      .verify(
419        &gens.gens_sc.gens_1,
420        transcript,
421        &expected_claim_post_phase1,
422        &comm_claim_post_phase1,
423      )
424      .is_ok());
425
426    // derive three public challenges and then derive a joint claim
427    let r_A = transcript.challenge_scalar(b"challenege_Az");
428    let r_B = transcript.challenge_scalar(b"challenege_Bz");
429    let r_C = transcript.challenge_scalar(b"challenege_Cz");
430
431    // r_A * comm_Az_claim + r_B * comm_Bz_claim + r_C * comm_Cz_claim;
432    let comm_claim_phase2 = GroupElement::vartime_multiscalar_mul(
433      iter::once(&r_A)
434        .chain(iter::once(&r_B))
435        .chain(iter::once(&r_C)),
436      iter::once(&comm_Az_claim)
437        .chain(iter::once(&comm_Bz_claim))
438        .chain(iter::once(&comm_Cz_claim))
439        .map(|pt| pt.decompress().unwrap())
440        .collect::<Vec<GroupElement>>(),
441    )
442    .compress();
443
444    // verify the joint claim with a sum-check protocol
445    let (comm_claim_post_phase2, ry) = self
446      .sc_proof_phase2
447      .verify(
448        &comm_claim_phase2,
449        num_rounds_y,
450        2,
451        &gens.gens_sc.gens_1,
452        &gens.gens_sc.gens_3,
453        transcript,
454      )
455      .unwrap();
456
457    // verify Z(ry) proof against the initial commitment
458    assert!(self
459      .proof_eval_vars_at_ry
460      .verify(
461        &gens.gens_pc,
462        transcript,
463        &ry[1..].to_vec(),
464        &self.comm_vars_at_ry,
465        &self.comm_vars
466      )
467      .is_ok());
468
469    let poly_input_eval = {
470      // constant term
471      let mut input_as_sparse_poly_entries = vec![SparsePolyEntry::new(0, Scalar::one())];
472      //remaining inputs
473      input_as_sparse_poly_entries.extend(
474        (0..input.len())
475          .map(|i| SparsePolyEntry::new(i + 1, input[i]))
476          .collect::<Vec<SparsePolyEntry>>(),
477      );
478      SparsePolynomial::new(n.log2(), input_as_sparse_poly_entries).evaluate(&ry[1..].to_vec())
479    };
480
481    // compute commitment to eval_Z_at_ry = (Scalar::one() - ry[0]) * self.eval_vars_at_ry + ry[0] * poly_input_eval
482    let comm_eval_Z_at_ry = GroupElement::vartime_multiscalar_mul(
483      iter::once(Scalar::one() - &ry[0]).chain(iter::once(ry[0])),
484      iter::once(&self.comm_vars_at_ry.decompress().unwrap()).chain(iter::once(
485        &poly_input_eval.commit(&Scalar::zero(), &gens.gens_pc.gens.gens_1),
486      )),
487    );
488
489    // perform the final check in the second sum-check protocol
490    let (eval_A_r, eval_B_r, eval_C_r) = evals.get_evaluations();
491    let expected_claim_post_phase2 =
492      (&(&r_A * &eval_A_r + &r_B * &eval_B_r + &r_C * &eval_C_r) * comm_eval_Z_at_ry).compress();
493    // verify proof that expected_claim_post_phase1 == claim_post_phase1
494    assert!(self
495      .proof_eq_sc_phase2
496      .verify(
497        &gens.gens_sc.gens_1,
498        transcript,
499        &expected_claim_post_phase2,
500        &comm_claim_post_phase2,
501      )
502      .is_ok());
503
504    Ok((rx, ry))
505  }
506}
507
508#[cfg(test)]
509mod tests {
510  use super::*;
511  use rand::rngs::OsRng;
512
513  fn produce_tiny_r1cs() -> (R1CSInstance, Vec<Scalar>, Vec<Scalar>) {
514    // three constraints over five variables Z1, Z2, Z3, Z4, and Z5
515    // rounded to the nearest power of two
516    let num_cons = 128;
517    let num_vars = 256;
518    let num_inputs = 2;
519
520    // encode the above constraints into three matrices
521    let mut A: Vec<SparseMatEntry> = Vec::new();
522    let mut B: Vec<SparseMatEntry> = Vec::new();
523    let mut C: Vec<SparseMatEntry> = Vec::new();
524
525    let one = Scalar::one();
526    // constraint 0 entries
527    // (Z1 + Z2) * I0 - Z3 = 0;
528    A.push(SparseMatEntry::new(0, 0, one));
529    A.push(SparseMatEntry::new(0, 1, one));
530    B.push(SparseMatEntry::new(0, num_vars + 1, one));
531    C.push(SparseMatEntry::new(0, 2, one));
532
533    // constraint 1 entries
534    // (Z1 + I1) * (Z3) - Z4 = 0
535    A.push(SparseMatEntry::new(1, 0, one));
536    A.push(SparseMatEntry::new(1, num_vars + 2, one));
537    B.push(SparseMatEntry::new(1, 2, one));
538    C.push(SparseMatEntry::new(1, 3, one));
539    // constraint 3 entries
540    // Z5 * 1 - 0 = 0
541    A.push(SparseMatEntry::new(2, 4, one));
542    B.push(SparseMatEntry::new(2, num_vars, one));
543
544    let num_vars_x = num_cons.log2();
545    let num_vars_y = (2 * num_vars).log2();
546
547    let poly_A = SparseMatPolynomial::new(num_vars_x, num_vars_y, A);
548    let poly_B = SparseMatPolynomial::new(num_vars_x, num_vars_y, B);
549    let poly_C = SparseMatPolynomial::new(num_vars_x, num_vars_y, C);
550
551    let inst = R1CSInstance::new(num_cons, num_vars, num_inputs, poly_A, poly_B, poly_C);
552
553    // compute a satisfying assignment
554    let mut csprng: OsRng = OsRng;
555    let i0 = Scalar::random(&mut csprng);
556    let i1 = Scalar::random(&mut csprng);
557    let z1 = Scalar::random(&mut csprng);
558    let z2 = Scalar::random(&mut csprng);
559    let z3 = (z1 + z2) * i0; // constraint 1: (Z1 + Z2) * I0 - Z3 = 0;
560    let z4 = (z1 + i1) * z3; // constraint 2: (Z1 + I1) * (Z3) - Z4 = 0
561    let z5 = Scalar::zero(); //constraint 3
562
563    let mut vars = vec![Scalar::zero(); num_vars];
564    vars[0] = z1;
565    vars[1] = z2;
566    vars[2] = z3;
567    vars[3] = z4;
568    vars[4] = z5;
569
570    let mut input = vec![Scalar::zero(); num_inputs];
571    input[0] = i0;
572    input[1] = i1;
573
574    (inst, vars, input)
575  }
576
577  #[test]
578  fn test_tiny_r1cs() {
579    let (inst, vars, input) = tests::produce_tiny_r1cs();
580    let is_sat = inst.is_sat(&vars, &input);
581    assert_eq!(is_sat, true);
582  }
583
584  #[test]
585  fn test_synthetic_r1cs() {
586    let (inst, vars, input) = R1CSInstance::produce_synthetic_r1cs(1024, 1024, 10);
587    let is_sat = inst.is_sat(&vars, &input);
588    assert_eq!(is_sat, true);
589  }
590
591  #[test]
592  pub fn check_r1cs_proof() {
593    let num_vars = 1024;
594    let num_cons = num_vars;
595    let num_inputs = 10;
596    let (inst, vars, input) = R1CSInstance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
597
598    let gens = R1CSGens::new(num_cons, num_vars, b"test-m");
599
600    let mut random_tape = {
601      let mut csprng: OsRng = OsRng;
602      let mut tape = Transcript::new(b"proof");
603      tape.append_scalar(b"init_randomness", &Scalar::random(&mut csprng));
604      tape
605    };
606    let mut prover_transcript = Transcript::new(b"example");
607    let (proof, rx, ry) = R1CSProof::prove(
608      &inst,
609      vars,
610      &input,
611      &gens,
612      &mut prover_transcript,
613      &mut random_tape,
614    );
615
616    let eval_table_rx = EqPolynomial::new(rx).evals();
617    let eval_table_ry = EqPolynomial::new(ry).evals();
618    let inst_evals = inst.evaluate_with_tables(&eval_table_rx, &eval_table_ry);
619
620    let mut verifier_transcript = Transcript::new(b"example");
621    assert!(proof
622      .verify(
623        inst.get_num_vars(),
624        inst.get_num_cons(),
625        &input,
626        &inst_evals,
627        &mut verifier_transcript,
628        &gens,
629      )
630      .is_ok());
631  }
632}