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