arnaucube
arnaucube/testudoPublic Self-hosted repository
testudo/src/lib.rs
src/lib.rsRaw
  1#![allow(non_snake_case)]
  2#![feature(test)]
  3#![deny(missing_docs)]
  4#![feature(external_doc)]
  5#![doc(include = "../README.md")]
  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: &Vec<[u8; 32]>) -> Result<Assignment, R1CSError> {
 68    let bytes_to_scalar = |vec: &Vec<[u8; 32]>| -> Result<Vec<Scalar>, R1CSError> {
 69      let mut vec_scalar: Vec<Scalar> = Vec::new();
 70      for i in 0..vec.len() {
 71        let val = Scalar::from_bytes(&vec[i]);
 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: &Vec<(usize, usize, [u8; 32])>,
128    B: &Vec<(usize, usize, [u8; 32])>,
129    C: &Vec<(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: &Vec<(usize, usize, [u8; 32])>| -> Result<Vec<(usize, usize, Scalar)>, R1CSError> {
165        let mut mat: Vec<(usize, usize, Scalar)> = Vec::new();
166        for i in 0..tups.len() {
167          let (row, col, val_bytes) = tups[i];
168
169          // row must be smaller than num_cons
170          if row >= num_cons {
171            return Err(R1CSError::InvalidIndex);
172          }
173
174          // col must be smaller than num_vars + 1 + num_inputs
175          if col >= num_vars + 1 + num_inputs {
176            return Err(R1CSError::InvalidIndex);
177          }
178
179          let val = Scalar::from_bytes(&val_bytes);
180          if val.is_some().unwrap_u8() == 1 {
181            // if col >= num_vars, it means that it is referencing a 1 or input in the satisfying
182            // assignment
183            if col >= num_vars {
184              mat.push((row, col + num_vars_padded - num_vars, val.unwrap()));
185            } else {
186              mat.push((row, col, val.unwrap()));
187            }
188          } else {
189            return Err(R1CSError::InvalidScalar);
190          }
191        }
192
193        // pad with additional constraints up until num_cons_padded if the original constraints were 0 or 1
194        // we do not need to pad otherwise because the dummy constraints are implicit in the sum-check protocol
195        if num_cons == 0 || num_cons == 1 {
196          for i in tups.len()..num_cons_padded {
197            mat.push((i, num_vars, Scalar::zero()));
198          }
199        }
200
201        Ok(mat)
202      };
203
204    let A_scalar = bytes_to_scalar(A);
205    if A_scalar.is_err() {
206      return Err(A_scalar.err().unwrap());
207    }
208
209    let B_scalar = bytes_to_scalar(B);
210    if B_scalar.is_err() {
211      return Err(B_scalar.err().unwrap());
212    }
213
214    let C_scalar = bytes_to_scalar(C);
215    if C_scalar.is_err() {
216      return Err(C_scalar.err().unwrap());
217    }
218
219    let inst = R1CSInstance::new(
220      num_cons_padded,
221      num_vars_padded,
222      num_inputs,
223      &A_scalar.unwrap(),
224      &B_scalar.unwrap(),
225      &C_scalar.unwrap(),
226    );
227
228    Ok(Instance { inst })
229  }
230
231  /// Checks if a given R1CSInstance is satisfiable with a given variables and inputs assignments
232  pub fn is_sat(
233    &self,
234    vars: &VarsAssignment,
235    inputs: &InputsAssignment,
236  ) -> Result<bool, R1CSError> {
237    if vars.assignment.len() > self.inst.get_num_vars() {
238      return Err(R1CSError::InvalidNumberOfInputs);
239    }
240
241    if inputs.assignment.len() != self.inst.get_num_inputs() {
242      return Err(R1CSError::InvalidNumberOfInputs);
243    }
244
245    // we might need to pad variables
246    let padded_vars = {
247      let num_padded_vars = self.inst.get_num_vars();
248      let num_vars = vars.assignment.len();
249      let padded_vars = if num_padded_vars > num_vars {
250        vars.pad(num_padded_vars)
251      } else {
252        vars.clone()
253      };
254      padded_vars
255    };
256
257    Ok(
258      self
259        .inst
260        .is_sat(&padded_vars.assignment, &inputs.assignment),
261    )
262  }
263
264  /// Constructs a new synthetic R1CS `Instance` and an associated satisfying assignment
265  pub fn produce_synthetic_r1cs(
266    num_cons: usize,
267    num_vars: usize,
268    num_inputs: usize,
269  ) -> (Instance, VarsAssignment, InputsAssignment) {
270    let (inst, vars, inputs) = R1CSInstance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
271    (
272      Instance { inst },
273      VarsAssignment { assignment: vars },
274      InputsAssignment { assignment: inputs },
275    )
276  }
277}
278
279/// `SNARKGens` holds public parameters for producing and verifying proofs with the Spartan SNARK
280pub struct SNARKGens {
281  gens_r1cs_sat: R1CSGens,
282  gens_r1cs_eval: R1CSCommitmentGens,
283}
284
285impl SNARKGens {
286  /// Constructs a new `SNARKGens` given the size of the R1CS statement
287  /// `num_nz_entries` specifies the maximum number of non-zero entries in any of the three R1CS matrices
288  pub fn new(num_cons: usize, num_vars: usize, num_inputs: usize, num_nz_entries: usize) -> Self {
289    let num_vars_padded = {
290      let mut num_vars_padded = max(num_vars, num_inputs + 1);
291      if num_vars_padded != num_vars_padded.next_power_of_two() {
292        num_vars_padded = num_vars_padded.next_power_of_two();
293      }
294      num_vars_padded
295    };
296
297    let gens_r1cs_sat = R1CSGens::new(b"gens_r1cs_sat", num_cons, num_vars_padded);
298    let gens_r1cs_eval = R1CSCommitmentGens::new(
299      b"gens_r1cs_eval",
300      num_cons,
301      num_vars_padded,
302      num_inputs,
303      num_nz_entries,
304    );
305    SNARKGens {
306      gens_r1cs_sat,
307      gens_r1cs_eval,
308    }
309  }
310}
311
312/// `SNARK` holds a proof produced by Spartan SNARK
313#[derive(Serialize, Deserialize, Debug)]
314pub struct SNARK {
315  r1cs_sat_proof: R1CSProof,
316  inst_evals: (Scalar, Scalar, Scalar),
317  r1cs_eval_proof: R1CSEvalProof,
318}
319
320impl SNARK {
321  fn protocol_name() -> &'static [u8] {
322    b"Spartan SNARK proof"
323  }
324
325  /// A public computation to create a commitment to an R1CS instance
326  pub fn encode(
327    inst: &Instance,
328    gens: &SNARKGens,
329  ) -> (ComputationCommitment, ComputationDecommitment) {
330    let timer_encode = Timer::new("SNARK::encode");
331    let (comm, decomm) = inst.inst.commit(&gens.gens_r1cs_eval);
332    timer_encode.stop();
333    (
334      ComputationCommitment { comm },
335      ComputationDecommitment { decomm },
336    )
337  }
338
339  /// A method to produce a SNARK proof of the satisfiability of an R1CS instance
340  pub fn prove(
341    inst: &Instance,
342    decomm: &ComputationDecommitment,
343    vars: VarsAssignment,
344    inputs: &InputsAssignment,
345    gens: &SNARKGens,
346    transcript: &mut Transcript,
347  ) -> Self {
348    let timer_prove = Timer::new("SNARK::prove");
349
350    // we create a Transcript object seeded with a random Scalar
351    // to aid the prover produce its randomness
352    let mut random_tape = RandomTape::new(b"proof");
353    transcript.append_protocol_name(SNARK::protocol_name());
354    let (r1cs_sat_proof, rx, ry) = {
355      let (proof, rx, ry) = {
356        // we might need to pad variables
357        let padded_vars = {
358          let num_padded_vars = inst.inst.get_num_vars();
359          let num_vars = vars.assignment.len();
360          let padded_vars = if num_padded_vars > num_vars {
361            vars.pad(num_padded_vars)
362          } else {
363            vars
364          };
365          padded_vars
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    let timer_sat_proof = Timer::new("verify_sat_proof");
432    assert_eq!(input.assignment.len(), comm.comm.get_num_inputs());
433    let (rx, ry) = self.r1cs_sat_proof.verify(
434      comm.comm.get_num_vars(),
435      comm.comm.get_num_cons(),
436      &input.assignment,
437      &self.inst_evals,
438      transcript,
439      &gens.gens_r1cs_sat,
440    )?;
441    timer_sat_proof.stop();
442
443    let timer_eval_proof = Timer::new("verify_eval_proof");
444    let (Ar, Br, Cr) = &self.inst_evals;
445    Ar.append_to_transcript(b"Ar_claim", transcript);
446    Br.append_to_transcript(b"Br_claim", transcript);
447    Cr.append_to_transcript(b"Cr_claim", transcript);
448    assert!(self
449      .r1cs_eval_proof
450      .verify(
451        &comm.comm,
452        &rx,
453        &ry,
454        &self.inst_evals,
455        &gens.gens_r1cs_eval,
456        transcript
457      )
458      .is_ok());
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    transcript.append_protocol_name(NIZK::protocol_name());
511    let (r1cs_sat_proof, rx, ry) = {
512      // we might need to pad variables
513      let padded_vars = {
514        let num_padded_vars = inst.inst.get_num_vars();
515        let num_vars = vars.assignment.len();
516        let padded_vars = if num_padded_vars > num_vars {
517          vars.pad(num_padded_vars)
518        } else {
519          vars
520        };
521        padded_vars
522      };
523
524      let (proof, rx, ry) = R1CSProof::prove(
525        &inst.inst,
526        padded_vars.assignment,
527        &input.assignment,
528        &gens.gens_r1cs_sat,
529        transcript,
530        &mut random_tape,
531      );
532      let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap();
533      Timer::print(&format!("len_r1cs_sat_proof {:?}", proof_encoded.len()));
534      (proof, rx, ry)
535    };
536
537    timer_prove.stop();
538    NIZK {
539      r1cs_sat_proof,
540      r: (rx, ry),
541    }
542  }
543
544  /// A method to verify a NIZK proof of the satisfiability of an R1CS instance
545  pub fn verify(
546    &self,
547    inst: &Instance,
548    input: &InputsAssignment,
549    transcript: &mut Transcript,
550    gens: &NIZKGens,
551  ) -> Result<(), ProofVerifyError> {
552    let timer_verify = Timer::new("NIZK::verify");
553
554    transcript.append_protocol_name(NIZK::protocol_name());
555
556    // We send evaluations of A, B, C at r = (rx, ry) as claims
557    // to enable the verifier complete the first sum-check
558    let timer_eval = Timer::new("eval_sparse_polys");
559    let (claimed_rx, claimed_ry) = &self.r;
560    let inst_evals = inst.inst.evaluate(claimed_rx, claimed_ry);
561    timer_eval.stop();
562
563    let timer_sat_proof = Timer::new("verify_sat_proof");
564    assert_eq!(input.assignment.len(), inst.inst.get_num_inputs());
565    let (rx, ry) = self.r1cs_sat_proof.verify(
566      inst.inst.get_num_vars(),
567      inst.inst.get_num_cons(),
568      &input.assignment,
569      &inst_evals,
570      transcript,
571      &gens.gens_r1cs_sat,
572    )?;
573
574    // verify if claimed rx and ry are correct
575    assert_eq!(rx, *claimed_rx);
576    assert_eq!(ry, *claimed_ry);
577    timer_sat_proof.stop();
578    timer_verify.stop();
579
580    Ok(())
581  }
582}
583
584#[cfg(test)]
585mod tests {
586  use super::*;
587
588  #[test]
589  pub fn check_snark() {
590    let num_vars = 256;
591    let num_cons = num_vars;
592    let num_inputs = 10;
593
594    // produce public generators
595    let gens = SNARKGens::new(num_cons, num_vars, num_inputs, num_cons);
596
597    // produce a synthetic R1CSInstance
598    let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
599
600    // create a commitment to R1CSInstance
601    let (comm, decomm) = SNARK::encode(&inst, &gens);
602
603    // produce a proof
604    let mut prover_transcript = Transcript::new(b"example");
605    let proof = SNARK::prove(&inst, &decomm, vars, &inputs, &gens, &mut prover_transcript);
606
607    // verify the proof
608    let mut verifier_transcript = Transcript::new(b"example");
609    assert!(proof
610      .verify(&comm, &inputs, &mut verifier_transcript, &gens)
611      .is_ok());
612  }
613
614  #[test]
615  pub fn check_r1cs_invalid_index() {
616    let num_cons = 4;
617    let num_vars = 8;
618    let num_inputs = 1;
619
620    let zero: [u8; 32] = [
621      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,
622      0,
623    ];
624
625    let A = vec![(0, 0, zero)];
626    let B = vec![(100, 1, zero)];
627    let C = vec![(1, 1, zero)];
628
629    let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C);
630    assert_eq!(inst.is_err(), true);
631    assert_eq!(inst.err(), Some(R1CSError::InvalidIndex));
632  }
633
634  #[test]
635  pub fn check_r1cs_invalid_scalar() {
636    let num_cons = 4;
637    let num_vars = 8;
638    let num_inputs = 1;
639
640    let zero: [u8; 32] = [
641      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,
642      0,
643    ];
644
645    let larger_than_mod = [
646      3, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216,
647      57, 51, 72, 125, 157, 41, 83, 167, 237, 115,
648    ];
649
650    let A = vec![(0, 0, zero)];
651    let B = vec![(1, 1, larger_than_mod)];
652    let C = vec![(1, 1, zero)];
653
654    let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C);
655    assert_eq!(inst.is_err(), true);
656    assert_eq!(inst.err(), Some(R1CSError::InvalidScalar));
657  }
658
659  #[test]
660  fn test_padded_constraints() {
661    // parameters of the R1CS instance
662    let num_cons = 1;
663    let num_vars = 0;
664    let num_inputs = 3;
665    let num_non_zero_entries = 3;
666
667    // We will encode the above constraints into three matrices, where
668    // the coefficients in the matrix are in the little-endian byte order
669    let mut A: Vec<(usize, usize, [u8; 32])> = Vec::new();
670    let mut B: Vec<(usize, usize, [u8; 32])> = Vec::new();
671    let mut C: Vec<(usize, usize, [u8; 32])> = Vec::new();
672
673    // Create a^2 + b + 13
674    A.push((0, num_vars + 2, Scalar::one().to_bytes())); // 1*a
675    B.push((0, num_vars + 2, Scalar::one().to_bytes())); // 1*a
676    C.push((0, num_vars + 1, Scalar::one().to_bytes())); // 1*z
677    C.push((0, num_vars, (-Scalar::from(13u64)).to_bytes())); // -13*1
678    C.push((0, num_vars + 3, (-Scalar::one()).to_bytes())); // -1*b
679
680    // Var Assignments (Z_0 = 16 is the only output)
681    let vars = vec![Scalar::zero().to_bytes(); num_vars];
682
683    // create an InputsAssignment (a = 1, b = 2)
684    let mut inputs = vec![Scalar::zero().to_bytes(); num_inputs];
685    inputs[0] = Scalar::from(16u64).to_bytes();
686    inputs[1] = Scalar::from(1u64).to_bytes();
687    inputs[2] = Scalar::from(2u64).to_bytes();
688
689    let assignment_inputs = InputsAssignment::new(&inputs).unwrap();
690    let assignment_vars = VarsAssignment::new(&vars).unwrap();
691
692    // Check if instance is satisfiable
693    let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C).unwrap();
694    let res = inst.is_sat(&assignment_vars, &assignment_inputs);
695    assert_eq!(res.unwrap(), true, "should be satisfied");
696
697    // SNARK public params
698    let gens = SNARKGens::new(num_cons, num_vars, num_inputs, num_non_zero_entries);
699
700    // create a commitment to the R1CS instance
701    let (comm, decomm) = SNARK::encode(&inst, &gens);
702
703    // produce a SNARK
704    let mut prover_transcript = Transcript::new(b"snark_example");
705    let proof = SNARK::prove(
706      &inst,
707      &decomm,
708      assignment_vars.clone(),
709      &assignment_inputs,
710      &gens,
711      &mut prover_transcript,
712    );
713
714    // verify the SNARK
715    let mut verifier_transcript = Transcript::new(b"snark_example");
716    assert!(proof
717      .verify(&comm, &assignment_inputs, &mut verifier_transcript, &gens)
718      .is_ok());
719
720    // NIZK public params
721    let gens = NIZKGens::new(num_cons, num_vars, num_inputs);
722
723    // produce a NIZK
724    let mut prover_transcript = Transcript::new(b"nizk_example");
725    let proof = NIZK::prove(
726      &inst,
727      assignment_vars,
728      &assignment_inputs,
729      &gens,
730      &mut prover_transcript,
731    );
732
733    // verify the NIZK
734    let mut verifier_transcript = Transcript::new(b"nizk_example");
735    assert!(proof
736      .verify(&inst, &assignment_inputs, &mut verifier_transcript, &gens)
737      .is_ok());
738  }
739}