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