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