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    self.r1cs_eval_proof.verify(
445      &comm.comm,
446      &rx,
447      &ry,
448      &self.inst_evals,
449      &gens.gens_r1cs_eval,
450      transcript,
451    )?;
452    timer_eval_proof.stop();
453    timer_verify.stop();
454    Ok(())
455  }
456}
457
458/// `NIZKGens` holds public parameters for producing and verifying proofs with the Spartan NIZK
459pub struct NIZKGens {
460  gens_r1cs_sat: R1CSGens,
461}
462
463impl NIZKGens {
464  /// Constructs a new `NIZKGens` given the size of the R1CS statement
465  pub fn new(num_cons: usize, num_vars: usize, num_inputs: usize) -> Self {
466    let num_vars_padded = {
467      let mut num_vars_padded = max(num_vars, num_inputs + 1);
468      if num_vars_padded != num_vars_padded.next_power_of_two() {
469        num_vars_padded = num_vars_padded.next_power_of_two();
470      }
471      num_vars_padded
472    };
473
474    let gens_r1cs_sat = R1CSGens::new(b"gens_r1cs_sat", num_cons, num_vars_padded);
475    NIZKGens { gens_r1cs_sat }
476  }
477}
478
479/// `NIZK` holds a proof produced by Spartan NIZK
480#[derive(Serialize, Deserialize, Debug)]
481pub struct NIZK {
482  r1cs_sat_proof: R1CSProof,
483  r: (Vec<Scalar>, Vec<Scalar>),
484}
485
486impl NIZK {
487  fn protocol_name() -> &'static [u8] {
488    b"Spartan NIZK proof"
489  }
490
491  /// A method to produce a NIZK proof of the satisfiability of an R1CS instance
492  pub fn prove(
493    inst: &Instance,
494    vars: VarsAssignment,
495    input: &InputsAssignment,
496    gens: &NIZKGens,
497    transcript: &mut Transcript,
498  ) -> Self {
499    let timer_prove = Timer::new("NIZK::prove");
500    // we create a Transcript object seeded with a random Scalar
501    // to aid the prover produce its randomness
502    let mut random_tape = RandomTape::new(b"proof");
503    transcript.append_protocol_name(NIZK::protocol_name());
504    let (r1cs_sat_proof, rx, ry) = {
505      // we might need to pad variables
506      let padded_vars = {
507        let num_padded_vars = inst.inst.get_num_vars();
508        let num_vars = vars.assignment.len();
509        if num_padded_vars > num_vars {
510          vars.pad(num_padded_vars)
511        } else {
512          vars
513        }
514      };
515
516      let (proof, rx, ry) = R1CSProof::prove(
517        &inst.inst,
518        padded_vars.assignment,
519        &input.assignment,
520        &gens.gens_r1cs_sat,
521        transcript,
522        &mut random_tape,
523      );
524      let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap();
525      Timer::print(&format!("len_r1cs_sat_proof {:?}", proof_encoded.len()));
526      (proof, rx, ry)
527    };
528
529    timer_prove.stop();
530    NIZK {
531      r1cs_sat_proof,
532      r: (rx, ry),
533    }
534  }
535
536  /// A method to verify a NIZK proof of the satisfiability of an R1CS instance
537  pub fn verify(
538    &self,
539    inst: &Instance,
540    input: &InputsAssignment,
541    transcript: &mut Transcript,
542    gens: &NIZKGens,
543  ) -> Result<(), ProofVerifyError> {
544    let timer_verify = Timer::new("NIZK::verify");
545
546    transcript.append_protocol_name(NIZK::protocol_name());
547
548    // We send evaluations of A, B, C at r = (rx, ry) as claims
549    // to enable the verifier complete the first sum-check
550    let timer_eval = Timer::new("eval_sparse_polys");
551    let (claimed_rx, claimed_ry) = &self.r;
552    let inst_evals = inst.inst.evaluate(claimed_rx, claimed_ry);
553    timer_eval.stop();
554
555    let timer_sat_proof = Timer::new("verify_sat_proof");
556    assert_eq!(input.assignment.len(), inst.inst.get_num_inputs());
557    let (rx, ry) = self.r1cs_sat_proof.verify(
558      inst.inst.get_num_vars(),
559      inst.inst.get_num_cons(),
560      &input.assignment,
561      &inst_evals,
562      transcript,
563      &gens.gens_r1cs_sat,
564    )?;
565
566    // verify if claimed rx and ry are correct
567    assert_eq!(rx, *claimed_rx);
568    assert_eq!(ry, *claimed_ry);
569    timer_sat_proof.stop();
570    timer_verify.stop();
571
572    Ok(())
573  }
574}
575
576#[cfg(test)]
577mod tests {
578  use super::*;
579
580  #[test]
581  pub fn check_snark() {
582    let num_vars = 256;
583    let num_cons = num_vars;
584    let num_inputs = 10;
585
586    // produce public generators
587    let gens = SNARKGens::new(num_cons, num_vars, num_inputs, num_cons);
588
589    // produce a synthetic R1CSInstance
590    let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
591
592    // create a commitment to R1CSInstance
593    let (comm, decomm) = SNARK::encode(&inst, &gens);
594
595    // produce a proof
596    let mut prover_transcript = Transcript::new(b"example");
597    let proof = SNARK::prove(&inst, &decomm, vars, &inputs, &gens, &mut prover_transcript);
598
599    // verify the proof
600    let mut verifier_transcript = Transcript::new(b"example");
601    assert!(proof
602      .verify(&comm, &inputs, &mut verifier_transcript, &gens)
603      .is_ok());
604  }
605
606  #[test]
607  pub fn check_r1cs_invalid_index() {
608    let num_cons = 4;
609    let num_vars = 8;
610    let num_inputs = 1;
611
612    let zero: [u8; 32] = [
613      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,
614      0,
615    ];
616
617    let A = vec![(0, 0, zero)];
618    let B = vec![(100, 1, zero)];
619    let C = vec![(1, 1, zero)];
620
621    let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C);
622    assert!(inst.is_err());
623    assert_eq!(inst.err(), Some(R1CSError::InvalidIndex));
624  }
625
626  #[test]
627  pub fn check_r1cs_invalid_scalar() {
628    let num_cons = 4;
629    let num_vars = 8;
630    let num_inputs = 1;
631
632    let zero: [u8; 32] = [
633      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,
634      0,
635    ];
636
637    let larger_than_mod = [
638      3, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216,
639      57, 51, 72, 125, 157, 41, 83, 167, 237, 115,
640    ];
641
642    let A = vec![(0, 0, zero)];
643    let B = vec![(1, 1, larger_than_mod)];
644    let C = vec![(1, 1, zero)];
645
646    let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C);
647    assert!(inst.is_err());
648    assert_eq!(inst.err(), Some(R1CSError::InvalidScalar));
649  }
650
651  #[test]
652  fn test_padded_constraints() {
653    // parameters of the R1CS instance
654    let num_cons = 1;
655    let num_vars = 0;
656    let num_inputs = 3;
657    let num_non_zero_entries = 3;
658
659    // We will encode the above constraints into three matrices, where
660    // the coefficients in the matrix are in the little-endian byte order
661    let mut A: Vec<(usize, usize, [u8; 32])> = Vec::new();
662    let mut B: Vec<(usize, usize, [u8; 32])> = Vec::new();
663    let mut C: Vec<(usize, usize, [u8; 32])> = Vec::new();
664
665    // Create a^2 + b + 13
666    A.push((0, num_vars + 2, Scalar::one().to_bytes())); // 1*a
667    B.push((0, num_vars + 2, Scalar::one().to_bytes())); // 1*a
668    C.push((0, num_vars + 1, Scalar::one().to_bytes())); // 1*z
669    C.push((0, num_vars, (-Scalar::from(13u64)).to_bytes())); // -13*1
670    C.push((0, num_vars + 3, (-Scalar::one()).to_bytes())); // -1*b
671
672    // Var Assignments (Z_0 = 16 is the only output)
673    let vars = vec![Scalar::zero().to_bytes(); num_vars];
674
675    // create an InputsAssignment (a = 1, b = 2)
676    let mut inputs = vec![Scalar::zero().to_bytes(); num_inputs];
677    inputs[0] = Scalar::from(16u64).to_bytes();
678    inputs[1] = Scalar::from(1u64).to_bytes();
679    inputs[2] = Scalar::from(2u64).to_bytes();
680
681    let assignment_inputs = InputsAssignment::new(&inputs).unwrap();
682    let assignment_vars = VarsAssignment::new(&vars).unwrap();
683
684    // Check if instance is satisfiable
685    let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C).unwrap();
686    let res = inst.is_sat(&assignment_vars, &assignment_inputs);
687    assert!(res.unwrap(), "should be satisfied");
688
689    // SNARK public params
690    let gens = SNARKGens::new(num_cons, num_vars, num_inputs, num_non_zero_entries);
691
692    // create a commitment to the R1CS instance
693    let (comm, decomm) = SNARK::encode(&inst, &gens);
694
695    // produce a SNARK
696    let mut prover_transcript = Transcript::new(b"snark_example");
697    let proof = SNARK::prove(
698      &inst,
699      &decomm,
700      assignment_vars.clone(),
701      &assignment_inputs,
702      &gens,
703      &mut prover_transcript,
704    );
705
706    // verify the SNARK
707    let mut verifier_transcript = Transcript::new(b"snark_example");
708    assert!(proof
709      .verify(&comm, &assignment_inputs, &mut verifier_transcript, &gens)
710      .is_ok());
711
712    // NIZK public params
713    let gens = NIZKGens::new(num_cons, num_vars, num_inputs);
714
715    // produce a NIZK
716    let mut prover_transcript = Transcript::new(b"nizk_example");
717    let proof = NIZK::prove(
718      &inst,
719      assignment_vars,
720      &assignment_inputs,
721      &gens,
722      &mut prover_transcript,
723    );
724
725    // verify the NIZK
726    let mut verifier_transcript = Transcript::new(b"nizk_example");
727    assert!(proof
728      .verify(&inst, &assignment_inputs, &mut verifier_transcript, &gens)
729      .is_ok());
730  }
731}