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