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