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