mirror of
https://github.com/arnaucube/testudo.git
synced 2026-01-12 16:51:28 +01:00
Arbitrary number of variables and contraints (#34)
* This commit makes adding an arbitrary number of variables and inputs possible and removes the
implementation leaking to the interface for
num_inps + 1 <= num_vars, num_vars: a power of 2, num_cons: a power of 2, but not 1.
1. When creating a new R1CS Instance throught the public interface,
it is required # constraints and # of vars be a power of 2. I remove
that requirement by padding with dummy constraints and vars until the nearest
power of 2.
2. The sumcheck protocol in src/sumcheck.rs does not work for 1 constraint, even
though 1 is a power of 2. I have to pad to a minimum of two constraints.
3. Added a test in src/r1csproof.rs called test_padded_constraints.
* Move test to src/lib.rs
* Remove padding metadata
* remove unused use
* Simplify padding to power of 2
* run cargo fmt
* Fix indexing bug
* Rayon is optional, depending on 'multicore' feature
* Update rust toolchain
* cargo fmt
* cleaner to track num_vars_padded and num_cons_padded
* cleanup
* further cleanup
* Cleanup & comments
* small fixes
* adjust code for padding constraints
* fix a bug with pad call
* add comment about num_nz_entries
* extend padding to NIZK methods
extend padding to NIZK methods
Co-authored-by: Lef Ioannidis <elefthei@seas.upenn.edu>
Co-authored-by: Srinath Setty <srinath@microsoft.com>
This commit is contained in:
2
.github/workflows/rust.yml
vendored
2
.github/workflows/rust.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Install
|
- name: Install
|
||||||
run: rustup default nightly-2021-01-03
|
run: rustup default nightly-2021-01-31
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build --verbose
|
run: cargo build --verbose
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ rand = "0.7.3"
|
|||||||
digest = "0.8.1"
|
digest = "0.8.1"
|
||||||
sha3 = "0.8.2"
|
sha3 = "0.8.2"
|
||||||
byteorder = "1.3.4"
|
byteorder = "1.3.4"
|
||||||
rayon = "1.3.0"
|
rayon = { version = "1.3.0", optional = true }
|
||||||
serde = { version = "1.0.106", features = ["derive"] }
|
serde = { version = "1.0.106", features = ["derive"] }
|
||||||
bincode = "1.2.1"
|
bincode = "1.2.1"
|
||||||
subtle = { version = "^2.2.3", default-features = false }
|
subtle = { version = "^2.2.3", default-features = false }
|
||||||
@@ -52,5 +52,5 @@ name = "nizk"
|
|||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
multicore = []
|
multicore = ["rayon"]
|
||||||
profile = []
|
profile = []
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ Here is another example to use the NIZK variant of the Spartan proof system:
|
|||||||
let num_inputs = 10;
|
let num_inputs = 10;
|
||||||
|
|
||||||
// produce public parameters
|
// produce public parameters
|
||||||
let gens = NIZKGens::new(num_cons, num_vars);
|
let gens = NIZKGens::new(num_cons, num_vars, num_inputs);
|
||||||
|
|
||||||
// ask the library to produce a synthentic R1CS instance
|
// ask the library to produce a synthentic R1CS instance
|
||||||
let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
|
let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
|
||||||
@@ -102,6 +102,7 @@ Here is another example to use the NIZK variant of the Spartan proof system:
|
|||||||
|
|
||||||
Finally, we provide an example that specifies a custom R1CS instance instead of using a synthetic instance
|
Finally, we provide an example that specifies a custom R1CS instance instead of using a synthetic instance
|
||||||
```rust
|
```rust
|
||||||
|
#![allow(non_snake_case)]
|
||||||
# extern crate curve25519_dalek;
|
# extern crate curve25519_dalek;
|
||||||
# extern crate libspartan;
|
# extern crate libspartan;
|
||||||
# extern crate merlin;
|
# extern crate merlin;
|
||||||
@@ -163,9 +164,9 @@ Finally, we provide an example that specifies a custom R1CS instance instead of
|
|||||||
|
|
||||||
// parameters of the R1CS instance rounded to the nearest power of two
|
// parameters of the R1CS instance rounded to the nearest power of two
|
||||||
let num_cons = 4;
|
let num_cons = 4;
|
||||||
let num_vars = 8;
|
let num_vars = 5;
|
||||||
let num_inputs = 2;
|
let num_inputs = 2;
|
||||||
let num_non_zero_entries = 8;
|
let num_non_zero_entries = 5;
|
||||||
|
|
||||||
// We will encode the above constraints into three matrices, where
|
// We will encode the above constraints into three matrices, where
|
||||||
// the coefficients in the matrix are in the little-endian byte order
|
// the coefficients in the matrix are in the little-endian byte order
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ fn nizk_prove_benchmark(c: &mut Criterion) {
|
|||||||
|
|
||||||
let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
|
let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
|
||||||
|
|
||||||
let gens = NIZKGens::new(num_cons, num_vars);
|
let gens = NIZKGens::new(num_cons, num_vars, num_inputs);
|
||||||
|
|
||||||
let name = format!("NIZK_prove_{}", num_vars);
|
let name = format!("NIZK_prove_{}", num_vars);
|
||||||
group.bench_function(&name, move |b| {
|
group.bench_function(&name, move |b| {
|
||||||
@@ -54,7 +54,7 @@ fn nizk_verify_benchmark(c: &mut Criterion) {
|
|||||||
let num_inputs = 10;
|
let num_inputs = 10;
|
||||||
let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
|
let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
|
||||||
|
|
||||||
let gens = NIZKGens::new(num_cons, num_vars);
|
let gens = NIZKGens::new(num_cons, num_vars, num_inputs);
|
||||||
|
|
||||||
// produce a proof of satisfiability
|
// produce a proof of satisfiability
|
||||||
let mut prover_transcript = Transcript::new(b"example");
|
let mut prover_transcript = Transcript::new(b"example");
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ pub fn main() {
|
|||||||
let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
|
let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
|
||||||
|
|
||||||
// produce public generators
|
// produce public generators
|
||||||
let gens = NIZKGens::new(num_cons, num_vars);
|
let gens = NIZKGens::new(num_cons, num_vars, num_inputs);
|
||||||
|
|
||||||
// produce a proof of satisfiability
|
// produce a proof of satisfiability
|
||||||
let mut prover_transcript = Transcript::new(b"nizk_example");
|
let mut prover_transcript = Transcript::new(b"nizk_example");
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ impl DensePolynomial {
|
|||||||
assert_eq!(L_size * R_size, self.Z.len());
|
assert_eq!(L_size * R_size, self.Z.len());
|
||||||
let C = (0..L_size)
|
let C = (0..L_size)
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.map(|&i| {
|
.map(|i| {
|
||||||
self.Z[R_size * i..R_size * (i + 1)]
|
self.Z[R_size * i..R_size * (i + 1)]
|
||||||
.commit(&blinds[i], gens)
|
.commit(&blinds[i], gens)
|
||||||
.compress()
|
.compress()
|
||||||
|
|||||||
256
src/lib.rs
256
src/lib.rs
@@ -10,10 +10,12 @@ extern crate curve25519_dalek;
|
|||||||
extern crate digest;
|
extern crate digest;
|
||||||
extern crate merlin;
|
extern crate merlin;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate rayon;
|
|
||||||
extern crate sha3;
|
extern crate sha3;
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
|
#[cfg(feature = "multicore")]
|
||||||
|
extern crate rayon;
|
||||||
|
|
||||||
mod commitments;
|
mod commitments;
|
||||||
mod dense_mlpoly;
|
mod dense_mlpoly;
|
||||||
mod errors;
|
mod errors;
|
||||||
@@ -31,6 +33,7 @@ mod timer;
|
|||||||
mod transcript;
|
mod transcript;
|
||||||
mod unipoly;
|
mod unipoly;
|
||||||
|
|
||||||
|
use core::cmp::max;
|
||||||
use errors::{ProofVerifyError, R1CSError};
|
use errors::{ProofVerifyError, R1CSError};
|
||||||
use merlin::Transcript;
|
use merlin::Transcript;
|
||||||
use r1csinstance::{
|
use r1csinstance::{
|
||||||
@@ -86,6 +89,22 @@ impl Assignment {
|
|||||||
assignment: assignment_scalar.unwrap(),
|
assignment: assignment_scalar.unwrap(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// pads Assignment to the specified length
|
||||||
|
fn pad(&self, len: usize) -> VarsAssignment {
|
||||||
|
// check that the new length is higher than current length
|
||||||
|
assert!(len > self.assignment.len());
|
||||||
|
|
||||||
|
let padded_assignment = {
|
||||||
|
let mut padded_assignment = self.assignment.clone();
|
||||||
|
padded_assignment.extend(vec![Scalar::zero(); len - self.assignment.len()]);
|
||||||
|
padded_assignment
|
||||||
|
};
|
||||||
|
|
||||||
|
VarsAssignment {
|
||||||
|
assignment: padded_assignment,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `VarsAssignment` holds an assignment of values to variables in an `Instance`
|
/// `VarsAssignment` holds an assignment of values to variables in an `Instance`
|
||||||
@@ -109,20 +128,37 @@ impl Instance {
|
|||||||
B: &Vec<(usize, usize, [u8; 32])>,
|
B: &Vec<(usize, usize, [u8; 32])>,
|
||||||
C: &Vec<(usize, usize, [u8; 32])>,
|
C: &Vec<(usize, usize, [u8; 32])>,
|
||||||
) -> Result<Instance, R1CSError> {
|
) -> Result<Instance, R1CSError> {
|
||||||
// check that num_cons is power of 2
|
let (num_vars_padded, num_cons_padded) = {
|
||||||
if num_cons.next_power_of_two() != num_cons {
|
let num_vars_padded = {
|
||||||
return Err(R1CSError::NonPowerOfTwoCons);
|
let mut num_vars_padded = num_vars;
|
||||||
}
|
|
||||||
|
|
||||||
// check that the number of variables is a power of 2
|
// ensure that num_inputs + 1 <= num_vars
|
||||||
if num_vars.next_power_of_two() != num_vars {
|
num_vars_padded = max(num_vars_padded, num_inputs + 1);
|
||||||
return Err(R1CSError::NonPowerOfTwoVars);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check that num_inputs + 1 <= num_vars
|
// ensure that num_vars_padded a power of two
|
||||||
if num_inputs >= num_vars {
|
if num_vars_padded.next_power_of_two() != num_vars_padded {
|
||||||
return Err(R1CSError::InvalidNumberOfInputs);
|
num_vars_padded = num_vars_padded.next_power_of_two();
|
||||||
}
|
}
|
||||||
|
num_vars_padded
|
||||||
|
};
|
||||||
|
|
||||||
|
let num_cons_padded = {
|
||||||
|
let mut num_cons_padded = num_cons;
|
||||||
|
|
||||||
|
// ensure that num_cons_padded is at least 2
|
||||||
|
if num_cons_padded == 0 || num_cons_padded == 1 {
|
||||||
|
num_cons_padded = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure that num_cons_padded is power of 2
|
||||||
|
if num_cons.next_power_of_two() != num_cons {
|
||||||
|
num_cons_padded = num_cons.next_power_of_two();
|
||||||
|
}
|
||||||
|
num_cons_padded
|
||||||
|
};
|
||||||
|
|
||||||
|
(num_vars_padded, num_cons_padded)
|
||||||
|
};
|
||||||
|
|
||||||
let bytes_to_scalar =
|
let bytes_to_scalar =
|
||||||
|tups: &Vec<(usize, usize, [u8; 32])>| -> Result<Vec<(usize, usize, Scalar)>, R1CSError> {
|
|tups: &Vec<(usize, usize, [u8; 32])>| -> Result<Vec<(usize, usize, Scalar)>, R1CSError> {
|
||||||
@@ -142,11 +178,26 @@ impl Instance {
|
|||||||
|
|
||||||
let val = Scalar::from_bytes(&val_bytes);
|
let val = Scalar::from_bytes(&val_bytes);
|
||||||
if val.is_some().unwrap_u8() == 1 {
|
if val.is_some().unwrap_u8() == 1 {
|
||||||
mat.push((row, col, val.unwrap()));
|
// if col >= num_vars, it means that it is referencing a 1 or input in the satisfying
|
||||||
|
// assignment
|
||||||
|
if col >= num_vars {
|
||||||
|
mat.push((row, col + num_vars_padded - num_vars, val.unwrap()));
|
||||||
|
} else {
|
||||||
|
mat.push((row, col, val.unwrap()));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(R1CSError::InvalidScalar);
|
return Err(R1CSError::InvalidScalar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pad with additional constraints up until num_cons_padded if the original constraints were 0 or 1
|
||||||
|
// we do not need to pad otherwise because the dummy constraints are implicit in the sum-check protocol
|
||||||
|
if num_cons == 0 || num_cons == 1 {
|
||||||
|
for i in tups.len()..num_cons_padded {
|
||||||
|
mat.push((i, num_vars, Scalar::zero()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(mat)
|
Ok(mat)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -166,8 +217,8 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let inst = R1CSInstance::new(
|
let inst = R1CSInstance::new(
|
||||||
num_cons,
|
num_cons_padded,
|
||||||
num_vars,
|
num_vars_padded,
|
||||||
num_inputs,
|
num_inputs,
|
||||||
&A_scalar.unwrap(),
|
&A_scalar.unwrap(),
|
||||||
&B_scalar.unwrap(),
|
&B_scalar.unwrap(),
|
||||||
@@ -183,15 +234,31 @@ impl Instance {
|
|||||||
vars: &VarsAssignment,
|
vars: &VarsAssignment,
|
||||||
inputs: &InputsAssignment,
|
inputs: &InputsAssignment,
|
||||||
) -> Result<bool, R1CSError> {
|
) -> Result<bool, R1CSError> {
|
||||||
if vars.assignment.len() != self.inst.get_num_vars() {
|
if vars.assignment.len() > self.inst.get_num_vars() {
|
||||||
return Err(R1CSError::InvalidNumberOfVars);
|
return Err(R1CSError::InvalidNumberOfInputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if inputs.assignment.len() != self.inst.get_num_inputs() {
|
if inputs.assignment.len() != self.inst.get_num_inputs() {
|
||||||
return Err(R1CSError::InvalidNumberOfInputs);
|
return Err(R1CSError::InvalidNumberOfInputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self.inst.is_sat(&vars.assignment, &inputs.assignment))
|
// we might need to pad variables
|
||||||
|
let padded_vars = {
|
||||||
|
let num_padded_vars = self.inst.get_num_vars();
|
||||||
|
let num_vars = vars.assignment.len();
|
||||||
|
let padded_vars = if num_padded_vars > num_vars {
|
||||||
|
vars.pad(num_padded_vars)
|
||||||
|
} else {
|
||||||
|
vars.clone()
|
||||||
|
};
|
||||||
|
padded_vars
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(
|
||||||
|
self
|
||||||
|
.inst
|
||||||
|
.is_sat(&padded_vars.assignment, &inputs.assignment),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new synthetic R1CS `Instance` and an associated satisfying assignment
|
/// Constructs a new synthetic R1CS `Instance` and an associated satisfying assignment
|
||||||
@@ -217,12 +284,21 @@ pub struct SNARKGens {
|
|||||||
|
|
||||||
impl SNARKGens {
|
impl SNARKGens {
|
||||||
/// Constructs a new `SNARKGens` given the size of the R1CS statement
|
/// Constructs a new `SNARKGens` given the size of the R1CS statement
|
||||||
|
/// `num_nz_entries` specifies the maximum number of non-zero entries in any of the three R1CS matrices
|
||||||
pub fn new(num_cons: usize, num_vars: usize, num_inputs: usize, num_nz_entries: usize) -> Self {
|
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 num_vars_padded = {
|
||||||
|
let mut num_vars_padded = max(num_vars, num_inputs + 1);
|
||||||
|
if num_vars_padded != num_vars_padded.next_power_of_two() {
|
||||||
|
num_vars_padded = num_vars_padded.next_power_of_two();
|
||||||
|
}
|
||||||
|
num_vars_padded
|
||||||
|
};
|
||||||
|
|
||||||
|
let gens_r1cs_sat = R1CSGens::new(b"gens_r1cs_sat", num_cons, num_vars_padded);
|
||||||
let gens_r1cs_eval = R1CSCommitmentGens::new(
|
let gens_r1cs_eval = R1CSCommitmentGens::new(
|
||||||
b"gens_r1cs_eval",
|
b"gens_r1cs_eval",
|
||||||
num_cons,
|
num_cons,
|
||||||
num_vars,
|
num_vars_padded,
|
||||||
num_inputs,
|
num_inputs,
|
||||||
num_nz_entries,
|
num_nz_entries,
|
||||||
);
|
);
|
||||||
@@ -276,14 +352,29 @@ impl SNARK {
|
|||||||
let mut random_tape = RandomTape::new(b"proof");
|
let mut random_tape = RandomTape::new(b"proof");
|
||||||
transcript.append_protocol_name(SNARK::protocol_name());
|
transcript.append_protocol_name(SNARK::protocol_name());
|
||||||
let (r1cs_sat_proof, rx, ry) = {
|
let (r1cs_sat_proof, rx, ry) = {
|
||||||
let (proof, rx, ry) = R1CSProof::prove(
|
let (proof, rx, ry) = {
|
||||||
&inst.inst,
|
// we might need to pad variables
|
||||||
vars.assignment,
|
let padded_vars = {
|
||||||
&inputs.assignment,
|
let num_padded_vars = inst.inst.get_num_vars();
|
||||||
&gens.gens_r1cs_sat,
|
let num_vars = vars.assignment.len();
|
||||||
transcript,
|
let padded_vars = if num_padded_vars > num_vars {
|
||||||
&mut random_tape,
|
vars.pad(num_padded_vars)
|
||||||
);
|
} else {
|
||||||
|
vars
|
||||||
|
};
|
||||||
|
padded_vars
|
||||||
|
};
|
||||||
|
|
||||||
|
R1CSProof::prove(
|
||||||
|
&inst.inst,
|
||||||
|
padded_vars.assignment,
|
||||||
|
&inputs.assignment,
|
||||||
|
&gens.gens_r1cs_sat,
|
||||||
|
transcript,
|
||||||
|
&mut random_tape,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap();
|
let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap();
|
||||||
Timer::print(&format!("len_r1cs_sat_proof {:?}", proof_encoded.len()));
|
Timer::print(&format!("len_r1cs_sat_proof {:?}", proof_encoded.len()));
|
||||||
|
|
||||||
@@ -378,8 +469,16 @@ pub struct NIZKGens {
|
|||||||
|
|
||||||
impl NIZKGens {
|
impl NIZKGens {
|
||||||
/// Constructs a new `NIZKGens` given the size of the R1CS statement
|
/// Constructs a new `NIZKGens` given the size of the R1CS statement
|
||||||
pub fn new(num_cons: usize, num_vars: usize) -> Self {
|
pub fn new(num_cons: usize, num_vars: usize, num_inputs: usize) -> Self {
|
||||||
let gens_r1cs_sat = R1CSGens::new(b"gens_r1cs_sat", num_cons, num_vars);
|
let num_vars_padded = {
|
||||||
|
let mut num_vars_padded = max(num_vars, num_inputs + 1);
|
||||||
|
if num_vars_padded != num_vars_padded.next_power_of_two() {
|
||||||
|
num_vars_padded = num_vars_padded.next_power_of_two();
|
||||||
|
}
|
||||||
|
num_vars_padded
|
||||||
|
};
|
||||||
|
|
||||||
|
let gens_r1cs_sat = R1CSGens::new(b"gens_r1cs_sat", num_cons, num_vars_padded);
|
||||||
NIZKGens { gens_r1cs_sat }
|
NIZKGens { gens_r1cs_sat }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -410,9 +509,21 @@ impl NIZK {
|
|||||||
let mut random_tape = RandomTape::new(b"proof");
|
let mut random_tape = RandomTape::new(b"proof");
|
||||||
transcript.append_protocol_name(NIZK::protocol_name());
|
transcript.append_protocol_name(NIZK::protocol_name());
|
||||||
let (r1cs_sat_proof, rx, ry) = {
|
let (r1cs_sat_proof, rx, ry) = {
|
||||||
|
// we might need to pad variables
|
||||||
|
let padded_vars = {
|
||||||
|
let num_padded_vars = inst.inst.get_num_vars();
|
||||||
|
let num_vars = vars.assignment.len();
|
||||||
|
let padded_vars = if num_padded_vars > num_vars {
|
||||||
|
vars.pad(num_padded_vars)
|
||||||
|
} else {
|
||||||
|
vars
|
||||||
|
};
|
||||||
|
padded_vars
|
||||||
|
};
|
||||||
|
|
||||||
let (proof, rx, ry) = R1CSProof::prove(
|
let (proof, rx, ry) = R1CSProof::prove(
|
||||||
&inst.inst,
|
&inst.inst,
|
||||||
vars.assignment,
|
padded_vars.assignment,
|
||||||
&input.assignment,
|
&input.assignment,
|
||||||
&gens.gens_r1cs_sat,
|
&gens.gens_r1cs_sat,
|
||||||
transcript,
|
transcript,
|
||||||
@@ -544,4 +655,85 @@ mod tests {
|
|||||||
assert_eq!(inst.is_err(), true);
|
assert_eq!(inst.is_err(), true);
|
||||||
assert_eq!(inst.err(), Some(R1CSError::InvalidScalar));
|
assert_eq!(inst.err(), Some(R1CSError::InvalidScalar));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_padded_constraints() {
|
||||||
|
// parameters of the R1CS instance
|
||||||
|
let num_cons = 1;
|
||||||
|
let num_vars = 0;
|
||||||
|
let num_inputs = 3;
|
||||||
|
let num_non_zero_entries = 3;
|
||||||
|
|
||||||
|
// We will encode the above constraints into three matrices, where
|
||||||
|
// the coefficients in the matrix are in the little-endian byte order
|
||||||
|
let mut A: Vec<(usize, usize, [u8; 32])> = Vec::new();
|
||||||
|
let mut B: Vec<(usize, usize, [u8; 32])> = Vec::new();
|
||||||
|
let mut C: Vec<(usize, usize, [u8; 32])> = Vec::new();
|
||||||
|
|
||||||
|
// Create a^2 + b + 13
|
||||||
|
A.push((0, num_vars + 2, Scalar::one().to_bytes())); // 1*a
|
||||||
|
B.push((0, num_vars + 2, Scalar::one().to_bytes())); // 1*a
|
||||||
|
C.push((0, num_vars + 1, Scalar::one().to_bytes())); // 1*z
|
||||||
|
C.push((0, num_vars, (-Scalar::from(13u64)).to_bytes())); // -13*1
|
||||||
|
C.push((0, num_vars + 3, (-Scalar::one()).to_bytes())); // -1*b
|
||||||
|
|
||||||
|
// Var Assignments (Z_0 = 16 is the only output)
|
||||||
|
let vars = vec![Scalar::zero().to_bytes(); num_vars];
|
||||||
|
|
||||||
|
// create an InputsAssignment (a = 1, b = 2)
|
||||||
|
let mut inputs = vec![Scalar::zero().to_bytes(); num_inputs];
|
||||||
|
inputs[0] = Scalar::from(16u64).to_bytes();
|
||||||
|
inputs[1] = Scalar::from(1u64).to_bytes();
|
||||||
|
inputs[2] = Scalar::from(2u64).to_bytes();
|
||||||
|
|
||||||
|
let assignment_inputs = InputsAssignment::new(&inputs).unwrap();
|
||||||
|
let assignment_vars = VarsAssignment::new(&vars).unwrap();
|
||||||
|
|
||||||
|
// Check if instance is satisfiable
|
||||||
|
let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C).unwrap();
|
||||||
|
let res = inst.is_sat(&assignment_vars, &assignment_inputs);
|
||||||
|
assert_eq!(res.unwrap(), true, "should be satisfied");
|
||||||
|
|
||||||
|
// SNARK public params
|
||||||
|
let gens = SNARKGens::new(num_cons, num_vars, num_inputs, num_non_zero_entries);
|
||||||
|
|
||||||
|
// create a commitment to the R1CS instance
|
||||||
|
let (comm, decomm) = SNARK::encode(&inst, &gens);
|
||||||
|
|
||||||
|
// produce a SNARK
|
||||||
|
let mut prover_transcript = Transcript::new(b"snark_example");
|
||||||
|
let proof = SNARK::prove(
|
||||||
|
&inst,
|
||||||
|
&decomm,
|
||||||
|
assignment_vars.clone(),
|
||||||
|
&assignment_inputs,
|
||||||
|
&gens,
|
||||||
|
&mut prover_transcript,
|
||||||
|
);
|
||||||
|
|
||||||
|
// verify the SNARK
|
||||||
|
let mut verifier_transcript = Transcript::new(b"snark_example");
|
||||||
|
assert!(proof
|
||||||
|
.verify(&comm, &assignment_inputs, &mut verifier_transcript, &gens)
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
|
// NIZK public params
|
||||||
|
let gens = NIZKGens::new(num_cons, num_vars, num_inputs);
|
||||||
|
|
||||||
|
// produce a NIZK
|
||||||
|
let mut prover_transcript = Transcript::new(b"nizk_example");
|
||||||
|
let proof = NIZK::prove(
|
||||||
|
&inst,
|
||||||
|
assignment_vars,
|
||||||
|
&assignment_inputs,
|
||||||
|
&gens,
|
||||||
|
&mut prover_transcript,
|
||||||
|
);
|
||||||
|
|
||||||
|
// verify the NIZK
|
||||||
|
let mut verifier_transcript = Transcript::new(b"nizk_example");
|
||||||
|
assert!(proof
|
||||||
|
.verify(&inst, &assignment_inputs, &mut verifier_transcript, &gens)
|
||||||
|
.is_ok());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user