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