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