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