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