arnaucube
arnaucube/testudoPublic Self-hosted repository
testudo/src/r1csproof.rs
src/r1csproof.rsRaw
  1#![allow(clippy::too_many_arguments)]
  2use super::dense_mlpoly::{DensePolynomial, EqPolynomial, PolyCommitmentGens};
  3use super::errors::ProofVerifyError;
  4use crate::constraints::{R1CSVerificationCircuit, SumcheckVerificationCircuit, VerifierConfig};
  5use crate::math::Math;
  6use crate::mipp::MippProof;
  7use crate::poseidon_transcript::PoseidonTranscript;
  8use crate::sqrt_pst::Polynomial;
  9use crate::sumcheck::SumcheckInstanceProof;
 10use crate::transcript::Transcript;
 11use crate::unipoly::UniPoly;
 12use ark_crypto_primitives::sponge::poseidon::PoseidonConfig;
 13use ark_crypto_primitives::sponge::Absorb;
 14use ark_ec::pairing::Pairing;
 15
 16use ark_poly_commit::multilinear_pc::data_structures::{Commitment, Proof};
 17use itertools::Itertools;
 18
 19use super::r1csinstance::R1CSInstance;
 20
 21use super::sparse_mlpoly::{SparsePolyEntry, SparsePolynomial};
 22use super::timer::Timer;
 23use ark_snark::{CircuitSpecificSetupSNARK, SNARK};
 24
 25use crate::ark_std::UniformRand;
 26use ark_groth16::{Groth16, ProvingKey, VerifyingKey};
 27
 28use ark_serialize::*;
 29use ark_std::{One, Zero};
 30
 31#[derive(CanonicalSerialize, CanonicalDeserialize, Debug)]
 32pub struct R1CSProof<E: Pairing> {
 33  // The PST commitment to the multilinear extension of the witness.
 34  pub comm: Commitment<E>,
 35  sc_proof_phase1: SumcheckInstanceProof<E::ScalarField>,
 36  claims_phase2: (
 37    E::ScalarField,
 38    E::ScalarField,
 39    E::ScalarField,
 40    E::ScalarField,
 41  ),
 42  sc_proof_phase2: SumcheckInstanceProof<E::ScalarField>,
 43  pub eval_vars_at_ry: E::ScalarField,
 44  pub proof_eval_vars_at_ry: Proof<E>,
 45  rx: Vec<E::ScalarField>,
 46  ry: Vec<E::ScalarField>,
 47  // The transcript state after the satisfiability proof was computed.
 48  pub transcript_sat_state: E::ScalarField,
 49  pub initial_state: E::ScalarField,
 50  pub t: E::TargetField,
 51  pub mipp_proof: MippProof<E>,
 52}
 53
 54#[derive(Debug, CanonicalSerialize, CanonicalDeserialize, Clone)]
 55pub struct R1CSVerifierProof<E: Pairing> {
 56  comm: Commitment<E>,
 57  circuit_proof: ark_groth16::Proof<E>,
 58  initial_state: E::ScalarField,
 59  transcript_sat_state: E::ScalarField,
 60  eval_vars_at_ry: E::ScalarField,
 61  proof_eval_vars_at_ry: Proof<E>,
 62  t: E::TargetField,
 63  mipp_proof: MippProof<E>,
 64}
 65
 66#[derive(Clone)]
 67pub struct CircuitGens<E: Pairing> {
 68  pk: ProvingKey<E>,
 69  vk: VerifyingKey<E>,
 70}
 71
 72impl<E> CircuitGens<E>
 73where
 74  E: Pairing,
 75{
 76  // Performs the circuit-specific setup required by Groth16 for the sumcheck
 77  // circuit. This is done by filling the struct with dummy elements, ensuring
 78  // the sizes are correct so the setup matches the circuit that will be proved.
 79  pub fn setup(
 80    num_cons: usize,
 81    num_vars: usize,
 82    num_inputs: usize,
 83    poseidon: PoseidonConfig<E::ScalarField>,
 84  ) -> Self {
 85    let mut rng = rand::thread_rng();
 86
 87    let uni_polys_round1 = (0..num_cons.log_2())
 88      .map(|_i| {
 89        UniPoly::<E::ScalarField>::from_evals(&[
 90          E::ScalarField::rand(&mut rng),
 91          E::ScalarField::rand(&mut rng),
 92          E::ScalarField::rand(&mut rng),
 93          E::ScalarField::rand(&mut rng),
 94        ])
 95      })
 96      .collect::<Vec<UniPoly<E::ScalarField>>>();
 97
 98    let uni_polys_round2 = (0..num_vars.log_2() + 1)
 99      .map(|_i| {
100        UniPoly::<E::ScalarField>::from_evals(&[
101          E::ScalarField::rand(&mut rng),
102          E::ScalarField::rand(&mut rng),
103          E::ScalarField::rand(&mut rng),
104        ])
105      })
106      .collect::<Vec<UniPoly<E::ScalarField>>>();
107
108    let circuit = R1CSVerificationCircuit {
109      num_vars: num_vars,
110      num_cons: num_cons,
111      input: (0..num_inputs)
112        .map(|_i| E::ScalarField::rand(&mut rng))
113        .collect_vec(),
114      input_as_sparse_poly: SparsePolynomial::new(
115        num_vars.log_2(),
116        (0..num_inputs + 1)
117          .map(|i| SparsePolyEntry::new(i, E::ScalarField::rand(&mut rng)))
118          .collect::<Vec<SparsePolyEntry<E::ScalarField>>>(),
119      ),
120      evals: (
121        E::ScalarField::zero(),
122        E::ScalarField::zero(),
123        E::ScalarField::zero(),
124      ),
125      params: poseidon,
126      prev_challenge: E::ScalarField::zero(),
127      claims_phase2: (
128        E::ScalarField::zero(),
129        E::ScalarField::zero(),
130        E::ScalarField::zero(),
131        E::ScalarField::zero(),
132      ),
133      eval_vars_at_ry: E::ScalarField::zero(),
134      sc_phase1: SumcheckVerificationCircuit {
135        polys: uni_polys_round1,
136      },
137      sc_phase2: SumcheckVerificationCircuit {
138        polys: uni_polys_round2,
139      },
140      claimed_rx: (0..num_cons.log_2())
141        .map(|_i| E::ScalarField::rand(&mut rng))
142        .collect_vec(),
143      claimed_ry: (0..num_vars.log_2() + 1)
144        .map(|_i| E::ScalarField::rand(&mut rng))
145        .collect_vec(),
146      claimed_transcript_sat_state: E::ScalarField::zero(),
147    };
148    let (pk, vk) = Groth16::<E>::setup(circuit.clone(), &mut rng).unwrap();
149    CircuitGens { pk, vk }
150  }
151}
152
153#[derive(Clone)]
154pub struct R1CSGens<E: Pairing> {
155  gens_pc: PolyCommitmentGens<E>,
156  gens_gc: CircuitGens<E>,
157}
158
159impl<E: Pairing> R1CSGens<E> {
160  // Performs the setup for the polynomial commitment PST and for Groth16.
161  pub fn setup(
162    label: &'static [u8],
163    num_cons: usize,
164    num_vars: usize,
165    num_inputs: usize,
166    poseidon: PoseidonConfig<E::ScalarField>,
167  ) -> Self {
168    let num_poly_vars = num_vars.log_2();
169    let gens_pc = PolyCommitmentGens::setup(num_poly_vars, label);
170    let gens_gc = CircuitGens::setup(num_cons, num_vars, num_inputs, poseidon);
171    R1CSGens { gens_pc, gens_gc }
172  }
173}
174
175impl<E> R1CSProof<E>
176where
177  E: Pairing,
178  E::ScalarField: Absorb,
179{
180  fn prove_phase_one(
181    num_rounds: usize,
182    evals_tau: &mut DensePolynomial<E::ScalarField>,
183    evals_Az: &mut DensePolynomial<E::ScalarField>,
184    evals_Bz: &mut DensePolynomial<E::ScalarField>,
185    evals_Cz: &mut DensePolynomial<E::ScalarField>,
186    transcript: &mut PoseidonTranscript<E::ScalarField>,
187  ) -> (
188    SumcheckInstanceProof<E::ScalarField>,
189    Vec<E::ScalarField>,
190    Vec<E::ScalarField>,
191  ) {
192    let comb_func =
193      |poly_tau_comp: &E::ScalarField,
194       poly_A_comp: &E::ScalarField,
195       poly_B_comp: &E::ScalarField,
196       poly_C_comp: &E::ScalarField|
197       -> E::ScalarField { (*poly_tau_comp) * ((*poly_A_comp) * poly_B_comp - poly_C_comp) };
198
199    let (sc_proof_phase_one, r, claims) = SumcheckInstanceProof::prove_cubic_with_additive_term(
200      &E::ScalarField::zero(), // claim is zero
201      num_rounds,
202      evals_tau,
203      evals_Az,
204      evals_Bz,
205      evals_Cz,
206      comb_func,
207      transcript,
208    );
209
210    (sc_proof_phase_one, r, claims)
211  }
212
213  fn prove_phase_two(
214    num_rounds: usize,
215    claim: &E::ScalarField,
216    evals_z: &mut DensePolynomial<E::ScalarField>,
217    evals_ABC: &mut DensePolynomial<E::ScalarField>,
218    transcript: &mut PoseidonTranscript<E::ScalarField>,
219  ) -> (
220    SumcheckInstanceProof<E::ScalarField>,
221    Vec<E::ScalarField>,
222    Vec<E::ScalarField>,
223  ) {
224    let comb_func = |poly_A_comp: &E::ScalarField,
225                     poly_B_comp: &E::ScalarField|
226     -> E::ScalarField { (*poly_A_comp) * poly_B_comp };
227    let (sc_proof_phase_two, r, claims) = SumcheckInstanceProof::prove_quad(
228      claim, num_rounds, evals_z, evals_ABC, comb_func, transcript,
229    );
230
231    (sc_proof_phase_two, r, claims)
232  }
233
234  // Proves the R1CS instance inst is satisfiable given the assignment
235  // vars.
236  pub fn prove(
237    inst: &R1CSInstance<E::ScalarField>,
238    vars: Vec<E::ScalarField>,
239    input: &[E::ScalarField],
240    gens: &R1CSGens<E>,
241    transcript: &mut PoseidonTranscript<E::ScalarField>,
242  ) -> (Self, Vec<E::ScalarField>, Vec<E::ScalarField>) {
243    let timer_prove = Timer::new("R1CSProof::prove");
244    // we currently require the number of |inputs| + 1 to be at most number of vars
245    assert!(input.len() < vars.len());
246
247    // create the multilinear witness polynomial from the satisfying assiment
248    // expressed as the list of sqrt-sized polynomials
249    let mut pl = Polynomial::from_evaluations(&vars.clone());
250
251    let timer_commit = Timer::new("polycommit");
252
253    // commitment list to the satisfying witness polynomial list
254    let (comm_list, t) = pl.commit(&gens.gens_pc.ck);
255
256    transcript.append_gt::<E>(b"", &t);
257
258    timer_commit.stop();
259
260    let initial_state = transcript.challenge_scalar(b"");
261    transcript.new_from_state(&initial_state);
262
263    transcript.append_scalar_vector(b"", &input);
264
265    let timer_sc_proof_phase1 = Timer::new("prove_sc_phase_one");
266
267    // append input to variables to create a single vector z
268    let z = {
269      let num_inputs = input.len();
270      let num_vars = vars.len();
271      let mut z = vars;
272      z.extend(&vec![E::ScalarField::one()]); // add constant term in z
273      z.extend(input);
274      z.extend(&vec![E::ScalarField::zero(); num_vars - num_inputs - 1]); // we will pad with zeros
275      z
276    };
277
278    // derive the verifier's challenge tau
279    let (num_rounds_x, num_rounds_y) = (inst.get_num_cons().log_2(), z.len().log_2());
280    let tau = transcript.challenge_scalar_vec(b"", num_rounds_x);
281    // compute the initial evaluation table for R(\tau, x)
282    let mut poly_tau = DensePolynomial::new(EqPolynomial::new(tau).evals());
283    let (mut poly_Az, mut poly_Bz, mut poly_Cz) =
284      inst.multiply_vec(inst.get_num_cons(), z.len(), &z);
285
286    let (sc_proof_phase1, rx, _claims_phase1) = R1CSProof::<E>::prove_phase_one(
287      num_rounds_x,
288      &mut poly_tau,
289      &mut poly_Az,
290      &mut poly_Bz,
291      &mut poly_Cz,
292      transcript,
293    );
294    assert_eq!(poly_tau.len(), 1);
295    assert_eq!(poly_Az.len(), 1);
296    assert_eq!(poly_Bz.len(), 1);
297    assert_eq!(poly_Cz.len(), 1);
298    timer_sc_proof_phase1.stop();
299
300    let (tau_claim, Az_claim, Bz_claim, Cz_claim) =
301      (&poly_tau[0], &poly_Az[0], &poly_Bz[0], &poly_Cz[0]);
302    let prod_Az_Bz_claims = (*Az_claim) * Bz_claim;
303
304    // prove the final step of sum-check #1
305    let taus_bound_rx = tau_claim;
306    let _claim_post_phase1 = ((*Az_claim) * Bz_claim - Cz_claim) * taus_bound_rx;
307
308    let timer_sc_proof_phase2 = Timer::new("prove_sc_phase_two");
309    // combine the three claims into a single claim
310    let r_A: E::ScalarField = transcript.challenge_scalar(b"");
311    let r_B: E::ScalarField = transcript.challenge_scalar(b"");
312    let r_C: E::ScalarField = transcript.challenge_scalar(b"");
313    let claim_phase2 = r_A * Az_claim + r_B * Bz_claim + r_C * Cz_claim;
314
315    let evals_ABC = {
316      // compute the initial evaluation table for R(\tau, x)
317      let evals_rx = EqPolynomial::new(rx.clone()).evals();
318      let (evals_A, evals_B, evals_C) =
319        inst.compute_eval_table_sparse(inst.get_num_cons(), z.len(), &evals_rx);
320
321      assert_eq!(evals_A.len(), evals_B.len());
322      assert_eq!(evals_A.len(), evals_C.len());
323      (0..evals_A.len())
324        .map(|i| r_A * evals_A[i] + r_B * evals_B[i] + r_C * evals_C[i])
325        .collect::<Vec<_>>()
326    };
327
328    // another instance of the sum-check protocol
329    let (sc_proof_phase2, ry, _claims_phase2) = R1CSProof::<E>::prove_phase_two(
330      num_rounds_y,
331      &claim_phase2,
332      &mut DensePolynomial::new(z),
333      &mut DensePolynomial::new(evals_ABC),
334      transcript,
335    );
336    timer_sc_proof_phase2.stop();
337    let transcript_sat_state = transcript.challenge_scalar(b"");
338    transcript.new_from_state(&transcript_sat_state);
339
340    let timmer_opening = Timer::new("polyopening");
341
342    let (comm, proof_eval_vars_at_ry, mipp_proof) =
343      pl.open(transcript, comm_list, &gens.gens_pc.ck, &ry[1..], &t);
344
345    timmer_opening.stop();
346
347    let timer_polyeval = Timer::new("polyeval");
348    let eval_vars_at_ry = pl.eval(&ry[1..]);
349    timer_polyeval.stop();
350    timer_prove.stop();
351    (
352      R1CSProof {
353        comm,
354        initial_state,
355        sc_proof_phase1,
356        claims_phase2: (*Az_claim, *Bz_claim, *Cz_claim, prod_Az_Bz_claims),
357        sc_proof_phase2,
358        eval_vars_at_ry,
359        proof_eval_vars_at_ry,
360        rx: rx.clone(),
361        ry: ry.clone(),
362        transcript_sat_state,
363        t,
364        mipp_proof,
365      },
366      rx,
367      ry,
368    )
369  }
370
371  // Creates a Groth16 proof for the verification of sumcheck, expressed
372  // as a circuit.
373  pub fn prove_verifier(
374    &self,
375    num_vars: usize,
376    num_cons: usize,
377    input: &[E::ScalarField],
378    evals: &(E::ScalarField, E::ScalarField, E::ScalarField),
379    transcript: &mut PoseidonTranscript<E::ScalarField>,
380    gens: &R1CSGens<E>,
381    poseidon: PoseidonConfig<E::ScalarField>,
382  ) -> Result<R1CSVerifierProof<E>, ProofVerifyError> {
383    // serialise and add the IPP commitment to the transcript
384    transcript.append_gt::<E>(b"", &self.t);
385
386    let initial_state = transcript.challenge_scalar(b"");
387    transcript.new_from_state(&initial_state);
388
389    let mut input_as_sparse_poly_entries = vec![SparsePolyEntry::new(0, E::ScalarField::one())];
390    //remaining inputs
391    input_as_sparse_poly_entries.extend(
392      (0..input.len())
393        .map(|i| SparsePolyEntry::new(i + 1, input[i]))
394        .collect::<Vec<SparsePolyEntry<E::ScalarField>>>(),
395    );
396    let input_as_sparse_poly =
397      SparsePolynomial::new(num_vars.log_2() as usize, input_as_sparse_poly_entries);
398
399    let config = VerifierConfig {
400      num_vars,
401      num_cons,
402      input: input.to_vec(),
403      evals: *evals,
404      params: poseidon,
405      prev_challenge: initial_state,
406      claims_phase2: self.claims_phase2,
407      polys_sc1: self.sc_proof_phase1.polys.clone(),
408      polys_sc2: self.sc_proof_phase2.polys.clone(),
409      eval_vars_at_ry: self.eval_vars_at_ry,
410      input_as_sparse_poly,
411      comm: self.comm.clone(),
412      rx: self.rx.clone(),
413      ry: self.ry.clone(),
414      transcript_sat_state: self.transcript_sat_state,
415    };
416
417    let circuit = R1CSVerificationCircuit::new(&config);
418
419    let circuit_prover_timer = Timer::new("provecircuit");
420    let proof = Groth16::<E>::prove(&gens.gens_gc.pk, circuit, &mut rand::thread_rng()).unwrap();
421    circuit_prover_timer.stop();
422
423    Ok(R1CSVerifierProof {
424      comm: self.comm.clone(),
425      circuit_proof: proof,
426      initial_state: self.initial_state,
427      transcript_sat_state: self.transcript_sat_state,
428      eval_vars_at_ry: self.eval_vars_at_ry,
429      proof_eval_vars_at_ry: self.proof_eval_vars_at_ry.clone(),
430      t: self.t,
431      mipp_proof: self.mipp_proof.clone(),
432    })
433  }
434}
435
436impl<E: Pairing> R1CSVerifierProof<E>
437where
438  <E as Pairing>::ScalarField: Absorb,
439{
440  // Verifier the Groth16 proof for the sumcheck circuit and the PST polynomial
441  // commitment opening.
442  pub fn verify(
443    &self,
444    r: (Vec<E::ScalarField>, Vec<E::ScalarField>),
445    input: &[E::ScalarField],
446    evals: &(E::ScalarField, E::ScalarField, E::ScalarField),
447    transcript: &mut PoseidonTranscript<E::ScalarField>,
448    gens: &R1CSGens<E>,
449  ) -> Result<bool, ProofVerifyError> {
450    let (rx, ry) = &r;
451    let (Ar, Br, Cr) = evals;
452    let mut pubs = vec![self.initial_state];
453    pubs.extend(input.clone());
454    pubs.extend(rx.clone());
455    pubs.extend(ry.clone());
456    pubs.extend(vec![
457      self.eval_vars_at_ry,
458      *Ar,
459      *Br,
460      *Cr,
461      self.transcript_sat_state,
462    ]);
463    transcript.new_from_state(&self.transcript_sat_state);
464    par! {
465      // verifies the Groth16 proof for the spartan verifier
466      let is_verified = Groth16::<E>::verify(&gens.gens_gc.vk, &pubs, &self.circuit_proof).unwrap(),
467
468      // verifies the proof of opening against the result of evaluating the
469      // witness polynomial at point ry
470        let res = Polynomial::verify(
471        transcript,
472        &gens.gens_pc.vk,
473        &self.comm,
474        &ry[1..],
475        self.eval_vars_at_ry,
476        &self.proof_eval_vars_at_ry,
477        &self.mipp_proof,
478        &self.t,
479      )
480    };
481    assert!(is_verified == true);
482    assert!(res == true);
483    Ok(is_verified && res)
484  }
485}
486
487#[cfg(test)]
488mod tests {
489
490  use super::*;
491
492  use ark_ff::PrimeField;
493  use ark_std::UniformRand;
494  type F = ark_bls12_377::Fr;
495
496  fn produce_tiny_r1cs() -> (R1CSInstance<F>, Vec<F>, Vec<F>) {
497    // three constraints over five variables Z1, Z2, Z3, Z4, and Z5
498    // rounded to the nearest power of two
499    let num_cons = 128;
500    let num_vars = 256;
501    let num_inputs = 2;
502
503    // encode the above constraints into three matrices
504    let mut A: Vec<(usize, usize, F)> = Vec::new();
505    let mut B: Vec<(usize, usize, F)> = Vec::new();
506    let mut C: Vec<(usize, usize, F)> = Vec::new();
507
508    let one = F::one();
509    // constraint 0 entries
510    // (Z1 + Z2) * I0 - Z3 = 0;
511    A.push((0, 0, one));
512    A.push((0, 1, one));
513    B.push((0, num_vars + 1, one));
514    C.push((0, 2, one));
515
516    // constraint 1 entries
517    // (Z1 + I1) * (Z3) - Z4 = 0
518    A.push((1, 0, one));
519    A.push((1, num_vars + 2, one));
520    B.push((1, 2, one));
521    C.push((1, 3, one));
522    // constraint 3 entries
523    // Z5 * 1 - 0 = 0
524    A.push((2, 4, one));
525    B.push((2, num_vars, one));
526
527    let inst = R1CSInstance::new(num_cons, num_vars, num_inputs, &A, &B, &C);
528
529    // compute a satisfying assignment
530    let mut rng = ark_std::rand::thread_rng();
531    let i0 = F::rand(&mut rng);
532    let i1 = F::rand(&mut rng);
533    let z1 = F::rand(&mut rng);
534    let z2 = F::rand(&mut rng);
535    let z3 = (z1 + z2) * i0; // constraint 1: (Z1 + Z2) * I0 - Z3 = 0;
536    let z4 = (z1 + i1) * z3; // constraint 2: (Z1 + I1) * (Z3) - Z4 = 0
537    let z5 = F::zero(); //constraint 3
538
539    let mut vars = vec![F::zero(); num_vars];
540    vars[0] = z1;
541    vars[1] = z2;
542    vars[2] = z3;
543    vars[3] = z4;
544    vars[4] = z5;
545
546    let mut input = vec![F::zero(); num_inputs];
547    input[0] = i0;
548    input[1] = i1;
549
550    (inst, vars, input)
551  }
552
553  #[test]
554  fn test_tiny_r1cs() {
555    let (inst, vars, input) = tests::produce_tiny_r1cs();
556    let is_sat = inst.is_sat(&vars, &input);
557    assert!(is_sat);
558  }
559
560  #[test]
561  fn test_synthetic_r1cs() {
562    type F = ark_bls12_377::Fr;
563    let (inst, vars, input) = R1CSInstance::<F>::produce_synthetic_r1cs(1024, 1024, 10);
564    let is_sat = inst.is_sat(&vars, &input);
565    assert!(is_sat);
566  }
567
568  use crate::parameters::PoseidonConfiguration;
569  #[test]
570  fn check_r1cs_proof_ark_blst() {
571    let params = ark_blst::Scalar::poseidon_params();
572    check_r1cs_proof::<ark_blst::Bls12>(params);
573  }
574  #[test]
575  fn check_r1cs_proof_bls12_377() {
576    let params = ark_bls12_377::Fr::poseidon_params();
577    check_r1cs_proof::<ark_bls12_377::Bls12_377>(params);
578  }
579
580  #[test]
581  fn check_r1cs_proof_bls12_381() {
582    let params = ark_bls12_381::Fr::poseidon_params();
583    check_r1cs_proof::<ark_bls12_381::Bls12_381>(params);
584  }
585  fn check_r1cs_proof<P>(params: PoseidonConfig<P::ScalarField>)
586  where
587    P: Pairing,
588    P::ScalarField: PrimeField,
589    P::ScalarField: Absorb,
590  {
591    let num_vars = 1024;
592    let num_cons = num_vars;
593    let num_inputs = 3;
594    let (inst, vars, input) =
595      R1CSInstance::<P::ScalarField>::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
596
597    let gens = R1CSGens::<P>::setup(b"test-m", num_cons, num_vars, num_inputs, params.clone());
598
599    //let params = poseidon_params();
600    // let mut random_tape = RandomTape::new(b"proof");
601
602    let mut prover_transcript = PoseidonTranscript::new(&params.clone());
603    let c = prover_transcript.challenge_scalar::<P::ScalarField>(b"");
604    prover_transcript.new_from_state(&c);
605    let (proof, rx, ry) = R1CSProof::prove(&inst, vars, &input, &gens, &mut prover_transcript);
606
607    let inst_evals = inst.evaluate(&rx, &ry);
608
609    prover_transcript.new_from_state(&c);
610    let verifier_proof = proof
611      .prove_verifier(
612        num_vars,
613        num_cons,
614        &input,
615        &inst_evals,
616        &mut prover_transcript,
617        &gens,
618        params.clone(),
619      )
620      .unwrap();
621
622    let mut verifier_transcript = PoseidonTranscript::new(&params.clone());
623    assert!(verifier_proof
624      .verify(
625        (rx, ry),
626        &input,
627        &inst_evals,
628        &mut verifier_transcript,
629        &gens
630      )
631      .is_ok());
632  }
633}