-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add ScalarField def and vector commitment feature. * Create Nova Folding Scheme lib * Create Fiat-Shamir Transcript and Matrix operator functions * Add Folding Scheme implementation. * Add satisfaction condition for R1CS * Separate the NIFS verification process into 2 different functions * Write a simple version of AugmentedCircuit * Reformat NIFS code & Add ZkIVCProof to AugmentedCircuit function * Implement the 'prove' function for IVC. * Implement the 'verify' function for IVC. * Change the parameters of circuit. * Write a simple testcase for IVC * Rewrite the simple test case into a step-by-step IVC test case * Write an iterable usage test case for IVC * Refine code and add more test cases. * refactor: Refine code and add comments * feat: Add examples for Nova lib & Refine code. * refactor: Refine code
- Loading branch information
Showing
17 changed files
with
2,277 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
[workspace] | ||
members = ["plonk", "kzg", "fri"] | ||
members = ["plonk", "kzg", "fri", "nova"] | ||
resolver = "2" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
[package] | ||
name = "nova" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
|
||
[[example]] | ||
name = "nova-example" | ||
path = "examples/examples.rs" | ||
|
||
[dependencies] | ||
ark-ff = "0.4.2" | ||
ark-ec = "0.4.2" | ||
ark-bls12-381 = "0.4.0" | ||
ark-serialize = "0.4.2" | ||
ark-std = "0.4.0" | ||
rand = "0.8.5" | ||
sha2 = "0.10" | ||
kzg = { path = "../kzg" } | ||
plonk = {path = "../plonk"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
use ark_ff::{BigInteger, One, PrimeField, Zero}; | ||
use kzg::scheme::KzgScheme; | ||
use kzg::srs::Srs; | ||
use kzg::types::{BaseField, ScalarField}; | ||
use nova::circuit::{AugmentedCircuit, FCircuit, State}; | ||
use nova::ivc::{IVCProof, ZkIVCProof, IVC}; | ||
use nova::r1cs::{create_trivial_pair, FInstance, FWitness, R1CS}; | ||
use nova::transcript::Transcript; | ||
use nova::utils::{to_f_matrix, to_f_vec}; | ||
use sha2::Sha256; | ||
|
||
struct TestCircuit {} | ||
impl FCircuit for TestCircuit { | ||
fn run(&self, z_i: &State, w_i: &FWitness) -> State { | ||
let x = w_i.w[0]; | ||
let res = x * x * x + x + ScalarField::from(5); | ||
let base_res = BaseField::from_le_bytes_mod_order(&res.into_bigint().to_bytes_le()); | ||
|
||
State { | ||
state: z_i.state + base_res, | ||
} | ||
} | ||
} | ||
fn main() { | ||
// (x0^3 + x0 + 5) + (x1^3 + x1 + 5) + (x2^3 + x2 + 5) + (x3^3 + x2 + 5) = 130 | ||
// x0 = 3, x1 = 4, x2 = 1, x3 = 2 | ||
|
||
// generate R1CS, witnesses and public input, output. | ||
let (r1cs, witnesses, x) = gen_test_values::<ScalarField>(vec![3, 4, 1, 2]); | ||
let (matrix_a, _, _) = ( | ||
r1cs.matrix_a.clone(), | ||
r1cs.matrix_b.clone(), | ||
r1cs.matrix_c.clone(), | ||
); | ||
|
||
// Trusted setup | ||
let domain_size = witnesses[0].len() + x[0].len() + 1; | ||
let srs = Srs::new(domain_size); | ||
let scheme = KzgScheme::new(srs); | ||
let x_len = x[0].len(); | ||
|
||
// Generate witnesses and instances | ||
let w: Vec<FWitness> = witnesses | ||
.iter() | ||
.map(|witness| FWitness::new(witness, matrix_a.len())) | ||
.collect(); | ||
let mut u: Vec<FInstance> = w | ||
.iter() | ||
.zip(x) | ||
.map(|(w, x)| w.commit(&scheme, &x)) | ||
.collect(); | ||
|
||
// step i | ||
let mut i = BaseField::zero(); | ||
|
||
// generate trivial instance-witness pair | ||
let (trivial_witness, trivial_instance) = | ||
create_trivial_pair(x_len, witnesses[0].len(), &scheme); | ||
|
||
// generate f_circuit instance | ||
let f_circuit = TestCircuit {}; | ||
|
||
// generate states | ||
let mut z = vec![ | ||
State { | ||
state: BaseField::from(0) | ||
}; | ||
5 | ||
]; | ||
for index in 1..5 { | ||
z[index] = f_circuit.run(&z[index - 1], &w[index - 1]); | ||
} | ||
|
||
let mut prover_transcript; | ||
let mut verifier_transcript = Transcript::<Sha256>::default(); | ||
|
||
// create F' | ||
let augmented_circuit = | ||
AugmentedCircuit::<Sha256, TestCircuit>::new(f_circuit, &trivial_instance, &z[0]); | ||
|
||
// generate IVC | ||
let mut ivc = IVC::<Sha256, TestCircuit> { | ||
scheme, | ||
augmented_circuit, | ||
}; | ||
|
||
// initialize IVC proof, zkIVCProof, folded witness and folded instance | ||
let mut ivc_proof = IVCProof::trivial_ivc_proof(&trivial_instance, &trivial_witness); | ||
let mut zk_ivc_proof = ZkIVCProof::trivial_zk_ivc_proof(&trivial_instance); | ||
let mut folded_witness = trivial_witness.clone(); | ||
let mut folded_instance = trivial_instance.clone(); | ||
|
||
let mut res; | ||
for step in 0..4 { | ||
println!("Step: {:?}", step); | ||
if step == 0 { | ||
res = ivc.augmented_circuit.run(&u[step], None, &w[step], None); | ||
} else { | ||
res = ivc.augmented_circuit.run( | ||
&ivc_proof.u_i, | ||
Some(&ivc_proof.big_u_i.clone()), | ||
&ivc_proof.w_i, | ||
Some(&zk_ivc_proof.com_t.clone().unwrap()), | ||
); | ||
} | ||
|
||
if res.is_err() { | ||
println!("{:?}", res); | ||
} | ||
assert!(res.is_ok()); | ||
|
||
// verifier verify this step | ||
let verify = ivc.verify(&zk_ivc_proof, &mut verifier_transcript); | ||
if verify.is_err() { | ||
println!("{:?}", verify); | ||
} | ||
assert!(verify.is_ok()); | ||
|
||
// update for next step | ||
|
||
if step != 3 { | ||
// do not update if we have done with IVC | ||
ivc.augmented_circuit.next_step(); | ||
i += BaseField::one(); | ||
assert_eq!(ivc.augmented_circuit.z_i.state, z[step + 1].state); | ||
prover_transcript = Transcript::<Sha256>::default(); | ||
verifier_transcript = Transcript::<Sha256>::default(); | ||
|
||
let hash_x = AugmentedCircuit::<Sha256, TestCircuit>::hash_io( | ||
i, | ||
&z[0], | ||
&z[step + 1], | ||
&folded_instance, | ||
); | ||
// convert u_1_x from BaseField into ScalarField | ||
u[step + 1].x = vec![ScalarField::from_le_bytes_mod_order( | ||
&hash_x.into_bigint().to_bytes_le(), | ||
)]; | ||
|
||
// generate ivc_proof and zkSNARK proof. | ||
ivc_proof = IVCProof::new( | ||
&u[step + 1], | ||
&w[step + 1], | ||
&folded_instance, | ||
&folded_witness, | ||
); | ||
(folded_witness, folded_instance, zk_ivc_proof) = | ||
ivc.prove(&r1cs, &ivc_proof, &mut prover_transcript); | ||
} | ||
} | ||
} | ||
|
||
fn gen_test_values<F: PrimeField>(inputs: Vec<usize>) -> (R1CS<F>, Vec<Vec<F>>, Vec<Vec<F>>) { | ||
// R1CS for: x^3 + x + 5 = y (example from article | ||
// https://vitalik.eth.limo/general/2016/12/10/qap.html ) | ||
|
||
let a = to_f_matrix::<F>(&[ | ||
vec![1, 0, 0, 0, 0, 0], | ||
vec![0, 1, 0, 0, 0, 0], | ||
vec![1, 0, 1, 0, 0, 0], | ||
vec![0, 0, 0, 1, 0, 5], | ||
]); | ||
let b = to_f_matrix::<F>(&[ | ||
vec![1, 0, 0, 0, 0, 0], | ||
vec![1, 0, 0, 0, 0, 0], | ||
vec![0, 0, 0, 0, 0, 1], | ||
vec![0, 0, 0, 0, 0, 1], | ||
]); | ||
let c = to_f_matrix::<F>(&[ | ||
vec![0, 1, 0, 0, 0, 0], | ||
vec![0, 0, 1, 0, 0, 0], | ||
vec![0, 0, 0, 1, 0, 0], | ||
vec![0, 0, 0, 0, 1, 0], | ||
]); | ||
|
||
// generate n witnesses | ||
let mut w: Vec<Vec<F>> = Vec::new(); | ||
let mut x: Vec<Vec<F>> = Vec::new(); | ||
for input in inputs { | ||
let w_i = to_f_vec::<F>(vec![ | ||
input, | ||
input * input, // x^2 | ||
input * input * input, // x^2 * x | ||
input * input * input + input, // x^3 + x | ||
]); | ||
w.push(w_i.clone()); | ||
let x_i = to_f_vec::<F>(vec![input * input * input + input + 5]); // output: x^3 + x + 5 | ||
x.push(x_i.clone()); | ||
} | ||
|
||
let r1cs = R1CS::<F> { | ||
matrix_a: a, | ||
matrix_b: b, | ||
matrix_c: c, | ||
num_io: 1, | ||
num_vars: 4, | ||
}; | ||
(r1cs, w, x) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
This is a simple implementation of [NOVA](https://eprint.iacr.org/2021/370.pdf). | ||
|
Oops, something went wrong.