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