testudo/src/lib.rs
src/lib.rsRaw
1#![allow(non_snake_case)]
2#![feature(test)]
3#![feature(int_log)]
4#![doc = include_str!("../README.md")]
5#![deny(missing_docs)]
6
7extern crate byteorder;
8extern crate core;
9extern crate curve25519_dalek;
10extern crate digest;
11extern crate merlin;
12extern crate rand;
13extern crate sha3;
14extern crate test;
15
16#[cfg(feature = "multicore")]
17extern crate rayon;
18
19mod commitments;
20mod dense_mlpoly;
21mod errors;
22mod group;
23mod math;
24mod nizk;
25mod product_tree;
26mod r1csinstance;
27mod r1csproof;
28mod random;
29mod scalar;
30mod sparse_mlpoly;
31mod sumcheck;
32mod timer;
33mod transcript;
34mod unipoly;
35
36use core::cmp::max;
37use errors::{ProofVerifyError, R1CSError};
38use merlin::Transcript;
39use r1csinstance::{
40 R1CSCommitment, R1CSCommitmentGens, R1CSDecommitment, R1CSEvalProof, R1CSInstance,
41};
42use r1csproof::{R1CSGens, R1CSProof};
43use random::RandomTape;
44use scalar::Scalar;
45use serde::{Deserialize, Serialize};
46use timer::Timer;
47use transcript::{AppendToTranscript, ProofTranscript};
48
49/// `ComputationCommitment` holds a public preprocessed NP statement (e.g., R1CS)
50pub struct ComputationCommitment {
51 comm: R1CSCommitment,
52}
53
54/// `ComputationDecommitment` holds information to decommit `ComputationCommitment`
55pub struct ComputationDecommitment {
56 decomm: R1CSDecommitment,
57}
58
59/// `Assignment` holds an assignment of values to either the inputs or variables in an `Instance`
60#[derive(Clone)]
61pub struct Assignment {
62 assignment: Vec<Scalar>,
63}
64
65impl Assignment {
66 /// Constructs a new `Assignment` from a vector
67 pub fn new(assignment: &[[u8; 32]]) -> Result<Assignment, R1CSError> {
68 let bytes_to_scalar = |vec: &[[u8; 32]]| -> Result<Vec<Scalar>, R1CSError> {
69 let mut vec_scalar: Vec<Scalar> = Vec::new();
70 for v in vec {
71 let val = Scalar::from_bytes(v);
72 if val.is_some().unwrap_u8() == 1 {
73 vec_scalar.push(val.unwrap());
74 } else {
75 return Err(R1CSError::InvalidScalar);
76 }
77 }
78 Ok(vec_scalar)
79 };
80
81 let assignment_scalar = bytes_to_scalar(assignment);
82
83 // check for any parsing errors
84 if assignment_scalar.is_err() {
85 return Err(R1CSError::InvalidScalar);
86 }
87
88 Ok(Assignment {
89 assignment: assignment_scalar.unwrap(),
90 })
91 }
92
93 /// pads Assignment to the specified length
94 fn pad(&self, len: usize) -> VarsAssignment {
95 // check that the new length is higher than current length
96 assert!(len > self.assignment.len());
97
98 let padded_assignment = {
99 let mut padded_assignment = self.assignment.clone();
100 padded_assignment.extend(vec![Scalar::zero(); len - self.assignment.len()]);
101 padded_assignment
102 };
103
104 VarsAssignment {
105 assignment: padded_assignment,
106 }
107 }
108}
109
110/// `VarsAssignment` holds an assignment of values to variables in an `Instance`
111pub type VarsAssignment = Assignment;
112
113/// `VarsAssignment` holds an assignment of values to variables in an `Instance`
114pub type InputsAssignment = Assignment;
115
116/// `Instance` holds the description of R1CS matrices
117pub struct Instance {
118 inst: R1CSInstance,
119}
120
121impl Instance {
122 /// Constructs a new `Instance` and an associated satisfying assignment
123 pub fn new(
124 num_cons: usize,
125 num_vars: usize,
126 num_inputs: usize,
127 A: &[(usize, usize, [u8; 32])],
128 B: &[(usize, usize, [u8; 32])],
129 C: &[(usize, usize, [u8; 32])],
130 ) -> Result<Instance, R1CSError> {
131 let (num_vars_padded, num_cons_padded) = {
132 let num_vars_padded = {
133 let mut num_vars_padded = num_vars;
134
135 // ensure that num_inputs + 1 <= num_vars
136 num_vars_padded = max(num_vars_padded, num_inputs + 1);
137
138 // ensure that num_vars_padded a power of two
139 if num_vars_padded.next_power_of_two() != num_vars_padded {
140 num_vars_padded = num_vars_padded.next_power_of_two();
141 }
142 num_vars_padded
143 };
144
145 let num_cons_padded = {
146 let mut num_cons_padded = num_cons;
147
148 // ensure that num_cons_padded is at least 2
149 if num_cons_padded == 0 || num_cons_padded == 1 {
150 num_cons_padded = 2;
151 }
152
153 // ensure that num_cons_padded is power of 2
154 if num_cons.next_power_of_two() != num_cons {
155 num_cons_padded = num_cons.next_power_of_two();
156 }
157 num_cons_padded
158 };
159
160 (num_vars_padded, num_cons_padded)
161 };
162
163 let bytes_to_scalar =
164 |tups: &[(usize, usize, [u8; 32])]| -> Result<Vec<(usize, usize, Scalar)>, R1CSError> {
165 let mut mat: Vec<(usize, usize, Scalar)> = Vec::new();
166 for &(row, col, val_bytes) in tups {
167 // row must be smaller than num_cons
168 if row >= num_cons {
169 return Err(R1CSError::InvalidIndex);
170 }
171
172 // col must be smaller than num_vars + 1 + num_inputs
173 if col >= num_vars + 1 + num_inputs {
174 return Err(R1CSError::InvalidIndex);
175 }
176
177 let val = Scalar::from_bytes(&val_bytes);
178 if val.is_some().unwrap_u8() == 1 {
179 // if col >= num_vars, it means that it is referencing a 1 or input in the satisfying
180 // assignment
181 if col >= num_vars {
182 mat.push((row, col + num_vars_padded - num_vars, val.unwrap()));
183 } else {
184 mat.push((row, col, val.unwrap()));
185 }
186 } else {
187 return Err(R1CSError::InvalidScalar);
188 }
189 }
190
191 // pad with additional constraints up until num_cons_padded if the original constraints were 0 or 1
192 // we do not need to pad otherwise because the dummy constraints are implicit in the sum-check protocol
193 if num_cons == 0 || num_cons == 1 {
194 for i in tups.len()..num_cons_padded {
195 mat.push((i, num_vars, Scalar::zero()));
196 }
197 }
198
199 Ok(mat)
200 };
201
202 let A_scalar = bytes_to_scalar(A);
203 if A_scalar.is_err() {
204 return Err(A_scalar.err().unwrap());
205 }
206
207 let B_scalar = bytes_to_scalar(B);
208 if B_scalar.is_err() {
209 return Err(B_scalar.err().unwrap());
210 }
211
212 let C_scalar = bytes_to_scalar(C);
213 if C_scalar.is_err() {
214 return Err(C_scalar.err().unwrap());
215 }
216
217 let inst = R1CSInstance::new(
218 num_cons_padded,
219 num_vars_padded,
220 num_inputs,
221 &A_scalar.unwrap(),
222 &B_scalar.unwrap(),
223 &C_scalar.unwrap(),
224 );
225
226 Ok(Instance { inst })
227 }
228
229 /// Checks if a given R1CSInstance is satisfiable with a given variables and inputs assignments
230 pub fn is_sat(
231 &self,
232 vars: &VarsAssignment,
233 inputs: &InputsAssignment,
234 ) -> Result<bool, R1CSError> {
235 if vars.assignment.len() > self.inst.get_num_vars() {
236 return Err(R1CSError::InvalidNumberOfInputs);
237 }
238
239 if inputs.assignment.len() != self.inst.get_num_inputs() {
240 return Err(R1CSError::InvalidNumberOfInputs);
241 }
242
243 // we might need to pad variables
244 let padded_vars = {
245 let num_padded_vars = self.inst.get_num_vars();
246 let num_vars = vars.assignment.len();
247 if num_padded_vars > num_vars {
248 vars.pad(num_padded_vars)
249 } else {
250 vars.clone()
251 }
252 };
253
254 Ok(
255 self
256 .inst
257 .is_sat(&padded_vars.assignment, &inputs.assignment),
258 )
259 }
260
261 /// Constructs a new synthetic R1CS `Instance` and an associated satisfying assignment
262 pub fn produce_synthetic_r1cs(
263 num_cons: usize,
264 num_vars: usize,
265 num_inputs: usize,
266 ) -> (Instance, VarsAssignment, InputsAssignment) {
267 let (inst, vars, inputs) = R1CSInstance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
268 (
269 Instance { inst },
270 VarsAssignment { assignment: vars },
271 InputsAssignment { assignment: inputs },
272 )
273 }
274}
275
276/// `SNARKGens` holds public parameters for producing and verifying proofs with the Spartan SNARK
277pub struct SNARKGens {
278 gens_r1cs_sat: R1CSGens,
279 gens_r1cs_eval: R1CSCommitmentGens,
280}
281
282impl SNARKGens {
283 /// Constructs a new `SNARKGens` given the size of the R1CS statement
284 /// `num_nz_entries` specifies the maximum number of non-zero entries in any of the three R1CS matrices
285 pub fn new(num_cons: usize, num_vars: usize, num_inputs: usize, num_nz_entries: usize) -> Self {
286 let num_vars_padded = {
287 let mut num_vars_padded = max(num_vars, num_inputs + 1);
288 if num_vars_padded != num_vars_padded.next_power_of_two() {
289 num_vars_padded = num_vars_padded.next_power_of_two();
290 }
291 num_vars_padded
292 };
293
294 let gens_r1cs_sat = R1CSGens::new(b"gens_r1cs_sat", num_cons, num_vars_padded);
295 let gens_r1cs_eval = R1CSCommitmentGens::new(
296 b"gens_r1cs_eval",
297 num_cons,
298 num_vars_padded,
299 num_inputs,
300 num_nz_entries,
301 );
302 SNARKGens {
303 gens_r1cs_sat,
304 gens_r1cs_eval,
305 }
306 }
307}
308
309/// `SNARK` holds a proof produced by Spartan SNARK
310#[derive(Serialize, Deserialize, Debug)]
311pub struct SNARK {
312 r1cs_sat_proof: R1CSProof,
313 inst_evals: (Scalar, Scalar, Scalar),
314 r1cs_eval_proof: R1CSEvalProof,
315}
316
317impl SNARK {
318 fn protocol_name() -> &'static [u8] {
319 b"Spartan SNARK proof"
320 }
321
322 /// A public computation to create a commitment to an R1CS instance
323 pub fn encode(
324 inst: &Instance,
325 gens: &SNARKGens,
326 ) -> (ComputationCommitment, ComputationDecommitment) {
327 let timer_encode = Timer::new("SNARK::encode");
328 let (comm, decomm) = inst.inst.commit(&gens.gens_r1cs_eval);
329 timer_encode.stop();
330 (
331 ComputationCommitment { comm },
332 ComputationDecommitment { decomm },
333 )
334 }
335
336 /// A method to produce a SNARK proof of the satisfiability of an R1CS instance
337 pub fn prove(
338 inst: &Instance,
339 comm: &ComputationCommitment,
340 decomm: &ComputationDecommitment,
341 vars: VarsAssignment,
342 inputs: &InputsAssignment,
343 gens: &SNARKGens,
344 transcript: &mut Transcript,
345 ) -> Self {
346 let timer_prove = Timer::new("SNARK::prove");
347
348 // we create a Transcript object seeded with a random Scalar
349 // to aid the prover produce its randomness
350 let mut random_tape = RandomTape::new(b"proof");
351
352 transcript.append_protocol_name(SNARK::protocol_name());
353 comm.comm.append_to_transcript(b"comm", transcript);
354
355 let (r1cs_sat_proof, rx, ry) = {
356 let (proof, rx, ry) = {
357 // we might need to pad variables
358 let padded_vars = {
359 let num_padded_vars = inst.inst.get_num_vars();
360 let num_vars = vars.assignment.len();
361 if num_padded_vars > num_vars {
362 vars.pad(num_padded_vars)
363 } else {
364 vars
365 }
366 };
367
368 R1CSProof::prove(
369 &inst.inst,
370 padded_vars.assignment,
371 &inputs.assignment,
372 &gens.gens_r1cs_sat,
373 transcript,
374 &mut random_tape,
375 )
376 };
377
378 let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap();
379 Timer::print(&format!("len_r1cs_sat_proof {:?}", proof_encoded.len()));
380
381 (proof, rx, ry)
382 };
383
384 // We send evaluations of A, B, C at r = (rx, ry) as claims
385 // to enable the verifier complete the first sum-check
386 let timer_eval = Timer::new("eval_sparse_polys");
387 let inst_evals = {
388 let (Ar, Br, Cr) = inst.inst.evaluate(&rx, &ry);
389 Ar.append_to_transcript(b"Ar_claim", transcript);
390 Br.append_to_transcript(b"Br_claim", transcript);
391 Cr.append_to_transcript(b"Cr_claim", transcript);
392 (Ar, Br, Cr)
393 };
394 timer_eval.stop();
395
396 let r1cs_eval_proof = {
397 let proof = R1CSEvalProof::prove(
398 &decomm.decomm,
399 &rx,
400 &ry,
401 &inst_evals,
402 &gens.gens_r1cs_eval,
403 transcript,
404 &mut random_tape,
405 );
406
407 let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap();
408 Timer::print(&format!("len_r1cs_eval_proof {:?}", proof_encoded.len()));
409 proof
410 };
411
412 timer_prove.stop();
413 SNARK {
414 r1cs_sat_proof,
415 inst_evals,
416 r1cs_eval_proof,
417 }
418 }
419
420 /// A method to verify the SNARK proof of the satisfiability of an R1CS instance
421 pub fn verify(
422 &self,
423 comm: &ComputationCommitment,
424 input: &InputsAssignment,
425 transcript: &mut Transcript,
426 gens: &SNARKGens,
427 ) -> Result<(), ProofVerifyError> {
428 let timer_verify = Timer::new("SNARK::verify");
429 transcript.append_protocol_name(SNARK::protocol_name());
430
431 // append a commitment to the computation to the transcript
432 comm.comm.append_to_transcript(b"comm", transcript);
433
434 let timer_sat_proof = Timer::new("verify_sat_proof");
435 assert_eq!(input.assignment.len(), comm.comm.get_num_inputs());
436 let (rx, ry) = self.r1cs_sat_proof.verify(
437 comm.comm.get_num_vars(),
438 comm.comm.get_num_cons(),
439 &input.assignment,
440 &self.inst_evals,
441 transcript,
442 &gens.gens_r1cs_sat,
443 )?;
444 timer_sat_proof.stop();
445
446 let timer_eval_proof = Timer::new("verify_eval_proof");
447 let (Ar, Br, Cr) = &self.inst_evals;
448 Ar.append_to_transcript(b"Ar_claim", transcript);
449 Br.append_to_transcript(b"Br_claim", transcript);
450 Cr.append_to_transcript(b"Cr_claim", transcript);
451 self.r1cs_eval_proof.verify(
452 &comm.comm,
453 &rx,
454 &ry,
455 &self.inst_evals,
456 &gens.gens_r1cs_eval,
457 transcript,
458 )?;
459 timer_eval_proof.stop();
460 timer_verify.stop();
461 Ok(())
462 }
463}
464
465/// `NIZKGens` holds public parameters for producing and verifying proofs with the Spartan NIZK
466pub struct NIZKGens {
467 gens_r1cs_sat: R1CSGens,
468}
469
470impl NIZKGens {
471 /// Constructs a new `NIZKGens` given the size of the R1CS statement
472 pub fn new(num_cons: usize, num_vars: usize, num_inputs: usize) -> Self {
473 let num_vars_padded = {
474 let mut num_vars_padded = max(num_vars, num_inputs + 1);
475 if num_vars_padded != num_vars_padded.next_power_of_two() {
476 num_vars_padded = num_vars_padded.next_power_of_two();
477 }
478 num_vars_padded
479 };
480
481 let gens_r1cs_sat = R1CSGens::new(b"gens_r1cs_sat", num_cons, num_vars_padded);
482 NIZKGens { gens_r1cs_sat }
483 }
484}
485
486/// `NIZK` holds a proof produced by Spartan NIZK
487#[derive(Serialize, Deserialize, Debug)]
488pub struct NIZK {
489 r1cs_sat_proof: R1CSProof,
490 r: (Vec<Scalar>, Vec<Scalar>),
491}
492
493impl NIZK {
494 fn protocol_name() -> &'static [u8] {
495 b"Spartan NIZK proof"
496 }
497
498 /// A method to produce a NIZK proof of the satisfiability of an R1CS instance
499 pub fn prove(
500 inst: &Instance,
501 vars: VarsAssignment,
502 input: &InputsAssignment,
503 gens: &NIZKGens,
504 transcript: &mut Transcript,
505 ) -> Self {
506 let timer_prove = Timer::new("NIZK::prove");
507 // we create a Transcript object seeded with a random Scalar
508 // to aid the prover produce its randomness
509 let mut random_tape = RandomTape::new(b"proof");
510
511 transcript.append_protocol_name(NIZK::protocol_name());
512 inst.inst.append_to_transcript(b"inst", transcript);
513
514 let (r1cs_sat_proof, rx, ry) = {
515 // we might need to pad variables
516 let padded_vars = {
517 let num_padded_vars = inst.inst.get_num_vars();
518 let num_vars = vars.assignment.len();
519 if num_padded_vars > num_vars {
520 vars.pad(num_padded_vars)
521 } else {
522 vars
523 }
524 };
525
526 let (proof, rx, ry) = R1CSProof::prove(
527 &inst.inst,
528 padded_vars.assignment,
529 &input.assignment,
530 &gens.gens_r1cs_sat,
531 transcript,
532 &mut random_tape,
533 );
534 let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap();
535 Timer::print(&format!("len_r1cs_sat_proof {:?}", proof_encoded.len()));
536 (proof, rx, ry)
537 };
538
539 timer_prove.stop();
540 NIZK {
541 r1cs_sat_proof,
542 r: (rx, ry),
543 }
544 }
545
546 /// A method to verify a NIZK proof of the satisfiability of an R1CS instance
547 pub fn verify(
548 &self,
549 inst: &Instance,
550 input: &InputsAssignment,
551 transcript: &mut Transcript,
552 gens: &NIZKGens,
553 ) -> Result<(), ProofVerifyError> {
554 let timer_verify = Timer::new("NIZK::verify");
555
556 transcript.append_protocol_name(NIZK::protocol_name());
557 inst.inst.append_to_transcript(b"inst", transcript);
558
559 // We send evaluations of A, B, C at r = (rx, ry) as claims
560 // to enable the verifier complete the first sum-check
561 let timer_eval = Timer::new("eval_sparse_polys");
562 let (claimed_rx, claimed_ry) = &self.r;
563 let inst_evals = inst.inst.evaluate(claimed_rx, claimed_ry);
564 timer_eval.stop();
565
566 let timer_sat_proof = Timer::new("verify_sat_proof");
567 assert_eq!(input.assignment.len(), inst.inst.get_num_inputs());
568 let (rx, ry) = self.r1cs_sat_proof.verify(
569 inst.inst.get_num_vars(),
570 inst.inst.get_num_cons(),
571 &input.assignment,
572 &inst_evals,
573 transcript,
574 &gens.gens_r1cs_sat,
575 )?;
576
577 // verify if claimed rx and ry are correct
578 assert_eq!(rx, *claimed_rx);
579 assert_eq!(ry, *claimed_ry);
580 timer_sat_proof.stop();
581 timer_verify.stop();
582
583 Ok(())
584 }
585}
586
587#[cfg(test)]
588mod tests {
589 use super::*;
590
591 #[test]
592 pub fn check_snark() {
593 let num_vars = 256;
594 let num_cons = num_vars;
595 let num_inputs = 10;
596
597 // produce public generators
598 let gens = SNARKGens::new(num_cons, num_vars, num_inputs, num_cons);
599
600 // produce a synthetic R1CSInstance
601 let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
602
603 // create a commitment to R1CSInstance
604 let (comm, decomm) = SNARK::encode(&inst, &gens);
605
606 // produce a proof
607 let mut prover_transcript = Transcript::new(b"example");
608 let proof = SNARK::prove(
609 &inst,
610 &comm,
611 &decomm,
612 vars,
613 &inputs,
614 &gens,
615 &mut prover_transcript,
616 );
617
618 // verify the proof
619 let mut verifier_transcript = Transcript::new(b"example");
620 assert!(proof
621 .verify(&comm, &inputs, &mut verifier_transcript, &gens)
622 .is_ok());
623 }
624
625 #[test]
626 pub fn check_r1cs_invalid_index() {
627 let num_cons = 4;
628 let num_vars = 8;
629 let num_inputs = 1;
630
631 let zero: [u8; 32] = [
632 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
633 0,
634 ];
635
636 let A = vec![(0, 0, zero)];
637 let B = vec![(100, 1, zero)];
638 let C = vec![(1, 1, zero)];
639
640 let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C);
641 assert!(inst.is_err());
642 assert_eq!(inst.err(), Some(R1CSError::InvalidIndex));
643 }
644
645 #[test]
646 pub fn check_r1cs_invalid_scalar() {
647 let num_cons = 4;
648 let num_vars = 8;
649 let num_inputs = 1;
650
651 let zero: [u8; 32] = [
652 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
653 0,
654 ];
655
656 let larger_than_mod = [
657 3, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216,
658 57, 51, 72, 125, 157, 41, 83, 167, 237, 115,
659 ];
660
661 let A = vec![(0, 0, zero)];
662 let B = vec![(1, 1, larger_than_mod)];
663 let C = vec![(1, 1, zero)];
664
665 let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C);
666 assert!(inst.is_err());
667 assert_eq!(inst.err(), Some(R1CSError::InvalidScalar));
668 }
669
670 #[test]
671 fn test_padded_constraints() {
672 // parameters of the R1CS instance
673 let num_cons = 1;
674 let num_vars = 0;
675 let num_inputs = 3;
676 let num_non_zero_entries = 3;
677
678 // We will encode the above constraints into three matrices, where
679 // the coefficients in the matrix are in the little-endian byte order
680 let mut A: Vec<(usize, usize, [u8; 32])> = Vec::new();
681 let mut B: Vec<(usize, usize, [u8; 32])> = Vec::new();
682 let mut C: Vec<(usize, usize, [u8; 32])> = Vec::new();
683
684 // Create a^2 + b + 13
685 A.push((0, num_vars + 2, Scalar::one().to_bytes())); // 1*a
686 B.push((0, num_vars + 2, Scalar::one().to_bytes())); // 1*a
687 C.push((0, num_vars + 1, Scalar::one().to_bytes())); // 1*z
688 C.push((0, num_vars, (-Scalar::from(13u64)).to_bytes())); // -13*1
689 C.push((0, num_vars + 3, (-Scalar::one()).to_bytes())); // -1*b
690
691 // Var Assignments (Z_0 = 16 is the only output)
692 let vars = vec![Scalar::zero().to_bytes(); num_vars];
693
694 // create an InputsAssignment (a = 1, b = 2)
695 let mut inputs = vec![Scalar::zero().to_bytes(); num_inputs];
696 inputs[0] = Scalar::from(16u64).to_bytes();
697 inputs[1] = Scalar::from(1u64).to_bytes();
698 inputs[2] = Scalar::from(2u64).to_bytes();
699
700 let assignment_inputs = InputsAssignment::new(&inputs).unwrap();
701 let assignment_vars = VarsAssignment::new(&vars).unwrap();
702
703 // Check if instance is satisfiable
704 let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C).unwrap();
705 let res = inst.is_sat(&assignment_vars, &assignment_inputs);
706 assert!(res.unwrap(), "should be satisfied");
707
708 // SNARK public params
709 let gens = SNARKGens::new(num_cons, num_vars, num_inputs, num_non_zero_entries);
710
711 // create a commitment to the R1CS instance
712 let (comm, decomm) = SNARK::encode(&inst, &gens);
713
714 // produce a SNARK
715 let mut prover_transcript = Transcript::new(b"snark_example");
716 let proof = SNARK::prove(
717 &inst,
718 &comm,
719 &decomm,
720 assignment_vars.clone(),
721 &assignment_inputs,
722 &gens,
723 &mut prover_transcript,
724 );
725
726 // verify the SNARK
727 let mut verifier_transcript = Transcript::new(b"snark_example");
728 assert!(proof
729 .verify(&comm, &assignment_inputs, &mut verifier_transcript, &gens)
730 .is_ok());
731
732 // NIZK public params
733 let gens = NIZKGens::new(num_cons, num_vars, num_inputs);
734
735 // produce a NIZK
736 let mut prover_transcript = Transcript::new(b"nizk_example");
737 let proof = NIZK::prove(
738 &inst,
739 assignment_vars,
740 &assignment_inputs,
741 &gens,
742 &mut prover_transcript,
743 );
744
745 // verify the NIZK
746 let mut verifier_transcript = Transcript::new(b"nizk_example");
747 assert!(proof
748 .verify(&inst, &assignment_inputs, &mut verifier_transcript, &gens)
749 .is_ok());
750 }
751}