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