-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fit Nova+CycleFold into
FoldingScheme
trait & Add examples/
for f…
…olding SHA256 circuit (#64) * Update FoldingSchemes trait, fit Nova+CycleFold - update lib.rs's `FoldingScheme` trait interface - fit Nova+CycleFold into the `FoldingScheme` trait - refactor `src/nova/*` * Add `examples` dir, with Nova's `FoldingScheme` example * polishing * expose poseidon_test_config outside tests
- Loading branch information
Showing
18 changed files
with
916 additions
and
574 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 |
---|---|---|
@@ -0,0 +1,172 @@ | ||
#![allow(non_snake_case)] | ||
#![allow(non_upper_case_globals)] | ||
#![allow(non_camel_case_types)] | ||
#![allow(clippy::upper_case_acronyms)] | ||
|
||
use ark_crypto_primitives::crh::{ | ||
sha256::{ | ||
constraints::{Sha256Gadget, UnitVar}, | ||
Sha256, | ||
}, | ||
CRHScheme, CRHSchemeGadget, | ||
}; | ||
use ark_ff::{BigInteger, PrimeField, ToConstraintField}; | ||
use ark_r1cs_std::{fields::fp::FpVar, ToBytesGadget, ToConstraintFieldGadget}; | ||
use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; | ||
use core::marker::PhantomData; | ||
use std::time::Instant; | ||
|
||
use ark_pallas::{constraints::GVar, Fr, Projective}; | ||
use ark_vesta::{constraints::GVar as GVar2, Projective as Projective2}; | ||
|
||
use folding_schemes::commitment::pedersen::Pedersen; | ||
use folding_schemes::folding::nova::{get_r1cs, Nova, ProverParams, VerifierParams}; | ||
use folding_schemes::frontend::FCircuit; | ||
use folding_schemes::transcript::poseidon::poseidon_test_config; | ||
use folding_schemes::{Error, FoldingScheme}; | ||
|
||
/// This is the circuit that we want to fold, it implements the FCircuit trait. | ||
/// The parameter z_i denotes the current state, and z_{i+1} denotes the next state which we get by | ||
/// applying the step. | ||
/// In this example we set z_i and z_{i+1} to be a single value, but the trait is made to support | ||
/// arrays, so our state could be an array with different values. | ||
#[derive(Clone, Copy, Debug)] | ||
pub struct Sha256FCircuit<F: PrimeField> { | ||
_f: PhantomData<F>, | ||
} | ||
impl<F: PrimeField> FCircuit<F> for Sha256FCircuit<F> { | ||
type Params = (); | ||
|
||
fn new(_params: Self::Params) -> Self { | ||
Self { _f: PhantomData } | ||
} | ||
|
||
/// computes the next state values in place, assigning z_{i+1} into z_i, and computing the new | ||
/// z_{i+1} | ||
fn step_native(self, z_i: Vec<F>) -> Result<Vec<F>, Error> { | ||
let out_bytes = Sha256::evaluate(&(), z_i[0].into_bigint().to_bytes_le()).unwrap(); | ||
let out: Vec<F> = out_bytes.to_field_elements().unwrap(); | ||
|
||
Ok(vec![out[0]]) | ||
} | ||
|
||
/// generates the constraints for the step of F for the given z_i | ||
fn generate_step_constraints( | ||
self, | ||
_cs: ConstraintSystemRef<F>, | ||
z_i: Vec<FpVar<F>>, | ||
) -> Result<Vec<FpVar<F>>, SynthesisError> { | ||
let unit_var = UnitVar::default(); | ||
let out_bytes = Sha256Gadget::evaluate(&unit_var, &z_i[0].to_bytes()?)?; | ||
let out = out_bytes.0.to_constraint_field()?; | ||
Ok(vec![out[0].clone()]) | ||
} | ||
} | ||
|
||
/// cargo test --example simple | ||
#[cfg(test)] | ||
pub mod tests { | ||
use super::*; | ||
use ark_r1cs_std::alloc::AllocVar; | ||
use ark_relations::r1cs::ConstraintSystem; | ||
|
||
// test to check that the Sha256FCircuit computes the same values inside and outside the circuit | ||
#[test] | ||
fn test_sha256_f_circuit() { | ||
let cs = ConstraintSystem::<Fr>::new_ref(); | ||
|
||
let circuit = Sha256FCircuit::<Fr>::new(()); | ||
let z_i = vec![Fr::from(1_u32)]; | ||
|
||
let z_i1 = circuit.step_native(z_i.clone()).unwrap(); | ||
|
||
let z_iVar = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_i)).unwrap(); | ||
let computed_z_i1Var = circuit | ||
.generate_step_constraints(cs.clone(), z_iVar.clone()) | ||
.unwrap(); | ||
assert_eq!(computed_z_i1Var.value().unwrap(), z_i1); | ||
} | ||
} | ||
|
||
// This method computes the Prover & Verifier parameters for the example. For a real world use case | ||
// those parameters should be generated carefuly (both the PoseidonConfig and the PedersenParams) | ||
#[allow(clippy::type_complexity)] | ||
fn nova_setup<FC: FCircuit<Fr>>( | ||
F_circuit: FC, | ||
) -> ( | ||
ProverParams<Projective, Projective2, Pedersen<Projective>, Pedersen<Projective2>>, | ||
VerifierParams<Projective, Projective2>, | ||
) { | ||
let mut rng = ark_std::test_rng(); | ||
let poseidon_config = poseidon_test_config::<Fr>(); | ||
|
||
// get the CM & CF_CM len | ||
let (r1cs, cf_r1cs) = | ||
get_r1cs::<Projective, GVar, Projective2, GVar2, FC>(&poseidon_config, F_circuit).unwrap(); | ||
let cm_len = r1cs.A.n_rows; | ||
let cf_cm_len = cf_r1cs.A.n_rows; | ||
|
||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, cm_len); | ||
let cf_pedersen_params = Pedersen::<Projective2>::new_params(&mut rng, cf_cm_len); | ||
|
||
let prover_params = | ||
ProverParams::<Projective, Projective2, Pedersen<Projective>, Pedersen<Projective2>> { | ||
poseidon_config: poseidon_config.clone(), | ||
cm_params: pedersen_params, | ||
cf_cm_params: cf_pedersen_params, | ||
}; | ||
let verifier_params = VerifierParams::<Projective, Projective2> { | ||
poseidon_config: poseidon_config.clone(), | ||
r1cs, | ||
cf_r1cs, | ||
}; | ||
(prover_params, verifier_params) | ||
} | ||
|
||
/// cargo run --release --example fold_sha256 | ||
fn main() { | ||
let num_steps = 10; | ||
let initial_state = vec![Fr::from(1_u32)]; | ||
|
||
let F_circuit = Sha256FCircuit::<Fr>::new(()); | ||
|
||
println!("Prepare Nova ProverParams & VerifierParams"); | ||
let (prover_params, verifier_params) = nova_setup::<Sha256FCircuit<Fr>>(F_circuit); | ||
|
||
/// The idea here is that eventually we could replace the next line chunk that defines the | ||
/// `type NOVA = Nova<...>` by using another folding scheme that fulfills the `FoldingScheme` | ||
/// trait, and the rest of our code would be working without needing to be updated. | ||
type NOVA = Nova< | ||
Projective, | ||
GVar, | ||
Projective2, | ||
GVar2, | ||
Sha256FCircuit<Fr>, | ||
Pedersen<Projective>, | ||
Pedersen<Projective2>, | ||
>; | ||
|
||
println!("Initialize FoldingScheme"); | ||
let mut folding_scheme = NOVA::init(&prover_params, F_circuit, initial_state.clone()).unwrap(); | ||
|
||
// compute a step of the IVC | ||
for i in 0..num_steps { | ||
let start = Instant::now(); | ||
folding_scheme.prove_step().unwrap(); | ||
println!("Nova::prove_step {}: {:?}", i, start.elapsed()); | ||
} | ||
|
||
let (running_instance, incomming_instance, cyclefold_instance) = folding_scheme.instances(); | ||
|
||
println!("Run the Nova's IVC verifier"); | ||
NOVA::verify( | ||
verifier_params, | ||
initial_state, | ||
folding_scheme.state(), // latest state | ||
Fr::from(num_steps as u32), | ||
running_instance, | ||
incomming_instance, | ||
cyclefold_instance, | ||
) | ||
.unwrap(); | ||
} |
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
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 @@ | ||
// used for the RO challenges. | ||
// From [Srinath Setty](research.microsoft.com/en-us/people/srinath/): In Nova, soundness error ≤ | ||
// 2/|S|, where S is the subset of the field F from which the challenges are drawn. In this case, | ||
// we keep the size of S close to 2^128. | ||
// From [Srinath Setty](https://microsoft.com/en-us/research/people/srinath/): In Nova, soundness | ||
// error ≤ 2/|S|, where S is the subset of the field F from which the challenges are drawn. In this | ||
// case, we keep the size of S close to 2^128. | ||
pub const N_BITS_RO: usize = 128; |
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
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
Oops, something went wrong.