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