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