arnaucube
arnaucube/testudoPublic Self-hosted repository
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}