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