mirror of
https://github.com/arnaucube/testudo.git
synced 2026-01-12 16:51:28 +01:00
Reduce the number of public APIs smaller and add more detailed documentation
This commit is contained in:
@@ -11,7 +11,7 @@ use core::ops::Index;
|
||||
use merlin::Transcript;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "rayon_par")]
|
||||
#[cfg(feature = "multicore")]
|
||||
use rayon::prelude::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -48,23 +48,6 @@ pub struct ConstPolyCommitment {
|
||||
C: CompressedGroup,
|
||||
}
|
||||
|
||||
impl PolyCommitment {
|
||||
pub fn combine(&self, comm: &PolyCommitment, s: &Scalar) -> PolyCommitment {
|
||||
assert_eq!(comm.C.len(), self.C.len());
|
||||
let C = (0..self.C.len())
|
||||
.map(|i| (self.C[i].decompress().unwrap() + s * comm.C[i].decompress().unwrap()).compress())
|
||||
.collect::<Vec<CompressedGroup>>();
|
||||
PolyCommitment { C }
|
||||
}
|
||||
|
||||
pub fn combine_const(&self, comm: &ConstPolyCommitment) -> PolyCommitment {
|
||||
let C = (0..self.C.len())
|
||||
.map(|i| (self.C[i].decompress().unwrap() + comm.C.decompress().unwrap()).compress())
|
||||
.collect::<Vec<CompressedGroup>>();
|
||||
PolyCommitment { C }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EqPolynomial {
|
||||
r: Vec<Scalar>,
|
||||
}
|
||||
@@ -159,7 +142,7 @@ impl DensePolynomial {
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "rayon_par")]
|
||||
#[cfg(feature = "multicore")]
|
||||
fn commit_inner(&self, blinds: &Vec<Scalar>, gens: &MultiCommitGens) -> PolyCommitment {
|
||||
let L_size = blinds.len();
|
||||
let R_size = self.Z.len() / L_size;
|
||||
@@ -176,7 +159,7 @@ impl DensePolynomial {
|
||||
PolyCommitment { C }
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "rayon_par"))]
|
||||
#[cfg(not(feature = "multicore"))]
|
||||
fn commit_inner(&self, blinds: &[Scalar], gens: &MultiCommitGens) -> PolyCommitment {
|
||||
let L_size = blinds.len();
|
||||
let R_size = self.Z.len() / L_size;
|
||||
@@ -193,7 +176,6 @@ impl DensePolynomial {
|
||||
|
||||
pub fn commit(
|
||||
&self,
|
||||
hiding: bool,
|
||||
gens: &PolyCommitmentGens,
|
||||
random_tape: Option<&mut RandomTape>,
|
||||
) -> (PolyCommitment, PolyCommitmentBlinds) {
|
||||
@@ -206,7 +188,7 @@ impl DensePolynomial {
|
||||
let R_size = right_num_vars.pow2();
|
||||
assert_eq!(L_size * R_size, n);
|
||||
|
||||
let blinds = if hiding {
|
||||
let blinds = if random_tape.is_some() {
|
||||
PolyCommitmentBlinds {
|
||||
blinds: random_tape.unwrap().random_vector(b"poly_blinds", L_size),
|
||||
}
|
||||
@@ -246,15 +228,6 @@ impl DensePolynomial {
|
||||
self.len = n;
|
||||
}
|
||||
|
||||
pub fn dotproduct(&self, other: &DensePolynomial) -> Scalar {
|
||||
assert_eq!(self.len(), other.len());
|
||||
let mut res = Scalar::zero();
|
||||
for i in 0..self.len() {
|
||||
res += self.Z[i] * other[i];
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
// returns Z(r) in O(n) time
|
||||
pub fn evaluate(&self, r: &[Scalar]) -> Scalar {
|
||||
// r must have a value for each variable
|
||||
@@ -613,7 +586,7 @@ mod tests {
|
||||
assert_eq!(eval, (28 as usize).to_scalar());
|
||||
|
||||
let gens = PolyCommitmentGens::new(poly.get_num_vars(), b"test-two");
|
||||
let (poly_commitment, blinds) = poly.commit(false, &gens, None);
|
||||
let (poly_commitment, blinds) = poly.commit(&gens, None);
|
||||
|
||||
let mut random_tape = RandomTape::new(b"proof");
|
||||
let mut prover_transcript = Transcript::new(b"example");
|
||||
|
||||
343
src/lib.rs
343
src/lib.rs
@@ -1,5 +1,8 @@
|
||||
#![allow(non_snake_case)]
|
||||
#![feature(test)]
|
||||
#![deny(missing_docs)]
|
||||
#![feature(external_doc)]
|
||||
#![doc(include = "../README.md")]
|
||||
|
||||
extern crate byteorder;
|
||||
extern crate core;
|
||||
@@ -18,13 +21,347 @@ mod group;
|
||||
mod math;
|
||||
mod nizk;
|
||||
mod product_tree;
|
||||
pub mod r1csinstance;
|
||||
mod r1csinstance;
|
||||
mod r1csproof;
|
||||
mod random;
|
||||
mod scalar;
|
||||
mod sparse_mlpoly;
|
||||
pub mod spartan;
|
||||
mod sumcheck;
|
||||
pub mod timer;
|
||||
mod timer;
|
||||
mod transcript;
|
||||
mod unipoly;
|
||||
|
||||
use errors::ProofVerifyError;
|
||||
use merlin::Transcript;
|
||||
use r1csinstance::{
|
||||
R1CSCommitment, R1CSCommitmentGens, R1CSDecommitment, R1CSEvalProof, R1CSInstance,
|
||||
};
|
||||
use r1csproof::{R1CSGens, R1CSProof};
|
||||
use random::RandomTape;
|
||||
use scalar::Scalar;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use timer::Timer;
|
||||
use transcript::{AppendToTranscript, ProofTranscript};
|
||||
|
||||
/// `ComputationCommitment` holds a public preprocessed NP statement (e.g., R1CS)
|
||||
pub struct ComputationCommitment {
|
||||
comm: R1CSCommitment,
|
||||
}
|
||||
|
||||
/// `ComputationDecommitment` holds information to decommit `ComputationCommitment`
|
||||
pub struct ComputationDecommitment {
|
||||
decomm: R1CSDecommitment,
|
||||
}
|
||||
|
||||
/// `Instance` holds the description of R1CS matrices
|
||||
pub struct Instance {
|
||||
inst: R1CSInstance,
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
/// Constructs a new `Instance` and an associated satisfying assignment
|
||||
pub fn new(
|
||||
num_cons: usize,
|
||||
num_vars: usize,
|
||||
num_inputs: usize,
|
||||
) -> (Self, Vec<Scalar>, Vec<Scalar>) {
|
||||
let (inst, vars, inputs) = R1CSInstance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
|
||||
(Instance { inst }, vars, inputs)
|
||||
}
|
||||
}
|
||||
|
||||
/// `SNARKGens` holds public parameters for producing and verifying proofs with the Spartan SNARK
|
||||
pub struct SNARKGens {
|
||||
gens_r1cs_sat: R1CSGens,
|
||||
gens_r1cs_eval: R1CSCommitmentGens,
|
||||
}
|
||||
|
||||
impl SNARKGens {
|
||||
/// Constructs a new `SNARKGens` given the size of the R1CS statement
|
||||
pub fn new(num_cons: usize, num_vars: usize, num_inputs: usize, num_nz_entries: usize) -> Self {
|
||||
let gens_r1cs_sat = R1CSGens::new(b"gens_r1cs_sat", num_cons, num_vars);
|
||||
let gens_r1cs_eval = R1CSCommitmentGens::new(
|
||||
b"gens_r1cs_eval",
|
||||
num_cons,
|
||||
num_vars,
|
||||
num_inputs,
|
||||
num_nz_entries,
|
||||
);
|
||||
SNARKGens {
|
||||
gens_r1cs_sat,
|
||||
gens_r1cs_eval,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `SNARK` holds a proof produced by Spartan SNARK
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct SNARK {
|
||||
r1cs_sat_proof: R1CSProof,
|
||||
inst_evals: (Scalar, Scalar, Scalar),
|
||||
r1cs_eval_proof: R1CSEvalProof,
|
||||
}
|
||||
|
||||
impl SNARK {
|
||||
fn protocol_name() -> &'static [u8] {
|
||||
b"Spartan SNARK proof"
|
||||
}
|
||||
|
||||
/// A public computation to create a commitment to an R1CS instance
|
||||
pub fn encode(
|
||||
inst: &Instance,
|
||||
gens: &SNARKGens,
|
||||
) -> (ComputationCommitment, ComputationDecommitment) {
|
||||
let timer_encode = Timer::new("SNARK::encode");
|
||||
let (comm, decomm) = inst.inst.commit(&gens.gens_r1cs_eval);
|
||||
timer_encode.stop();
|
||||
(
|
||||
ComputationCommitment { comm },
|
||||
ComputationDecommitment { decomm },
|
||||
)
|
||||
}
|
||||
|
||||
/// A method to produce a SNARK proof of the satisfiability of an R1CS instance
|
||||
pub fn prove(
|
||||
inst: &Instance,
|
||||
decomm: &ComputationDecommitment,
|
||||
vars: Vec<Scalar>,
|
||||
input: &[Scalar],
|
||||
gens: &SNARKGens,
|
||||
transcript: &mut Transcript,
|
||||
) -> Self {
|
||||
let timer_prove = Timer::new("SNARK::prove");
|
||||
|
||||
// we create a Transcript object seeded with a random Scalar
|
||||
// to aid the prover produce its randomness
|
||||
let mut random_tape = RandomTape::new(b"proof");
|
||||
transcript.append_protocol_name(SNARK::protocol_name());
|
||||
let (r1cs_sat_proof, rx, ry) = {
|
||||
let (proof, rx, ry) = R1CSProof::prove(
|
||||
&inst.inst,
|
||||
vars,
|
||||
input,
|
||||
&gens.gens_r1cs_sat,
|
||||
transcript,
|
||||
&mut random_tape,
|
||||
);
|
||||
let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap();
|
||||
Timer::print(&format!("len_r1cs_sat_proof {:?}", proof_encoded.len()));
|
||||
|
||||
(proof, rx, ry)
|
||||
};
|
||||
|
||||
// We send evaluations of A, B, C at r = (rx, ry) as claims
|
||||
// to enable the verifier complete the first sum-check
|
||||
let timer_eval = Timer::new("eval_sparse_polys");
|
||||
let inst_evals = {
|
||||
let (Ar, Br, Cr) = inst.inst.evaluate(&rx, &ry);
|
||||
Ar.append_to_transcript(b"Ar_claim", transcript);
|
||||
Br.append_to_transcript(b"Br_claim", transcript);
|
||||
Cr.append_to_transcript(b"Cr_claim", transcript);
|
||||
(Ar, Br, Cr)
|
||||
};
|
||||
timer_eval.stop();
|
||||
|
||||
let r1cs_eval_proof = {
|
||||
let proof = R1CSEvalProof::prove(
|
||||
&decomm.decomm,
|
||||
&rx,
|
||||
&ry,
|
||||
&inst_evals,
|
||||
&gens.gens_r1cs_eval,
|
||||
transcript,
|
||||
&mut random_tape,
|
||||
);
|
||||
|
||||
let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap();
|
||||
Timer::print(&format!("len_r1cs_eval_proof {:?}", proof_encoded.len()));
|
||||
proof
|
||||
};
|
||||
|
||||
timer_prove.stop();
|
||||
SNARK {
|
||||
r1cs_sat_proof,
|
||||
inst_evals,
|
||||
r1cs_eval_proof,
|
||||
}
|
||||
}
|
||||
|
||||
/// A method to verify the SNARK proof of the satisfiability of an R1CS instance
|
||||
pub fn verify(
|
||||
&self,
|
||||
comm: &ComputationCommitment,
|
||||
input: &[Scalar],
|
||||
transcript: &mut Transcript,
|
||||
gens: &SNARKGens,
|
||||
) -> Result<(), ProofVerifyError> {
|
||||
let timer_verify = Timer::new("SNARK::verify");
|
||||
transcript.append_protocol_name(SNARK::protocol_name());
|
||||
|
||||
let timer_sat_proof = Timer::new("verify_sat_proof");
|
||||
assert_eq!(input.len(), comm.comm.get_num_inputs());
|
||||
let (rx, ry) = self
|
||||
.r1cs_sat_proof
|
||||
.verify(
|
||||
comm.comm.get_num_vars(),
|
||||
comm.comm.get_num_cons(),
|
||||
input,
|
||||
&self.inst_evals,
|
||||
transcript,
|
||||
&gens.gens_r1cs_sat,
|
||||
)
|
||||
.unwrap();
|
||||
timer_sat_proof.stop();
|
||||
|
||||
let timer_eval_proof = Timer::new("verify_eval_proof");
|
||||
let (Ar, Br, Cr) = &self.inst_evals;
|
||||
Ar.append_to_transcript(b"Ar_claim", transcript);
|
||||
Br.append_to_transcript(b"Br_claim", transcript);
|
||||
Cr.append_to_transcript(b"Cr_claim", transcript);
|
||||
assert!(self
|
||||
.r1cs_eval_proof
|
||||
.verify(
|
||||
&comm.comm,
|
||||
&rx,
|
||||
&ry,
|
||||
&self.inst_evals,
|
||||
&gens.gens_r1cs_eval,
|
||||
transcript
|
||||
)
|
||||
.is_ok());
|
||||
timer_eval_proof.stop();
|
||||
timer_verify.stop();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// `NIZKGens` holds public parameters for producing and verifying proofs with the Spartan NIZK
|
||||
pub struct NIZKGens {
|
||||
gens_r1cs_sat: R1CSGens,
|
||||
}
|
||||
|
||||
impl NIZKGens {
|
||||
/// Constructs a new `NIZKGens` given the size of the R1CS statement
|
||||
pub fn new(num_cons: usize, num_vars: usize) -> Self {
|
||||
let gens_r1cs_sat = R1CSGens::new(b"gens_r1cs_sat", num_cons, num_vars);
|
||||
NIZKGens { gens_r1cs_sat }
|
||||
}
|
||||
}
|
||||
|
||||
/// `NIZK` holds a proof produced by Spartan NIZK
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct NIZK {
|
||||
r1cs_sat_proof: R1CSProof,
|
||||
r: (Vec<Scalar>, Vec<Scalar>),
|
||||
}
|
||||
|
||||
impl NIZK {
|
||||
fn protocol_name() -> &'static [u8] {
|
||||
b"Spartan NIZK proof"
|
||||
}
|
||||
|
||||
/// A method to produce a NIZK proof of the satisfiability of an R1CS instance
|
||||
pub fn prove(
|
||||
inst: &Instance,
|
||||
vars: Vec<Scalar>,
|
||||
input: &[Scalar],
|
||||
gens: &NIZKGens,
|
||||
transcript: &mut Transcript,
|
||||
) -> Self {
|
||||
let timer_prove = Timer::new("NIZK::prove");
|
||||
// we create a Transcript object seeded with a random Scalar
|
||||
// to aid the prover produce its randomness
|
||||
let mut random_tape = RandomTape::new(b"proof");
|
||||
transcript.append_protocol_name(NIZK::protocol_name());
|
||||
let (r1cs_sat_proof, rx, ry) = {
|
||||
let (proof, rx, ry) = R1CSProof::prove(
|
||||
&inst.inst,
|
||||
vars,
|
||||
input,
|
||||
&gens.gens_r1cs_sat,
|
||||
transcript,
|
||||
&mut random_tape,
|
||||
);
|
||||
let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap();
|
||||
Timer::print(&format!("len_r1cs_sat_proof {:?}", proof_encoded.len()));
|
||||
(proof, rx, ry)
|
||||
};
|
||||
|
||||
timer_prove.stop();
|
||||
NIZK {
|
||||
r1cs_sat_proof,
|
||||
r: (rx, ry),
|
||||
}
|
||||
}
|
||||
|
||||
/// A method to verify a NIZK proof of the satisfiability of an R1CS instance
|
||||
pub fn verify(
|
||||
&self,
|
||||
inst: &Instance,
|
||||
input: &[Scalar],
|
||||
transcript: &mut Transcript,
|
||||
gens: &NIZKGens,
|
||||
) -> Result<(), ProofVerifyError> {
|
||||
let timer_verify = Timer::new("NIZK::verify");
|
||||
|
||||
transcript.append_protocol_name(NIZK::protocol_name());
|
||||
|
||||
// We send evaluations of A, B, C at r = (rx, ry) as claims
|
||||
// to enable the verifier complete the first sum-check
|
||||
let timer_eval = Timer::new("eval_sparse_polys");
|
||||
let (claimed_rx, claimed_ry) = &self.r;
|
||||
let inst_evals = inst.inst.evaluate(claimed_rx, claimed_ry);
|
||||
timer_eval.stop();
|
||||
|
||||
let timer_sat_proof = Timer::new("verify_sat_proof");
|
||||
assert_eq!(input.len(), inst.inst.get_num_inputs());
|
||||
let (rx, ry) = self
|
||||
.r1cs_sat_proof
|
||||
.verify(
|
||||
inst.inst.get_num_vars(),
|
||||
inst.inst.get_num_cons(),
|
||||
input,
|
||||
&inst_evals,
|
||||
transcript,
|
||||
&gens.gens_r1cs_sat,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// verify if claimed rx and ry are correct
|
||||
assert_eq!(rx, *claimed_rx);
|
||||
assert_eq!(ry, *claimed_ry);
|
||||
timer_sat_proof.stop();
|
||||
timer_verify.stop();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
pub fn check_snark() {
|
||||
let num_vars = 256;
|
||||
let num_cons = num_vars;
|
||||
let num_inputs = 10;
|
||||
let (inst, vars, inputs) = Instance::new(num_cons, num_vars, num_inputs);
|
||||
|
||||
// produce public generators
|
||||
let gens = SNARKGens::new(num_cons, num_vars, num_inputs, num_cons);
|
||||
|
||||
// create a commitment to R1CSInstance
|
||||
let (comm, decomm) = SNARK::encode(&inst, &gens);
|
||||
|
||||
// produce a proof
|
||||
let mut prover_transcript = Transcript::new(b"example");
|
||||
let proof = SNARK::prove(&inst, &decomm, vars, &inputs, &gens, &mut prover_transcript);
|
||||
|
||||
// verify the proof
|
||||
let mut verifier_transcript = Transcript::new(b"example");
|
||||
assert!(proof
|
||||
.verify(&comm, &inputs, &mut verifier_transcript, &gens)
|
||||
.is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! This module is an adaptation of code from the bulletproofs crate.
|
||||
//! See NOTICE.md for more details
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(clippy::type_complexity)]
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
@@ -6,10 +6,8 @@ use super::scalar::Scalar;
|
||||
use super::sparse_mlpoly::{
|
||||
MultiSparseMatPolynomialAsDense, SparseMatEntry, SparseMatPolyCommitment,
|
||||
SparseMatPolyCommitmentGens, SparseMatPolyEvalProof, SparseMatPolynomial,
|
||||
SparseMatPolynomialSize,
|
||||
};
|
||||
use super::timer::Timer;
|
||||
use super::transcript::{AppendToTranscript, ProofTranscript};
|
||||
use merlin::Transcript;
|
||||
use rand::rngs::OsRng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -24,38 +22,23 @@ pub struct R1CSInstance {
|
||||
C: SparseMatPolynomial,
|
||||
}
|
||||
|
||||
pub struct R1CSInstanceSize {
|
||||
num_cons: usize,
|
||||
num_vars: usize,
|
||||
num_inputs: usize,
|
||||
size_A: SparseMatPolynomialSize,
|
||||
size_B: SparseMatPolynomialSize,
|
||||
size_C: SparseMatPolynomialSize,
|
||||
}
|
||||
|
||||
impl R1CSInstanceSize {
|
||||
pub fn get_num_cons(&self) -> usize {
|
||||
self.num_cons
|
||||
}
|
||||
|
||||
pub fn get_num_vars(&self) -> usize {
|
||||
self.num_vars
|
||||
}
|
||||
|
||||
pub fn get_num_inputs(&self) -> usize {
|
||||
self.num_inputs
|
||||
}
|
||||
}
|
||||
|
||||
pub struct R1CSCommitmentGens {
|
||||
gens: SparseMatPolyCommitmentGens,
|
||||
}
|
||||
|
||||
impl R1CSCommitmentGens {
|
||||
pub fn new(size: &R1CSInstanceSize, label: &'static [u8]) -> R1CSCommitmentGens {
|
||||
assert_eq!(size.size_A, size.size_B);
|
||||
assert_eq!(size.size_A, size.size_C);
|
||||
let gens = SparseMatPolyCommitmentGens::new(&size.size_A, 3, label);
|
||||
pub fn new(
|
||||
label: &'static [u8],
|
||||
num_cons: usize,
|
||||
num_vars: usize,
|
||||
num_inputs: usize,
|
||||
num_nz_entries: usize,
|
||||
) -> R1CSCommitmentGens {
|
||||
assert!(num_inputs < num_vars);
|
||||
let num_poly_vars_x = num_cons.log2();
|
||||
let num_poly_vars_y = (2 * num_vars).log2();
|
||||
let gens =
|
||||
SparseMatPolyCommitmentGens::new(label, num_poly_vars_x, num_poly_vars_y, num_nz_entries, 3);
|
||||
R1CSCommitmentGens { gens }
|
||||
}
|
||||
}
|
||||
@@ -85,29 +68,6 @@ impl R1CSCommitment {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct R1CSInstanceEvals {
|
||||
eval_A_r: Scalar,
|
||||
eval_B_r: Scalar,
|
||||
eval_C_r: Scalar,
|
||||
}
|
||||
|
||||
impl R1CSInstanceEvals {
|
||||
pub fn get_evaluations(&self) -> (Scalar, Scalar, Scalar) {
|
||||
(self.eval_A_r, self.eval_B_r, self.eval_C_r)
|
||||
}
|
||||
}
|
||||
|
||||
impl AppendToTranscript for R1CSInstanceEvals {
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) {
|
||||
transcript.append_message(label, b"R1CSInstanceEvals_begin");
|
||||
transcript.append_scalar(b"Ar_eval", &self.eval_A_r);
|
||||
transcript.append_scalar(b"Br_eval", &self.eval_B_r);
|
||||
transcript.append_scalar(b"Cr_eval", &self.eval_C_r);
|
||||
transcript.append_message(label, b"R1CSInstanceEvals_end");
|
||||
}
|
||||
}
|
||||
|
||||
impl R1CSInstance {
|
||||
pub fn new(
|
||||
num_cons: usize,
|
||||
@@ -139,22 +99,15 @@ impl R1CSInstance {
|
||||
self.num_inputs
|
||||
}
|
||||
|
||||
pub fn size(&self) -> R1CSInstanceSize {
|
||||
R1CSInstanceSize {
|
||||
num_cons: self.num_cons,
|
||||
num_vars: self.num_vars,
|
||||
num_inputs: self.num_inputs,
|
||||
size_A: self.A.size(),
|
||||
size_B: self.B.size(),
|
||||
size_C: self.C.size(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn produce_synthetic_r1cs(
|
||||
num_cons: usize,
|
||||
num_vars: usize,
|
||||
num_inputs: usize,
|
||||
) -> (R1CSInstance, Vec<Scalar>, Vec<Scalar>) {
|
||||
Timer::print(&format!("number_of_constraints {}", num_cons));
|
||||
Timer::print(&format!("number_of_variables {}", num_vars));
|
||||
Timer::print(&format!("number_of_inputs {}", num_inputs));
|
||||
|
||||
let mut csprng: OsRng = OsRng;
|
||||
|
||||
// assert num_cons and num_vars are power of 2
|
||||
@@ -202,6 +155,10 @@ impl R1CSInstance {
|
||||
}
|
||||
}
|
||||
|
||||
Timer::print(&format!("number_non-zero_entries_A {}", A.len()));
|
||||
Timer::print(&format!("number_non-zero_entries_B {}", B.len()));
|
||||
Timer::print(&format!("number_non-zero_entries_C {}", C.len()));
|
||||
|
||||
let num_poly_vars_x = num_cons.log2();
|
||||
let num_poly_vars_y = (2 * num_vars).log2();
|
||||
let poly_A = SparseMatPolynomial::new(num_poly_vars_x, num_poly_vars_y, A);
|
||||
@@ -282,16 +239,9 @@ impl R1CSInstance {
|
||||
(evals_A, evals_B, evals_C)
|
||||
}
|
||||
|
||||
pub fn evaluate_with_tables(
|
||||
&self,
|
||||
evals_rx: &[Scalar],
|
||||
evals_ry: &[Scalar],
|
||||
) -> R1CSInstanceEvals {
|
||||
R1CSInstanceEvals {
|
||||
eval_A_r: self.A.evaluate_with_tables(evals_rx, evals_ry),
|
||||
eval_B_r: self.B.evaluate_with_tables(evals_rx, evals_ry),
|
||||
eval_C_r: self.C.evaluate_with_tables(evals_rx, evals_ry),
|
||||
}
|
||||
pub fn evaluate(&self, rx: &[Scalar], ry: &[Scalar]) -> (Scalar, Scalar, Scalar) {
|
||||
let evals = SparseMatPolynomial::multi_evaluate(&[&self.A, &self.B, &self.C], rx, ry);
|
||||
(evals[0], evals[1], evals[2])
|
||||
}
|
||||
|
||||
pub fn commit(&self, gens: &R1CSCommitmentGens) -> (R1CSCommitment, R1CSDecommitment) {
|
||||
@@ -321,7 +271,7 @@ impl R1CSEvalProof {
|
||||
decomm: &R1CSDecommitment,
|
||||
rx: &[Scalar], // point at which the polynomial is evaluated
|
||||
ry: &[Scalar],
|
||||
evals: &R1CSInstanceEvals,
|
||||
evals: &(Scalar, Scalar, Scalar),
|
||||
gens: &R1CSCommitmentGens,
|
||||
transcript: &mut Transcript,
|
||||
random_tape: &mut RandomTape,
|
||||
@@ -331,7 +281,7 @@ impl R1CSEvalProof {
|
||||
&decomm.dense,
|
||||
rx,
|
||||
ry,
|
||||
&[evals.eval_A_r, evals.eval_B_r, evals.eval_C_r],
|
||||
&[evals.0, evals.1, evals.2],
|
||||
&gens.gens,
|
||||
transcript,
|
||||
random_tape,
|
||||
@@ -346,7 +296,7 @@ impl R1CSEvalProof {
|
||||
comm: &R1CSCommitment,
|
||||
rx: &[Scalar], // point at which the R1CS matrix polynomials are evaluated
|
||||
ry: &[Scalar],
|
||||
eval: &R1CSInstanceEvals,
|
||||
evals: &(Scalar, Scalar, Scalar),
|
||||
gens: &R1CSCommitmentGens,
|
||||
transcript: &mut Transcript,
|
||||
) -> Result<(), ProofVerifyError> {
|
||||
@@ -356,7 +306,7 @@ impl R1CSEvalProof {
|
||||
&comm.comm,
|
||||
rx,
|
||||
ry,
|
||||
&[eval.eval_A_r, eval.eval_B_r, eval.eval_C_r],
|
||||
&[evals.0, evals.1, evals.2],
|
||||
&gens.gens,
|
||||
transcript
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@ use super::errors::ProofVerifyError;
|
||||
use super::group::{CompressedGroup, GroupElement, VartimeMultiscalarMul};
|
||||
use super::math::Math;
|
||||
use super::nizk::{EqualityProof, KnowledgeProof, ProductProof};
|
||||
use super::r1csinstance::{R1CSInstance, R1CSInstanceEvals};
|
||||
use super::r1csinstance::R1CSInstance;
|
||||
use super::random::RandomTape;
|
||||
use super::scalar::Scalar;
|
||||
use super::sparse_mlpoly::{SparsePolyEntry, SparsePolynomial};
|
||||
@@ -66,7 +66,7 @@ pub struct R1CSGens {
|
||||
}
|
||||
|
||||
impl R1CSGens {
|
||||
pub fn new(_num_cons: usize, num_vars: usize, label: &'static [u8]) -> Self {
|
||||
pub fn new(label: &'static [u8], _num_cons: usize, num_vars: usize) -> Self {
|
||||
let num_poly_vars = num_vars.log2();
|
||||
let gens_pc = PolyCommitmentGens::new(num_poly_vars, label);
|
||||
let gens_sc = R1CSSumcheckGens::new(label, &gens_pc.gens.gens_1);
|
||||
@@ -162,7 +162,7 @@ impl R1CSProof {
|
||||
let poly_vars = DensePolynomial::new(vars.clone());
|
||||
|
||||
// produce a commitment to the satisfying assignment
|
||||
let (comm_vars, blinds_vars) = poly_vars.commit(true, &gens.gens_pc, Some(random_tape));
|
||||
let (comm_vars, blinds_vars) = poly_vars.commit(&gens.gens_pc, Some(random_tape));
|
||||
|
||||
// add the commitment to the prover's transcript
|
||||
comm_vars.append_to_transcript(b"poly_commitment", transcript);
|
||||
@@ -352,7 +352,7 @@ impl R1CSProof {
|
||||
num_vars: usize,
|
||||
num_cons: usize,
|
||||
input: &[Scalar],
|
||||
evals: &R1CSInstanceEvals,
|
||||
evals: &(Scalar, Scalar, Scalar),
|
||||
transcript: &mut Transcript,
|
||||
gens: &R1CSGens,
|
||||
) -> Result<(Vec<Scalar>, Vec<Scalar>), ProofVerifyError> {
|
||||
@@ -489,7 +489,7 @@ impl R1CSProof {
|
||||
);
|
||||
|
||||
// perform the final check in the second sum-check protocol
|
||||
let (eval_A_r, eval_B_r, eval_C_r) = evals.get_evaluations();
|
||||
let (eval_A_r, eval_B_r, eval_C_r) = evals;
|
||||
let expected_claim_post_phase2 =
|
||||
((r_A * eval_A_r + r_B * eval_B_r + r_C * eval_C_r) * comm_eval_Z_at_ry).compress();
|
||||
// verify proof that expected_claim_post_phase1 == claim_post_phase1
|
||||
@@ -597,7 +597,7 @@ mod tests {
|
||||
let num_inputs = 10;
|
||||
let (inst, vars, input) = R1CSInstance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
|
||||
|
||||
let gens = R1CSGens::new(num_cons, num_vars, b"test-m");
|
||||
let gens = R1CSGens::new(b"test-m", num_cons, num_vars);
|
||||
|
||||
let mut random_tape = RandomTape::new(b"proof");
|
||||
let mut prover_transcript = Transcript::new(b"example");
|
||||
@@ -610,10 +610,8 @@ mod tests {
|
||||
&mut random_tape,
|
||||
);
|
||||
|
||||
let eval_table_rx = EqPolynomial::new(rx).evals();
|
||||
let eval_table_ry = EqPolynomial::new(ry).evals();
|
||||
let inst_evals = inst.evaluate_with_tables(&eval_table_rx, &eval_table_ry);
|
||||
|
||||
let inst_evals = inst.evaluate(&rx, &ry);
|
||||
|
||||
let mut verifier_transcript = Transcript::new(b"example");
|
||||
assert!(proof
|
||||
.verify(
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
//! This module provides an implementation of the Curve25519's scalar field $\mathbb{F}_q$
|
||||
//! where `q = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed`
|
||||
//! The entire file is an adaptation from bls12-381 crate. We modify various constants (MODULUS, R, R2, etc.) to appropriate values for Curve25519 and update tests
|
||||
//! We borrow the `invert` method from curve25519-dalek crate
|
||||
//! This module is an adaptation of code from the bls12-381 crate.
|
||||
//! We modify various constants (MODULUS, R, R2, etc.) to appropriate values for Curve25519 and update tests
|
||||
//! We borrow the `invert` method from the curve25519-dalek crate.
|
||||
//! See NOTICE.md for more details
|
||||
#![allow(clippy::all)]
|
||||
use core::borrow::Borrow;
|
||||
|
||||
@@ -51,18 +51,22 @@ impl Derefs {
|
||||
pub fn new(row_ops_val: Vec<DensePolynomial>, col_ops_val: Vec<DensePolynomial>) -> Self {
|
||||
assert_eq!(row_ops_val.len(), col_ops_val.len());
|
||||
|
||||
// combine all polynomials into a single polynomial (used below to produce a single commitment)
|
||||
let comb = DensePolynomial::merge(row_ops_val.iter().chain(col_ops_val.iter()));
|
||||
let derefs = {
|
||||
// combine all polynomials into a single polynomial (used below to produce a single commitment)
|
||||
let comb = DensePolynomial::merge(row_ops_val.iter().chain(col_ops_val.iter()));
|
||||
|
||||
Derefs {
|
||||
row_ops_val,
|
||||
col_ops_val,
|
||||
comb,
|
||||
}
|
||||
Derefs {
|
||||
row_ops_val,
|
||||
col_ops_val,
|
||||
comb,
|
||||
}
|
||||
};
|
||||
|
||||
derefs
|
||||
}
|
||||
|
||||
pub fn commit(&self, gens: &PolyCommitmentGens) -> DerefsCommitment {
|
||||
let (comm_ops_val, _blinds) = self.comb.commit(false, gens, None);
|
||||
let (comm_ops_val, _blinds) = self.comb.commit(gens, None);
|
||||
DerefsCommitment { comm_ops_val }
|
||||
}
|
||||
}
|
||||
@@ -91,25 +95,28 @@ impl DerefsEvalProof {
|
||||
evals.append_to_transcript(b"evals_ops_val", transcript);
|
||||
|
||||
// n-to-1 reduction
|
||||
let challenges = transcript.challenge_vector(b"challenge_combine_n_to_one", evals.len().log2());
|
||||
let mut poly_evals = DensePolynomial::new(evals);
|
||||
for i in (0..challenges.len()).rev() {
|
||||
poly_evals.bound_poly_var_bot(&challenges[i]);
|
||||
}
|
||||
assert_eq!(poly_evals.len(), 1);
|
||||
let joint_claim_eval = poly_evals[0];
|
||||
let mut r_joint = challenges;
|
||||
r_joint.extend(r);
|
||||
|
||||
debug_assert_eq!(joint_poly.evaluate(&r_joint), joint_claim_eval);
|
||||
let (r_joint, eval_joint) = {
|
||||
let challenges =
|
||||
transcript.challenge_vector(b"challenge_combine_n_to_one", evals.len().log2());
|
||||
let mut poly_evals = DensePolynomial::new(evals);
|
||||
for i in (0..challenges.len()).rev() {
|
||||
poly_evals.bound_poly_var_bot(&challenges[i]);
|
||||
}
|
||||
assert_eq!(poly_evals.len(), 1);
|
||||
let joint_claim_eval = poly_evals[0];
|
||||
let mut r_joint = challenges;
|
||||
r_joint.extend(r);
|
||||
|
||||
debug_assert_eq!(joint_poly.evaluate(&r_joint), joint_claim_eval);
|
||||
(r_joint, joint_claim_eval)
|
||||
};
|
||||
// decommit the joint polynomial at r_joint
|
||||
joint_claim_eval.append_to_transcript(b"joint_claim_eval", transcript);
|
||||
eval_joint.append_to_transcript(b"joint_claim_eval", transcript);
|
||||
let (proof_derefs, _comm_derefs_eval) = PolyEvalProof::prove(
|
||||
joint_poly,
|
||||
None,
|
||||
&r_joint,
|
||||
&joint_claim_eval,
|
||||
&eval_joint,
|
||||
None,
|
||||
gens,
|
||||
transcript,
|
||||
@@ -131,10 +138,12 @@ impl DerefsEvalProof {
|
||||
) -> Self {
|
||||
transcript.append_protocol_name(DerefsEvalProof::protocol_name());
|
||||
|
||||
let mut evals = eval_row_ops_val_vec.to_owned();
|
||||
evals.extend(eval_col_ops_val_vec);
|
||||
evals.resize(evals.len().next_power_of_two(), Scalar::zero());
|
||||
|
||||
let evals = {
|
||||
let mut evals = eval_row_ops_val_vec.to_owned();
|
||||
evals.extend(eval_col_ops_val_vec);
|
||||
evals.resize(evals.len().next_power_of_two(), Scalar::zero());
|
||||
evals
|
||||
};
|
||||
let proof_derefs =
|
||||
DerefsEvalProof::prove_single(&derefs.comb, r, evals, gens, transcript, random_tape);
|
||||
|
||||
@@ -279,22 +288,6 @@ pub struct MultiSparseMatPolynomialAsDense {
|
||||
comb_mem: DensePolynomial,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SparseMatPolynomialSize {
|
||||
size_ops: usize,
|
||||
size_mem: usize,
|
||||
size_derefs: usize,
|
||||
}
|
||||
|
||||
impl PartialEq for SparseMatPolynomialSize {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.size_derefs == other.size_derefs
|
||||
&& self.size_mem == other.size_mem
|
||||
&& self.size_ops == other.size_ops
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SparseMatPolyCommitmentGens {
|
||||
gens_ops: PolyCommitmentGens,
|
||||
gens_mem: PolyCommitmentGens,
|
||||
@@ -303,13 +296,21 @@ pub struct SparseMatPolyCommitmentGens {
|
||||
|
||||
impl SparseMatPolyCommitmentGens {
|
||||
pub fn new(
|
||||
size: &SparseMatPolynomialSize,
|
||||
batch_size: usize,
|
||||
label: &'static [u8],
|
||||
num_vars_x: usize,
|
||||
num_vars_y: usize,
|
||||
num_nz_entries: usize,
|
||||
batch_size: usize,
|
||||
) -> SparseMatPolyCommitmentGens {
|
||||
let num_vars_ops = size.size_ops + (batch_size * 5).next_power_of_two().log2();
|
||||
let num_vars_mem = size.size_mem + 1;
|
||||
let num_vars_derefs = size.size_derefs + batch_size.next_power_of_two().log2();
|
||||
let num_vars_ops =
|
||||
num_nz_entries.next_power_of_two().log2() + (batch_size * 5).next_power_of_two().log2();
|
||||
let num_vars_mem = if num_vars_x > num_vars_y {
|
||||
num_vars_x
|
||||
} else {
|
||||
num_vars_y
|
||||
} + 1;
|
||||
let num_vars_derefs =
|
||||
num_nz_entries.next_power_of_two().log2() + (batch_size * 2).next_power_of_two().log2();
|
||||
|
||||
let gens_ops = PolyCommitmentGens::new(num_vars_ops, label);
|
||||
let gens_mem = PolyCommitmentGens::new(num_vars_mem, label);
|
||||
@@ -416,19 +417,7 @@ impl SparseMatPolynomial {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> SparseMatPolynomialSize {
|
||||
let dense = SparseMatPolynomial::multi_sparse_to_dense_rep(&[&self]);
|
||||
|
||||
assert_eq!(dense.col.audit_ts.len(), dense.row.audit_ts.len());
|
||||
|
||||
SparseMatPolynomialSize {
|
||||
size_mem: dense.row.audit_ts.get_num_vars(),
|
||||
size_ops: dense.row.read_ts[0].get_num_vars(),
|
||||
size_derefs: dense.row.read_ts[0].get_num_vars() + 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn evaluate_with_tables(&self, eval_table_rx: &[Scalar], eval_table_ry: &[Scalar]) -> Scalar {
|
||||
fn evaluate_with_tables(&self, eval_table_rx: &[Scalar], eval_table_ry: &[Scalar]) -> Scalar {
|
||||
assert_eq!(self.num_vars_x.pow2(), eval_table_rx.len());
|
||||
assert_eq!(self.num_vars_y.pow2(), eval_table_ry.len());
|
||||
|
||||
@@ -442,20 +431,17 @@ impl SparseMatPolynomial {
|
||||
.sum()
|
||||
}
|
||||
|
||||
pub fn evaluate(&self, rx: &[Scalar], ry: &[Scalar]) -> Scalar {
|
||||
pub fn multi_evaluate(
|
||||
polys: &[&SparseMatPolynomial],
|
||||
rx: &[Scalar],
|
||||
ry: &[Scalar],
|
||||
) -> Vec<Scalar> {
|
||||
let eval_table_rx = EqPolynomial::new(rx.to_vec()).evals();
|
||||
let eval_table_ry = EqPolynomial::new(ry.to_vec()).evals();
|
||||
assert_eq!(self.num_vars_x.pow2(), eval_table_rx.len());
|
||||
assert_eq!(self.num_vars_y.pow2(), eval_table_ry.len());
|
||||
|
||||
(0..self.M.len())
|
||||
.map(|i| {
|
||||
let row = self.M[i].row;
|
||||
let col = self.M[i].col;
|
||||
let val = &self.M[i].val;
|
||||
eval_table_rx[row] * eval_table_ry[col] * val
|
||||
})
|
||||
.sum()
|
||||
(0..polys.len())
|
||||
.map(|i| polys[i].evaluate_with_tables(&eval_table_rx, &eval_table_ry))
|
||||
.collect::<Vec<Scalar>>()
|
||||
}
|
||||
|
||||
pub fn multiply_vec(&self, num_rows: usize, num_cols: usize, z: &[Scalar]) -> Vec<Scalar> {
|
||||
@@ -498,8 +484,8 @@ impl SparseMatPolynomial {
|
||||
let batch_size = sparse_polys.len();
|
||||
let dense = SparseMatPolynomial::multi_sparse_to_dense_rep(sparse_polys);
|
||||
|
||||
let (comm_comb_ops, _blinds_comb_ops) = dense.comb_ops.commit(false, &gens.gens_ops, None);
|
||||
let (comm_comb_mem, _blinds_comb_mem) = dense.comb_mem.commit(false, &gens.gens_mem, None);
|
||||
let (comm_comb_ops, _blinds_comb_ops) = dense.comb_ops.commit(&gens.gens_ops, None);
|
||||
let (comm_comb_mem, _blinds_comb_mem) = dense.comb_mem.commit(&gens.gens_mem, None);
|
||||
|
||||
(
|
||||
SparseMatPolyCommitment {
|
||||
@@ -885,7 +871,6 @@ impl HashLayerProof {
|
||||
|
||||
// read
|
||||
for i in 0..eval_ops_addr.len() {
|
||||
// TODO: should we verify length of these?
|
||||
let hash_read_at_rand_ops =
|
||||
hash_func(&eval_ops_addr[i], &eval_ops_val[i], &eval_read_ts[i]) - r_multiset_check; // verify the claim_last of init chunk
|
||||
assert_eq!(&hash_read_at_rand_ops, &claim_read[i]);
|
||||
@@ -1674,8 +1659,13 @@ mod tests {
|
||||
}
|
||||
|
||||
let poly_M = SparseMatPolynomial::new(num_vars_x, num_vars_y, M);
|
||||
let poly_M_size = poly_M.size();
|
||||
let gens = SparseMatPolyCommitmentGens::new(&poly_M_size, 3, b"gens_sparse_poly");
|
||||
let gens = SparseMatPolyCommitmentGens::new(
|
||||
b"gens_sparse_poly",
|
||||
num_vars_x,
|
||||
num_vars_y,
|
||||
num_nz_entries,
|
||||
3,
|
||||
);
|
||||
|
||||
// commitment
|
||||
let (poly_comm, dense) =
|
||||
@@ -1688,8 +1678,8 @@ mod tests {
|
||||
let ry: Vec<Scalar> = (0..num_vars_y)
|
||||
.map(|_i| Scalar::random(&mut csprng))
|
||||
.collect::<Vec<Scalar>>();
|
||||
let eval = poly_M.evaluate(&rx, &ry);
|
||||
let evals = vec![eval, eval, eval];
|
||||
let eval = SparseMatPolynomial::multi_evaluate(&[&poly_M], &rx, &ry);
|
||||
let evals = vec![eval[0], eval[0], eval[0]];
|
||||
|
||||
let mut random_tape = RandomTape::new(b"proof");
|
||||
let mut prover_transcript = Transcript::new(b"example");
|
||||
|
||||
282
src/spartan.rs
282
src/spartan.rs
@@ -1,282 +0,0 @@
|
||||
use super::dense_mlpoly::EqPolynomial;
|
||||
use super::errors::ProofVerifyError;
|
||||
use super::r1csinstance::{
|
||||
R1CSCommitment, R1CSCommitmentGens, R1CSDecommitment, R1CSEvalProof, R1CSInstance,
|
||||
R1CSInstanceEvals, R1CSInstanceSize,
|
||||
};
|
||||
use super::r1csproof::{R1CSGens, R1CSProof};
|
||||
use super::random::RandomTape;
|
||||
use super::scalar::Scalar;
|
||||
use super::timer::Timer;
|
||||
use super::transcript::{AppendToTranscript, ProofTranscript};
|
||||
use merlin::Transcript;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub struct SNARKGens {
|
||||
gens_r1cs_sat: R1CSGens,
|
||||
gens_r1cs_eval: R1CSCommitmentGens,
|
||||
}
|
||||
|
||||
impl SNARKGens {
|
||||
pub fn new(size: &R1CSInstanceSize) -> Self {
|
||||
let gens_r1cs_sat = R1CSGens::new(size.get_num_cons(), size.get_num_vars(), b"gens_r1cs_sat");
|
||||
let gens_r1cs_eval = R1CSCommitmentGens::new(size, b"gens_r1cs_eval");
|
||||
SNARKGens {
|
||||
gens_r1cs_sat,
|
||||
gens_r1cs_eval,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct SNARK {
|
||||
r1cs_sat_proof: R1CSProof,
|
||||
inst_evals: R1CSInstanceEvals,
|
||||
r1cs_eval_proof: R1CSEvalProof,
|
||||
}
|
||||
|
||||
impl SNARK {
|
||||
fn protocol_name() -> &'static [u8] {
|
||||
b"Spartan SNARK proof"
|
||||
}
|
||||
|
||||
/// A public computation to create a commitment to an R1CS instance
|
||||
pub fn encode(inst: &R1CSInstance, gens: &SNARKGens) -> (R1CSCommitment, R1CSDecommitment) {
|
||||
inst.commit(&gens.gens_r1cs_eval)
|
||||
}
|
||||
|
||||
/// A method to produce a proof of the satisfiability of an R1CS instance
|
||||
pub fn prove(
|
||||
inst: &R1CSInstance,
|
||||
decomm: &R1CSDecommitment,
|
||||
vars: Vec<Scalar>,
|
||||
input: &[Scalar],
|
||||
gens: &SNARKGens,
|
||||
transcript: &mut Transcript,
|
||||
) -> Self {
|
||||
// we create a Transcript object seeded with a random Scalar
|
||||
// to aid the prover produce its randomness
|
||||
let mut random_tape = RandomTape::new(b"proof");
|
||||
transcript.append_protocol_name(SNARK::protocol_name());
|
||||
let (r1cs_sat_proof, rx, ry) = {
|
||||
let (proof, rx, ry) = R1CSProof::prove(
|
||||
inst,
|
||||
vars,
|
||||
input,
|
||||
&gens.gens_r1cs_sat,
|
||||
transcript,
|
||||
&mut random_tape,
|
||||
);
|
||||
let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap();
|
||||
Timer::print(&format!("len_r1cs_sat_proof {:?}", proof_encoded.len()));
|
||||
|
||||
(proof, rx, ry)
|
||||
};
|
||||
|
||||
// We send evaluations of A, B, C at r = (rx, ry) as claims
|
||||
// to enable the verifier complete the first sum-check
|
||||
let timer_eval = Timer::new("eval_sparse_polys");
|
||||
let inst_evals = {
|
||||
let eval_table_rx = EqPolynomial::new(rx.clone()).evals();
|
||||
let eval_table_ry = EqPolynomial::new(ry.clone()).evals();
|
||||
inst.evaluate_with_tables(&eval_table_rx, &eval_table_ry)
|
||||
};
|
||||
inst_evals.append_to_transcript(b"r1cs_inst_evals", transcript);
|
||||
timer_eval.stop();
|
||||
|
||||
let r1cs_eval_proof = {
|
||||
let proof = R1CSEvalProof::prove(
|
||||
decomm,
|
||||
&rx,
|
||||
&ry,
|
||||
&inst_evals,
|
||||
&gens.gens_r1cs_eval,
|
||||
transcript,
|
||||
&mut random_tape,
|
||||
);
|
||||
|
||||
let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap();
|
||||
Timer::print(&format!("len_r1cs_eval_proof {:?}", proof_encoded.len()));
|
||||
proof
|
||||
};
|
||||
|
||||
SNARK {
|
||||
r1cs_sat_proof,
|
||||
inst_evals,
|
||||
r1cs_eval_proof,
|
||||
}
|
||||
}
|
||||
|
||||
/// A method to verify the proof of the satisfiability of an R1CS instance
|
||||
pub fn verify(
|
||||
&self,
|
||||
comm: &R1CSCommitment,
|
||||
input: &[Scalar],
|
||||
transcript: &mut Transcript,
|
||||
gens: &SNARKGens,
|
||||
) -> Result<(), ProofVerifyError> {
|
||||
transcript.append_protocol_name(SNARK::protocol_name());
|
||||
|
||||
let timer_sat_proof = Timer::new("verify_sat_proof");
|
||||
assert_eq!(input.len(), comm.get_num_inputs());
|
||||
let (rx, ry) = self
|
||||
.r1cs_sat_proof
|
||||
.verify(
|
||||
comm.get_num_vars(),
|
||||
comm.get_num_cons(),
|
||||
input,
|
||||
&self.inst_evals,
|
||||
transcript,
|
||||
&gens.gens_r1cs_sat,
|
||||
)
|
||||
.unwrap();
|
||||
timer_sat_proof.stop();
|
||||
|
||||
let timer_eval_proof = Timer::new("verify_eval_proof");
|
||||
self
|
||||
.inst_evals
|
||||
.append_to_transcript(b"r1cs_inst_evals", transcript);
|
||||
assert!(self
|
||||
.r1cs_eval_proof
|
||||
.verify(
|
||||
comm,
|
||||
&rx,
|
||||
&ry,
|
||||
&self.inst_evals,
|
||||
&gens.gens_r1cs_eval,
|
||||
transcript
|
||||
)
|
||||
.is_ok());
|
||||
timer_eval_proof.stop();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NIZKGens {
|
||||
gens_r1cs_sat: R1CSGens,
|
||||
}
|
||||
|
||||
impl NIZKGens {
|
||||
pub fn new(num_cons: usize, num_vars: usize) -> Self {
|
||||
let gens_r1cs_sat = R1CSGens::new(num_cons, num_vars, b"gens_r1cs_sat");
|
||||
NIZKGens { gens_r1cs_sat }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct NIZK {
|
||||
r1cs_sat_proof: R1CSProof,
|
||||
r: (Vec<Scalar>, Vec<Scalar>),
|
||||
}
|
||||
|
||||
impl NIZK {
|
||||
fn protocol_name() -> &'static [u8] {
|
||||
b"Spartan NIZK proof"
|
||||
}
|
||||
|
||||
/// A method to produce a proof of the satisfiability of an R1CS instance
|
||||
pub fn prove(
|
||||
inst: &R1CSInstance,
|
||||
vars: Vec<Scalar>,
|
||||
input: &[Scalar],
|
||||
gens: &NIZKGens,
|
||||
transcript: &mut Transcript,
|
||||
) -> Self {
|
||||
// we create a Transcript object seeded with a random Scalar
|
||||
// to aid the prover produce its randomness
|
||||
let mut random_tape = RandomTape::new(b"proof");
|
||||
transcript.append_protocol_name(NIZK::protocol_name());
|
||||
let (r1cs_sat_proof, rx, ry) = {
|
||||
let (proof, rx, ry) = R1CSProof::prove(
|
||||
inst,
|
||||
vars,
|
||||
input,
|
||||
&gens.gens_r1cs_sat,
|
||||
transcript,
|
||||
&mut random_tape,
|
||||
);
|
||||
let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap();
|
||||
Timer::print(&format!("len_r1cs_sat_proof {:?}", proof_encoded.len()));
|
||||
|
||||
(proof, rx, ry)
|
||||
};
|
||||
|
||||
NIZK {
|
||||
r1cs_sat_proof,
|
||||
r: (rx, ry),
|
||||
}
|
||||
}
|
||||
|
||||
/// A method to verify the proof of the satisfiability of an R1CS instance
|
||||
pub fn verify(
|
||||
&self,
|
||||
inst: &R1CSInstance,
|
||||
input: &[Scalar],
|
||||
transcript: &mut Transcript,
|
||||
gens: &NIZKGens,
|
||||
) -> Result<(), ProofVerifyError> {
|
||||
transcript.append_protocol_name(NIZK::protocol_name());
|
||||
|
||||
// We send evaluations of A, B, C at r = (rx, ry) as claims
|
||||
// to enable the verifier complete the first sum-check
|
||||
let timer_eval = Timer::new("eval_sparse_polys");
|
||||
let (claimed_rx, claimed_ry) = &self.r;
|
||||
let inst_evals = {
|
||||
let eval_table_rx = EqPolynomial::new(claimed_rx.clone()).evals();
|
||||
let eval_table_ry = EqPolynomial::new(claimed_ry.clone()).evals();
|
||||
inst.evaluate_with_tables(&eval_table_rx, &eval_table_ry)
|
||||
};
|
||||
timer_eval.stop();
|
||||
|
||||
let timer_sat_proof = Timer::new("verify_sat_proof");
|
||||
assert_eq!(input.len(), inst.get_num_inputs());
|
||||
let (rx, ry) = self
|
||||
.r1cs_sat_proof
|
||||
.verify(
|
||||
inst.get_num_vars(),
|
||||
inst.get_num_cons(),
|
||||
input,
|
||||
&inst_evals,
|
||||
transcript,
|
||||
&gens.gens_r1cs_sat,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// verify if claimed rx and ry are correct
|
||||
assert_eq!(rx, *claimed_rx);
|
||||
assert_eq!(ry, *claimed_ry);
|
||||
timer_sat_proof.stop();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
pub fn check_snark() {
|
||||
let num_vars = 256;
|
||||
let num_cons = num_vars;
|
||||
let num_inputs = 10;
|
||||
let (inst, vars, input) = R1CSInstance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
|
||||
let r1cs_size = inst.size();
|
||||
|
||||
// produce public generators
|
||||
let gens = SNARKGens::new(&r1cs_size);
|
||||
|
||||
// create a commitment to R1CSInstance
|
||||
let (comm, decomm) = SNARK::encode(&inst, &gens);
|
||||
|
||||
// produce a proof
|
||||
let mut prover_transcript = Transcript::new(b"example");
|
||||
let proof = SNARK::prove(&inst, &decomm, vars, &input, &gens, &mut prover_transcript);
|
||||
|
||||
// verify the proof
|
||||
let mut verifier_transcript = Transcript::new(b"example");
|
||||
assert!(proof
|
||||
.verify(&comm, &input, &mut verifier_transcript, &gens)
|
||||
.is_ok());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user