mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-08 15:01:30 +01:00
Implement HyperNova's IVC into the FoldingScheme trait (#116)
- implement the IVC `FoldingScheme` trait for HyperNova
- refactor Nova's preprocess logic to make it simplier to use
- add to Decider trait (& Nova's DeciderEth) a preprocess method
- get rid of the `init_nova_ivc_params` and `init_ivc_and_decider_params` methods in `examples` since this is achieved with the `FS::preprocess` & `Decider::preprocess` methods
- (update the examples code to the simplified interface using
FS::preprocess & Decider::preprocess)
This commit is contained in:
@@ -21,9 +21,10 @@ use folding_schemes::{
|
|||||||
commitment::{kzg::KZG, pedersen::Pedersen},
|
commitment::{kzg::KZG, pedersen::Pedersen},
|
||||||
folding::nova::{
|
folding::nova::{
|
||||||
decider_eth::{prepare_calldata, Decider as DeciderEth},
|
decider_eth::{prepare_calldata, Decider as DeciderEth},
|
||||||
Nova,
|
Nova, PreprocessorParam,
|
||||||
},
|
},
|
||||||
frontend::{circom::CircomFCircuit, FCircuit},
|
frontend::{circom::CircomFCircuit, FCircuit},
|
||||||
|
transcript::poseidon::poseidon_canonical_config,
|
||||||
Decider, FoldingScheme,
|
Decider, FoldingScheme,
|
||||||
};
|
};
|
||||||
use solidity_verifiers::{
|
use solidity_verifiers::{
|
||||||
@@ -33,9 +34,6 @@ use solidity_verifiers::{
|
|||||||
NovaCycleFoldVerifierKey,
|
NovaCycleFoldVerifierKey,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod utils;
|
|
||||||
use utils::init_ivc_and_decider_params;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// set the initial state
|
// set the initial state
|
||||||
let z_0 = vec![Fr::from(3_u32)];
|
let z_0 = vec![Fr::from(3_u32)];
|
||||||
@@ -66,12 +64,8 @@ fn main() {
|
|||||||
let f_circuit_params = (r1cs_path, wasm_path, 1, 2);
|
let f_circuit_params = (r1cs_path, wasm_path, 1, 2);
|
||||||
let f_circuit = CircomFCircuit::<Fr>::new(f_circuit_params).unwrap();
|
let f_circuit = CircomFCircuit::<Fr>::new(f_circuit_params).unwrap();
|
||||||
|
|
||||||
let (fs_prover_params, kzg_vk, g16_pk, g16_vk) =
|
pub type N = Nova<G1, GVar, G2, GVar2, CircomFCircuit<Fr>, KZG<'static, Bn254>, Pedersen<G2>>;
|
||||||
init_ivc_and_decider_params::<CircomFCircuit<Fr>>(f_circuit.clone());
|
pub type D = DeciderEth<
|
||||||
|
|
||||||
pub type NOVA =
|
|
||||||
Nova<G1, GVar, G2, GVar2, CircomFCircuit<Fr>, KZG<'static, Bn254>, Pedersen<G2>>;
|
|
||||||
pub type DECIDERETH_FCircuit = DeciderEth<
|
|
||||||
G1,
|
G1,
|
||||||
GVar,
|
GVar,
|
||||||
G2,
|
G2,
|
||||||
@@ -80,30 +74,36 @@ fn main() {
|
|||||||
KZG<'static, Bn254>,
|
KZG<'static, Bn254>,
|
||||||
Pedersen<G2>,
|
Pedersen<G2>,
|
||||||
Groth16<Bn254>,
|
Groth16<Bn254>,
|
||||||
NOVA,
|
N,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
let poseidon_config = poseidon_canonical_config::<Fr>();
|
||||||
|
let mut rng = rand::rngs::OsRng;
|
||||||
|
|
||||||
|
// prepare the Nova prover & verifier params
|
||||||
|
let nova_preprocess_params = PreprocessorParam::new(poseidon_config, f_circuit.clone());
|
||||||
|
let (fs_pp, fs_vp) = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
|
||||||
|
|
||||||
// initialize the folding scheme engine, in our case we use Nova
|
// initialize the folding scheme engine, in our case we use Nova
|
||||||
let mut nova = NOVA::init(&fs_prover_params, f_circuit.clone(), z_0).unwrap();
|
let mut nova = N::init(&fs_pp, f_circuit.clone(), z_0).unwrap();
|
||||||
|
|
||||||
|
// prepare the Decider prover & verifier params
|
||||||
|
let (decider_pp, decider_vp) = D::preprocess(&mut rng, &(fs_pp, fs_vp), nova.clone()).unwrap();
|
||||||
|
|
||||||
// run n steps of the folding iteration
|
// run n steps of the folding iteration
|
||||||
for (i, external_inputs_at_step) in external_inputs.iter().enumerate() {
|
for (i, external_inputs_at_step) in external_inputs.iter().enumerate() {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
nova.prove_step(external_inputs_at_step.clone()).unwrap();
|
nova.prove_step(rng, external_inputs_at_step.clone())
|
||||||
|
.unwrap();
|
||||||
println!("Nova::prove_step {}: {:?}", i, start.elapsed());
|
println!("Nova::prove_step {}: {:?}", i, start.elapsed());
|
||||||
}
|
}
|
||||||
|
|
||||||
let rng = rand::rngs::OsRng;
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let proof = DECIDERETH_FCircuit::prove(
|
let proof = D::prove(rng, decider_pp, nova.clone()).unwrap();
|
||||||
(g16_pk, fs_prover_params.cs_params.clone()),
|
|
||||||
rng,
|
|
||||||
nova.clone(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
println!("generated Decider proof: {:?}", start.elapsed());
|
println!("generated Decider proof: {:?}", start.elapsed());
|
||||||
|
|
||||||
let verified = DECIDERETH_FCircuit::verify(
|
let verified = D::verify(
|
||||||
(g16_vk.clone(), kzg_vk.clone()),
|
decider_vp.clone(),
|
||||||
nova.i,
|
nova.i,
|
||||||
nova.z_0.clone(),
|
nova.z_0.clone(),
|
||||||
nova.z_i.clone(),
|
nova.z_i.clone(),
|
||||||
@@ -131,7 +131,7 @@ fn main() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// prepare the setup params for the solidity verifier
|
// prepare the setup params for the solidity verifier
|
||||||
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from((g16_vk, kzg_vk, f_circuit.state_len()));
|
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from((decider_vp, f_circuit.state_len()));
|
||||||
|
|
||||||
// generate the solidity code
|
// generate the solidity code
|
||||||
let decider_solidity_code = get_decider_template_for_cyclefold_decider(nova_cyclefold_vk);
|
let decider_solidity_code = get_decider_template_for_cyclefold_decider(nova_cyclefold_vk);
|
||||||
|
|||||||
@@ -21,12 +21,10 @@ use core::marker::PhantomData;
|
|||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use folding_schemes::commitment::{kzg::KZG, pedersen::Pedersen};
|
use folding_schemes::commitment::{kzg::KZG, pedersen::Pedersen};
|
||||||
use folding_schemes::folding::nova::Nova;
|
use folding_schemes::folding::nova::{Nova, PreprocessorParam};
|
||||||
use folding_schemes::frontend::FCircuit;
|
use folding_schemes::frontend::FCircuit;
|
||||||
use folding_schemes::{Error, FoldingScheme};
|
|
||||||
mod utils;
|
|
||||||
use folding_schemes::transcript::poseidon::poseidon_canonical_config;
|
use folding_schemes::transcript::poseidon::poseidon_canonical_config;
|
||||||
use utils::init_nova_ivc_params;
|
use folding_schemes::{Error, FoldingScheme};
|
||||||
|
|
||||||
/// This is the circuit that we want to fold, it implements the FCircuit trait. The parameter z_i
|
/// This is the circuit that we want to fold, it implements the FCircuit trait. The parameter z_i
|
||||||
/// denotes the current state which contains 1 element, and z_{i+1} denotes the next state which we
|
/// denotes the current state which contains 1 element, and z_{i+1} denotes the next state which we
|
||||||
@@ -65,14 +63,14 @@ use utils::init_nova_ivc_params;
|
|||||||
/// The last state z_i is used together with the external input w_i as inputs to compute the new
|
/// The last state z_i is used together with the external input w_i as inputs to compute the new
|
||||||
/// state z_{i+1}.
|
/// state z_{i+1}.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ExternalInputsCircuits<F: PrimeField>
|
pub struct ExternalInputsCircuit<F: PrimeField>
|
||||||
where
|
where
|
||||||
F: Absorb,
|
F: Absorb,
|
||||||
{
|
{
|
||||||
_f: PhantomData<F>,
|
_f: PhantomData<F>,
|
||||||
poseidon_config: PoseidonConfig<F>,
|
poseidon_config: PoseidonConfig<F>,
|
||||||
}
|
}
|
||||||
impl<F: PrimeField> FCircuit<F> for ExternalInputsCircuits<F>
|
impl<F: PrimeField> FCircuit<F> for ExternalInputsCircuit<F>
|
||||||
where
|
where
|
||||||
F: Absorb,
|
F: Absorb,
|
||||||
{
|
{
|
||||||
@@ -128,14 +126,14 @@ pub mod tests {
|
|||||||
use ark_r1cs_std::R1CSVar;
|
use ark_r1cs_std::R1CSVar;
|
||||||
use ark_relations::r1cs::ConstraintSystem;
|
use ark_relations::r1cs::ConstraintSystem;
|
||||||
|
|
||||||
// test to check that the ExternalInputsCircuits computes the same values inside and outside the circuit
|
// test to check that the ExternalInputsCircuit computes the same values inside and outside the circuit
|
||||||
#[test]
|
#[test]
|
||||||
fn test_f_circuit() {
|
fn test_f_circuit() {
|
||||||
let poseidon_config = poseidon_canonical_config::<Fr>();
|
let poseidon_config = poseidon_canonical_config::<Fr>();
|
||||||
|
|
||||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||||
|
|
||||||
let circuit = ExternalInputsCircuits::<Fr>::new(poseidon_config).unwrap();
|
let circuit = ExternalInputsCircuit::<Fr>::new(poseidon_config).unwrap();
|
||||||
let z_i = vec![Fr::from(1_u32)];
|
let z_i = vec![Fr::from(1_u32)];
|
||||||
let external_inputs = vec![Fr::from(3_u32)];
|
let external_inputs = vec![Fr::from(3_u32)];
|
||||||
|
|
||||||
@@ -170,33 +168,35 @@ fn main() {
|
|||||||
assert_eq!(external_inputs.len(), num_steps);
|
assert_eq!(external_inputs.len(), num_steps);
|
||||||
|
|
||||||
let poseidon_config = poseidon_canonical_config::<Fr>();
|
let poseidon_config = poseidon_canonical_config::<Fr>();
|
||||||
let F_circuit = ExternalInputsCircuits::<Fr>::new(poseidon_config).unwrap();
|
let F_circuit = ExternalInputsCircuit::<Fr>::new(poseidon_config.clone()).unwrap();
|
||||||
|
|
||||||
println!("Prepare Nova ProverParams & VerifierParams");
|
|
||||||
let (prover_params, verifier_params, _) =
|
|
||||||
init_nova_ivc_params::<ExternalInputsCircuits<Fr>>(F_circuit.clone());
|
|
||||||
|
|
||||||
/// The idea here is that eventually we could replace the next line chunk that defines the
|
/// 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`
|
/// `type N = 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.
|
/// trait, and the rest of our code would be working without needing to be updated.
|
||||||
type NOVA = Nova<
|
type N = Nova<
|
||||||
Projective,
|
Projective,
|
||||||
GVar,
|
GVar,
|
||||||
Projective2,
|
Projective2,
|
||||||
GVar2,
|
GVar2,
|
||||||
ExternalInputsCircuits<Fr>,
|
ExternalInputsCircuit<Fr>,
|
||||||
KZG<'static, Bn254>,
|
KZG<'static, Bn254>,
|
||||||
Pedersen<Projective2>,
|
Pedersen<Projective2>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
let mut rng = rand::rngs::OsRng;
|
||||||
|
|
||||||
|
println!("Prepare Nova's ProverParams & VerifierParams");
|
||||||
|
let nova_preprocess_params = PreprocessorParam::new(poseidon_config, F_circuit.clone());
|
||||||
|
let (nova_pp, nova_vp) = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
|
||||||
|
|
||||||
println!("Initialize FoldingScheme");
|
println!("Initialize FoldingScheme");
|
||||||
let mut folding_scheme = NOVA::init(&prover_params, F_circuit, initial_state.clone()).unwrap();
|
let mut folding_scheme = N::init(&nova_pp, F_circuit, initial_state.clone()).unwrap();
|
||||||
|
|
||||||
// compute a step of the IVC
|
// compute a step of the IVC
|
||||||
for (i, external_inputs_at_step) in external_inputs.iter().enumerate() {
|
for (i, external_inputs_at_step) in external_inputs.iter().enumerate() {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
folding_scheme
|
folding_scheme
|
||||||
.prove_step(external_inputs_at_step.clone())
|
.prove_step(rng, external_inputs_at_step.clone())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("Nova::prove_step {}: {:?}", i, start.elapsed());
|
println!("Nova::prove_step {}: {:?}", i, start.elapsed());
|
||||||
}
|
}
|
||||||
@@ -209,8 +209,8 @@ fn main() {
|
|||||||
let (running_instance, incoming_instance, cyclefold_instance) = folding_scheme.instances();
|
let (running_instance, incoming_instance, cyclefold_instance) = folding_scheme.instances();
|
||||||
|
|
||||||
println!("Run the Nova's IVC verifier");
|
println!("Run the Nova's IVC verifier");
|
||||||
NOVA::verify(
|
N::verify(
|
||||||
verifier_params,
|
nova_vp,
|
||||||
initial_state.clone(),
|
initial_state.clone(),
|
||||||
folding_scheme.state(), // latest state
|
folding_scheme.state(), // latest state
|
||||||
Fr::from(num_steps as u32),
|
Fr::from(num_steps as u32),
|
||||||
|
|||||||
@@ -19,16 +19,14 @@ use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
mod utils;
|
|
||||||
use utils::init_ivc_and_decider_params;
|
|
||||||
|
|
||||||
use folding_schemes::{
|
use folding_schemes::{
|
||||||
commitment::{kzg::KZG, pedersen::Pedersen},
|
commitment::{kzg::KZG, pedersen::Pedersen},
|
||||||
folding::nova::{
|
folding::nova::{
|
||||||
decider_eth::{prepare_calldata, Decider as DeciderEth},
|
decider_eth::{prepare_calldata, Decider as DeciderEth},
|
||||||
Nova,
|
Nova, PreprocessorParam,
|
||||||
},
|
},
|
||||||
frontend::FCircuit,
|
frontend::FCircuit,
|
||||||
|
transcript::poseidon::poseidon_canonical_config,
|
||||||
Decider, Error, FoldingScheme,
|
Decider, Error, FoldingScheme,
|
||||||
};
|
};
|
||||||
use solidity_verifiers::{
|
use solidity_verifiers::{
|
||||||
@@ -82,11 +80,9 @@ fn main() {
|
|||||||
let z_0 = vec![Fr::from(3_u32)];
|
let z_0 = vec![Fr::from(3_u32)];
|
||||||
|
|
||||||
let f_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
|
let f_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
|
||||||
let (fs_prover_params, kzg_vk, g16_pk, g16_vk) =
|
|
||||||
init_ivc_and_decider_params::<CubicFCircuit<Fr>>(f_circuit);
|
|
||||||
|
|
||||||
pub type NOVA = Nova<G1, GVar, G2, GVar2, CubicFCircuit<Fr>, KZG<'static, Bn254>, Pedersen<G2>>;
|
pub type N = Nova<G1, GVar, G2, GVar2, CubicFCircuit<Fr>, KZG<'static, Bn254>, Pedersen<G2>>;
|
||||||
pub type DECIDERETH_FCircuit = DeciderEth<
|
pub type D = DeciderEth<
|
||||||
G1,
|
G1,
|
||||||
GVar,
|
GVar,
|
||||||
G2,
|
G2,
|
||||||
@@ -95,30 +91,35 @@ fn main() {
|
|||||||
KZG<'static, Bn254>,
|
KZG<'static, Bn254>,
|
||||||
Pedersen<G2>,
|
Pedersen<G2>,
|
||||||
Groth16<Bn254>,
|
Groth16<Bn254>,
|
||||||
NOVA,
|
N,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
let poseidon_config = poseidon_canonical_config::<Fr>();
|
||||||
|
let mut rng = rand::rngs::OsRng;
|
||||||
|
|
||||||
|
// prepare the Nova prover & verifier params
|
||||||
|
let nova_preprocess_params = PreprocessorParam::new(poseidon_config.clone(), f_circuit);
|
||||||
|
let (fs_pp, fs_vp) = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
|
||||||
|
|
||||||
// initialize the folding scheme engine, in our case we use Nova
|
// initialize the folding scheme engine, in our case we use Nova
|
||||||
let mut nova = NOVA::init(&fs_prover_params, f_circuit, z_0).unwrap();
|
let mut nova = N::init(&fs_pp, f_circuit, z_0).unwrap();
|
||||||
|
|
||||||
|
// prepare the Decider prover & verifier params
|
||||||
|
let (decider_pp, decider_vp) = D::preprocess(&mut rng, &(fs_pp, fs_vp), nova.clone()).unwrap();
|
||||||
|
|
||||||
// run n steps of the folding iteration
|
// run n steps of the folding iteration
|
||||||
for i in 0..n_steps {
|
for i in 0..n_steps {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
nova.prove_step(vec![]).unwrap();
|
nova.prove_step(rng, vec![]).unwrap();
|
||||||
println!("Nova::prove_step {}: {:?}", i, start.elapsed());
|
println!("Nova::prove_step {}: {:?}", i, start.elapsed());
|
||||||
}
|
}
|
||||||
|
|
||||||
let rng = rand::rngs::OsRng;
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let proof = DECIDERETH_FCircuit::prove(
|
let proof = D::prove(rng, decider_pp, nova.clone()).unwrap();
|
||||||
(g16_pk, fs_prover_params.cs_params.clone()),
|
|
||||||
rng,
|
|
||||||
nova.clone(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
println!("generated Decider proof: {:?}", start.elapsed());
|
println!("generated Decider proof: {:?}", start.elapsed());
|
||||||
|
|
||||||
let verified = DECIDERETH_FCircuit::verify(
|
let verified = D::verify(
|
||||||
(g16_vk.clone(), kzg_vk.clone()),
|
decider_vp.clone(),
|
||||||
nova.i,
|
nova.i,
|
||||||
nova.z_0.clone(),
|
nova.z_0.clone(),
|
||||||
nova.z_i.clone(),
|
nova.z_i.clone(),
|
||||||
@@ -146,7 +147,7 @@ fn main() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// prepare the setup params for the solidity verifier
|
// prepare the setup params for the solidity verifier
|
||||||
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from((g16_vk, kzg_vk, f_circuit.state_len()));
|
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from((decider_vp, f_circuit.state_len()));
|
||||||
|
|
||||||
// generate the solidity code
|
// generate the solidity code
|
||||||
let decider_solidity_code = get_decider_template_for_cyclefold_decider(nova_cyclefold_vk);
|
let decider_solidity_code = get_decider_template_for_cyclefold_decider(nova_cyclefold_vk);
|
||||||
|
|||||||
@@ -14,11 +14,10 @@ use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
|
|||||||
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
||||||
|
|
||||||
use folding_schemes::commitment::{kzg::KZG, pedersen::Pedersen};
|
use folding_schemes::commitment::{kzg::KZG, pedersen::Pedersen};
|
||||||
use folding_schemes::folding::nova::Nova;
|
use folding_schemes::folding::nova::{Nova, PreprocessorParam};
|
||||||
use folding_schemes::frontend::FCircuit;
|
use folding_schemes::frontend::FCircuit;
|
||||||
|
use folding_schemes::transcript::poseidon::poseidon_canonical_config;
|
||||||
use folding_schemes::{Error, FoldingScheme};
|
use folding_schemes::{Error, FoldingScheme};
|
||||||
mod utils;
|
|
||||||
use utils::init_nova_ivc_params;
|
|
||||||
|
|
||||||
/// This is the circuit that we want to fold, it implements the FCircuit trait. The parameter z_i
|
/// This is the circuit that we want to fold, it implements the FCircuit trait. The parameter z_i
|
||||||
/// denotes the current state which contains 5 elements, and z_{i+1} denotes the next state which
|
/// denotes the current state which contains 5 elements, and z_{i+1} denotes the next state which
|
||||||
@@ -124,14 +123,13 @@ fn main() {
|
|||||||
|
|
||||||
let F_circuit = MultiInputsFCircuit::<Fr>::new(()).unwrap();
|
let F_circuit = MultiInputsFCircuit::<Fr>::new(()).unwrap();
|
||||||
|
|
||||||
println!("Prepare Nova ProverParams & VerifierParams");
|
let poseidon_config = poseidon_canonical_config::<Fr>();
|
||||||
let (prover_params, verifier_params, _) =
|
let mut rng = rand::rngs::OsRng;
|
||||||
init_nova_ivc_params::<MultiInputsFCircuit<Fr>>(F_circuit);
|
|
||||||
|
|
||||||
/// The idea here is that eventually we could replace the next line chunk that defines the
|
/// 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`
|
/// `type N = 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.
|
/// trait, and the rest of our code would be working without needing to be updated.
|
||||||
type NOVA = Nova<
|
type N = Nova<
|
||||||
Projective,
|
Projective,
|
||||||
GVar,
|
GVar,
|
||||||
Projective2,
|
Projective2,
|
||||||
@@ -141,21 +139,25 @@ fn main() {
|
|||||||
Pedersen<Projective2>,
|
Pedersen<Projective2>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
println!("Prepare Nova ProverParams & VerifierParams");
|
||||||
|
let nova_preprocess_params = PreprocessorParam::new(poseidon_config, F_circuit);
|
||||||
|
let (nova_pp, nova_vp) = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
|
||||||
|
|
||||||
println!("Initialize FoldingScheme");
|
println!("Initialize FoldingScheme");
|
||||||
let mut folding_scheme = NOVA::init(&prover_params, F_circuit, initial_state.clone()).unwrap();
|
let mut folding_scheme = N::init(&nova_pp, F_circuit, initial_state.clone()).unwrap();
|
||||||
|
|
||||||
// compute a step of the IVC
|
// compute a step of the IVC
|
||||||
for i in 0..num_steps {
|
for i in 0..num_steps {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
folding_scheme.prove_step(vec![]).unwrap();
|
folding_scheme.prove_step(rng, vec![]).unwrap();
|
||||||
println!("Nova::prove_step {}: {:?}", i, start.elapsed());
|
println!("Nova::prove_step {}: {:?}", i, start.elapsed());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (running_instance, incoming_instance, cyclefold_instance) = folding_scheme.instances();
|
let (running_instance, incoming_instance, cyclefold_instance) = folding_scheme.instances();
|
||||||
|
|
||||||
println!("Run the Nova's IVC verifier");
|
println!("Run the Nova's IVC verifier");
|
||||||
NOVA::verify(
|
N::verify(
|
||||||
verifier_params,
|
nova_vp,
|
||||||
initial_state.clone(),
|
initial_state.clone(),
|
||||||
folding_scheme.state(), // latest state
|
folding_scheme.state(), // latest state
|
||||||
Fr::from(num_steps as u32),
|
Fr::from(num_steps as u32),
|
||||||
|
|||||||
@@ -20,11 +20,10 @@ use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
|
|||||||
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
||||||
|
|
||||||
use folding_schemes::commitment::{kzg::KZG, pedersen::Pedersen};
|
use folding_schemes::commitment::{kzg::KZG, pedersen::Pedersen};
|
||||||
use folding_schemes::folding::nova::Nova;
|
use folding_schemes::folding::nova::{Nova, PreprocessorParam};
|
||||||
use folding_schemes::frontend::FCircuit;
|
use folding_schemes::frontend::FCircuit;
|
||||||
|
use folding_schemes::transcript::poseidon::poseidon_canonical_config;
|
||||||
use folding_schemes::{Error, FoldingScheme};
|
use folding_schemes::{Error, FoldingScheme};
|
||||||
mod utils;
|
|
||||||
use utils::init_nova_ivc_params;
|
|
||||||
|
|
||||||
/// This is the circuit that we want to fold, it implements the FCircuit trait.
|
/// 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
|
/// The parameter z_i denotes the current state, and z_{i+1} denotes the next state which we get by
|
||||||
@@ -109,13 +108,10 @@ fn main() {
|
|||||||
|
|
||||||
let F_circuit = Sha256FCircuit::<Fr>::new(()).unwrap();
|
let F_circuit = Sha256FCircuit::<Fr>::new(()).unwrap();
|
||||||
|
|
||||||
println!("Prepare Nova ProverParams & VerifierParams");
|
|
||||||
let (prover_params, verifier_params, _) = init_nova_ivc_params::<Sha256FCircuit<Fr>>(F_circuit);
|
|
||||||
|
|
||||||
/// The idea here is that eventually we could replace the next line chunk that defines the
|
/// 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`
|
/// `type N = 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.
|
/// trait, and the rest of our code would be working without needing to be updated.
|
||||||
type NOVA = Nova<
|
type N = Nova<
|
||||||
Projective,
|
Projective,
|
||||||
GVar,
|
GVar,
|
||||||
Projective2,
|
Projective2,
|
||||||
@@ -125,21 +121,27 @@ fn main() {
|
|||||||
Pedersen<Projective2>,
|
Pedersen<Projective2>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
println!("Initialize FoldingScheme");
|
let poseidon_config = poseidon_canonical_config::<Fr>();
|
||||||
let mut folding_scheme = NOVA::init(&prover_params, F_circuit, initial_state.clone()).unwrap();
|
let mut rng = rand::rngs::OsRng;
|
||||||
|
|
||||||
|
println!("Prepare Nova ProverParams & VerifierParams");
|
||||||
|
let nova_preprocess_params = PreprocessorParam::new(poseidon_config, F_circuit);
|
||||||
|
let (nova_pp, nova_vp) = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
|
||||||
|
|
||||||
|
println!("Initialize FoldingScheme");
|
||||||
|
let mut folding_scheme = N::init(&nova_pp, F_circuit, initial_state.clone()).unwrap();
|
||||||
// compute a step of the IVC
|
// compute a step of the IVC
|
||||||
for i in 0..num_steps {
|
for i in 0..num_steps {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
folding_scheme.prove_step(vec![]).unwrap();
|
folding_scheme.prove_step(rng, vec![]).unwrap();
|
||||||
println!("Nova::prove_step {}: {:?}", i, start.elapsed());
|
println!("Nova::prove_step {}: {:?}", i, start.elapsed());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (running_instance, incoming_instance, cyclefold_instance) = folding_scheme.instances();
|
let (running_instance, incoming_instance, cyclefold_instance) = folding_scheme.instances();
|
||||||
|
|
||||||
println!("Run the Nova's IVC verifier");
|
println!("Run the Nova's IVC verifier");
|
||||||
NOVA::verify(
|
N::verify(
|
||||||
verifier_params,
|
nova_vp,
|
||||||
initial_state,
|
initial_state,
|
||||||
folding_scheme.state(), // latest state
|
folding_scheme.state(), // latest state
|
||||||
Fr::from(num_steps as u32),
|
Fr::from(num_steps as u32),
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
#![allow(non_snake_case)]
|
|
||||||
#![allow(non_upper_case_globals)]
|
|
||||||
#![allow(non_camel_case_types)]
|
|
||||||
#![allow(clippy::upper_case_acronyms)]
|
|
||||||
#![allow(dead_code)]
|
|
||||||
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as G1};
|
|
||||||
use ark_crypto_primitives::snark::SNARK;
|
|
||||||
use ark_groth16::{Groth16, ProvingKey, VerifyingKey as G16VerifierKey};
|
|
||||||
use ark_grumpkin::{constraints::GVar as GVar2, Projective as G2};
|
|
||||||
use ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey;
|
|
||||||
use ark_std::Zero;
|
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
use folding_schemes::{
|
|
||||||
commitment::{
|
|
||||||
kzg::{ProverKey as KZGProverKey, KZG},
|
|
||||||
pedersen::Pedersen,
|
|
||||||
CommitmentScheme,
|
|
||||||
},
|
|
||||||
folding::nova::{
|
|
||||||
decider_eth_circuit::DeciderEthCircuit, get_r1cs, Nova, ProverParams, VerifierParams,
|
|
||||||
},
|
|
||||||
frontend::FCircuit,
|
|
||||||
transcript::poseidon::poseidon_canonical_config,
|
|
||||||
FoldingScheme,
|
|
||||||
};
|
|
||||||
|
|
||||||
// This method computes the Nova's Prover & Verifier parameters for the example.
|
|
||||||
// Warning: this method is only for testing purposes. For a real world use case those parameters
|
|
||||||
// should be generated carefully (both the PoseidonConfig and the PedersenParams).
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
pub(crate) fn init_nova_ivc_params<FC: FCircuit<Fr>>(
|
|
||||||
F_circuit: FC,
|
|
||||||
) -> (
|
|
||||||
ProverParams<G1, G2, KZG<'static, Bn254>, Pedersen<G2>>,
|
|
||||||
VerifierParams<G1, G2>,
|
|
||||||
KZGVerifierKey<Bn254>,
|
|
||||||
) {
|
|
||||||
let mut rng = ark_std::test_rng();
|
|
||||||
let poseidon_config = poseidon_canonical_config::<Fr>();
|
|
||||||
|
|
||||||
// get the CM & CF_CM len
|
|
||||||
let (r1cs, cf_r1cs) = get_r1cs::<G1, GVar, G2, GVar2, FC>(&poseidon_config, F_circuit).unwrap();
|
|
||||||
let cs_len = r1cs.A.n_rows;
|
|
||||||
let cf_cs_len = cf_r1cs.A.n_rows;
|
|
||||||
|
|
||||||
// let (pedersen_params, _) = Pedersen::<G1>::setup(&mut rng, cf_len).unwrap();
|
|
||||||
let (kzg_pk, kzg_vk): (KZGProverKey<G1>, KZGVerifierKey<Bn254>) =
|
|
||||||
KZG::<Bn254>::setup(&mut rng, cs_len).unwrap();
|
|
||||||
let (cf_pedersen_params, _) = Pedersen::<G2>::setup(&mut rng, cf_cs_len).unwrap();
|
|
||||||
|
|
||||||
let fs_prover_params = ProverParams::<G1, G2, KZG<Bn254>, Pedersen<G2>> {
|
|
||||||
poseidon_config: poseidon_config.clone(),
|
|
||||||
cs_params: kzg_pk.clone(),
|
|
||||||
cf_cs_params: cf_pedersen_params,
|
|
||||||
};
|
|
||||||
let fs_verifier_params = VerifierParams::<G1, G2> {
|
|
||||||
poseidon_config: poseidon_config.clone(),
|
|
||||||
r1cs,
|
|
||||||
cf_r1cs,
|
|
||||||
};
|
|
||||||
(fs_prover_params, fs_verifier_params, kzg_vk)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initializes Nova parameters and DeciderEth parameters. Only for test purposes.
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
pub(crate) fn init_ivc_and_decider_params<FC: FCircuit<Fr>>(
|
|
||||||
f_circuit: FC,
|
|
||||||
) -> (
|
|
||||||
ProverParams<G1, G2, KZG<'static, Bn254>, Pedersen<G2>>,
|
|
||||||
KZGVerifierKey<Bn254>,
|
|
||||||
ProvingKey<Bn254>,
|
|
||||||
G16VerifierKey<Bn254>,
|
|
||||||
) {
|
|
||||||
let mut rng = rand::rngs::OsRng;
|
|
||||||
let start = Instant::now();
|
|
||||||
let (fs_prover_params, _, kzg_vk) = init_nova_ivc_params::<FC>(f_circuit.clone());
|
|
||||||
println!("generated Nova folding params: {:?}", start.elapsed());
|
|
||||||
|
|
||||||
pub type NOVA<FC> = Nova<G1, GVar, G2, GVar2, FC, KZG<'static, Bn254>, Pedersen<G2>>;
|
|
||||||
let z_0 = vec![Fr::zero(); f_circuit.state_len()];
|
|
||||||
let nova = NOVA::init(&fs_prover_params, f_circuit, z_0.clone()).unwrap();
|
|
||||||
|
|
||||||
let decider_circuit =
|
|
||||||
DeciderEthCircuit::<G1, GVar, G2, GVar2, KZG<Bn254>, Pedersen<G2>>::from_nova::<FC>(
|
|
||||||
nova.clone(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let start = Instant::now();
|
|
||||||
let (g16_pk, g16_vk) =
|
|
||||||
Groth16::<Bn254>::circuit_specific_setup(decider_circuit.clone(), &mut rng).unwrap();
|
|
||||||
println!(
|
|
||||||
"generated G16 (Decider circuit) params: {:?}",
|
|
||||||
start.elapsed()
|
|
||||||
);
|
|
||||||
(fs_prover_params, kzg_vk, g16_pk, g16_vk)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
||||||
@@ -54,6 +54,13 @@ impl<C: CurveGroup, const H: bool> CommitmentScheme<C, H> for IPA<C, H> {
|
|||||||
type ProverChallenge = (C::ScalarField, C, Vec<C::ScalarField>);
|
type ProverChallenge = (C::ScalarField, C, Vec<C::ScalarField>);
|
||||||
type Challenge = (C::ScalarField, C, Vec<C::ScalarField>);
|
type Challenge = (C::ScalarField, C, Vec<C::ScalarField>);
|
||||||
|
|
||||||
|
fn is_hiding() -> bool {
|
||||||
|
if H {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn setup(
|
fn setup(
|
||||||
mut rng: impl RngCore,
|
mut rng: impl RngCore,
|
||||||
len: usize,
|
len: usize,
|
||||||
|
|||||||
@@ -93,6 +93,13 @@ where
|
|||||||
type ProverChallenge = E::ScalarField;
|
type ProverChallenge = E::ScalarField;
|
||||||
type Challenge = E::ScalarField;
|
type Challenge = E::ScalarField;
|
||||||
|
|
||||||
|
fn is_hiding() -> bool {
|
||||||
|
if H {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// setup returns the tuple (ProverKey, VerifierKey). For real world deployments the setup must
|
/// setup returns the tuple (ProverKey, VerifierKey). For real world deployments the setup must
|
||||||
/// be computed in the most trustless way possible, usually through a MPC ceremony.
|
/// be computed in the most trustless way possible, usually through a MPC ceremony.
|
||||||
fn setup(
|
fn setup(
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ pub trait CommitmentScheme<C: CurveGroup, const H: bool = false>: Clone + Debug
|
|||||||
type ProverChallenge: Clone + Debug;
|
type ProverChallenge: Clone + Debug;
|
||||||
type Challenge: Clone + Debug;
|
type Challenge: Clone + Debug;
|
||||||
|
|
||||||
|
fn is_hiding() -> bool;
|
||||||
|
|
||||||
fn setup(
|
fn setup(
|
||||||
rng: impl RngCore,
|
rng: impl RngCore,
|
||||||
len: usize,
|
len: usize,
|
||||||
|
|||||||
@@ -38,6 +38,13 @@ impl<C: CurveGroup, const H: bool> CommitmentScheme<C, H> for Pedersen<C, H> {
|
|||||||
type ProverChallenge = (C::ScalarField, Vec<C::ScalarField>, C, C::ScalarField);
|
type ProverChallenge = (C::ScalarField, Vec<C::ScalarField>, C, C::ScalarField);
|
||||||
type Challenge = C::ScalarField;
|
type Challenge = C::ScalarField;
|
||||||
|
|
||||||
|
fn is_hiding() -> bool {
|
||||||
|
if H {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn setup(
|
fn setup(
|
||||||
mut rng: impl RngCore,
|
mut rng: impl RngCore,
|
||||||
len: usize,
|
len: usize,
|
||||||
|
|||||||
@@ -460,9 +460,9 @@ pub mod tests {
|
|||||||
use ark_std::UniformRand;
|
use ark_std::UniformRand;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::folding::nova::get_cm_coordinates;
|
|
||||||
use crate::folding::nova::nifs::tests::prepare_simple_fold_inputs;
|
use crate::folding::nova::nifs::tests::prepare_simple_fold_inputs;
|
||||||
use crate::transcript::poseidon::poseidon_canonical_config;
|
use crate::transcript::poseidon::poseidon_canonical_config;
|
||||||
|
use crate::utils::get_cm_coordinates;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_committed_instance_cyclefold_var() {
|
fn test_committed_instance_cyclefold_var() {
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ use ark_std::rand::Rng;
|
|||||||
|
|
||||||
use super::Witness;
|
use super::Witness;
|
||||||
use crate::ccs::CCS;
|
use crate::ccs::CCS;
|
||||||
use crate::commitment::{
|
use crate::commitment::CommitmentScheme;
|
||||||
pedersen::{Params as PedersenParams, Pedersen},
|
|
||||||
CommitmentScheme,
|
|
||||||
};
|
|
||||||
use crate::utils::mle::dense_vec_to_dense_mle;
|
use crate::utils::mle::dense_vec_to_dense_mle;
|
||||||
use crate::utils::vec::mat_vec_mul;
|
use crate::utils::vec::mat_vec_mul;
|
||||||
use crate::utils::virtual_polynomial::{build_eq_x_r_vec, VirtualPolynomial};
|
use crate::utils::virtual_polynomial::{build_eq_x_r_vec, VirtualPolynomial};
|
||||||
@@ -27,10 +24,10 @@ pub struct CCCS<C: CurveGroup> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<F: PrimeField> CCS<F> {
|
impl<F: PrimeField> CCS<F> {
|
||||||
pub fn to_cccs<R: Rng, C: CurveGroup>(
|
pub fn to_cccs<R: Rng, C: CurveGroup, CS: CommitmentScheme<C>>(
|
||||||
&self,
|
&self,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
pedersen_params: &PedersenParams<C>,
|
cs_params: &CS::ProverParams,
|
||||||
z: &[C::ScalarField],
|
z: &[C::ScalarField],
|
||||||
) -> Result<(CCCS<C>, Witness<C::ScalarField>), Error>
|
) -> Result<(CCCS<C>, Witness<C::ScalarField>), Error>
|
||||||
where
|
where
|
||||||
@@ -38,8 +35,14 @@ impl<F: PrimeField> CCS<F> {
|
|||||||
C: CurveGroup<ScalarField = F>,
|
C: CurveGroup<ScalarField = F>,
|
||||||
{
|
{
|
||||||
let w: Vec<C::ScalarField> = z[(1 + self.l)..].to_vec();
|
let w: Vec<C::ScalarField> = z[(1 + self.l)..].to_vec();
|
||||||
let r_w = C::ScalarField::rand(rng);
|
|
||||||
let C = Pedersen::<C, true>::commit(pedersen_params, &w, &r_w)?;
|
// if the commitment scheme is set to be hiding, set the random blinding parameter
|
||||||
|
let r_w = if CS::is_hiding() {
|
||||||
|
C::ScalarField::rand(rng)
|
||||||
|
} else {
|
||||||
|
C::ScalarField::zero()
|
||||||
|
};
|
||||||
|
let C = CS::commit(cs_params, &w, &r_w)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
CCCS::<C> {
|
CCCS::<C> {
|
||||||
@@ -95,19 +98,13 @@ impl<C: CurveGroup> CCCS<C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform the check of the CCCS instance described at section 4.1
|
/// Perform the check of the CCCS instance described at section 4.1,
|
||||||
|
/// notice that this method does not check the commitment correctness
|
||||||
pub fn check_relation(
|
pub fn check_relation(
|
||||||
&self,
|
&self,
|
||||||
pedersen_params: &PedersenParams<C>,
|
|
||||||
ccs: &CCS<C::ScalarField>,
|
ccs: &CCS<C::ScalarField>,
|
||||||
w: &Witness<C::ScalarField>,
|
w: &Witness<C::ScalarField>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// check that C is the commitment of w. Notice that this is not verifying a Pedersen
|
|
||||||
// opening, but checking that the commitment comes from committing to the witness.
|
|
||||||
if self.C != Pedersen::<C, true>::commit(pedersen_params, &w.w, &w.r_w)? {
|
|
||||||
return Err(Error::NotSatisfied);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check CCCS relation
|
// check CCCS relation
|
||||||
let z: Vec<C::ScalarField> =
|
let z: Vec<C::ScalarField> =
|
||||||
[vec![C::ScalarField::one()], self.x.clone(), w.w.to_vec()].concat();
|
[vec![C::ScalarField::one()], self.x.clone(), w.w.to_vec()].concat();
|
||||||
|
|||||||
@@ -596,7 +596,7 @@ where
|
|||||||
|
|
||||||
/// Returns the cs (ConstraintSystem) and the CCS out of the AugmentedFCircuit
|
/// Returns the cs (ConstraintSystem) and the CCS out of the AugmentedFCircuit
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
fn compute_cs_ccs(
|
pub fn compute_cs_ccs(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<(ConstraintSystem<C1::ScalarField>, CCS<C1::ScalarField>), Error> {
|
) -> Result<(ConstraintSystem<C1::ScalarField>, CCS<C1::ScalarField>), Error> {
|
||||||
let cs = ConstraintSystem::<C1::ScalarField>::new_ref();
|
let cs = ConstraintSystem::<C1::ScalarField>::new_ref();
|
||||||
@@ -720,8 +720,14 @@ where
|
|||||||
z_0.clone(),
|
z_0.clone(),
|
||||||
z_i1.clone(),
|
z_i1.clone(),
|
||||||
)?;
|
)?;
|
||||||
let x = FpVar::new_input(cs.clone(), || Ok(self.x.unwrap_or(C1::ScalarField::zero())))?;
|
let (u_i1_x_base, _) = LCCCSVar::new_constant(cs.clone(), U_dummy)?.hash(
|
||||||
x.enforce_equal(&u_i1_x)?;
|
&crh_params,
|
||||||
|
FpVar::<CF1<C1>>::one(),
|
||||||
|
z_0.clone(),
|
||||||
|
z_i1.clone(),
|
||||||
|
)?;
|
||||||
|
let x = FpVar::new_input(cs.clone(), || Ok(self.x.unwrap_or(u_i1_x_base.value()?)))?;
|
||||||
|
x.enforce_equal(&is_basecase.select(&u_i1_x_base, &u_i1_x)?)?;
|
||||||
|
|
||||||
// convert rho_bits to a `NonNativeFieldVar`
|
// convert rho_bits to a `NonNativeFieldVar`
|
||||||
let rho_nonnat = {
|
let rho_nonnat = {
|
||||||
@@ -817,15 +823,14 @@ mod tests {
|
|||||||
utils::{compute_c, compute_sigmas_thetas},
|
utils::{compute_c, compute_sigmas_thetas},
|
||||||
Witness,
|
Witness,
|
||||||
},
|
},
|
||||||
nova::{
|
nova::{traits::NovaR1CS, CommittedInstance, Witness as NovaWitness},
|
||||||
get_cm_coordinates, traits::NovaR1CS, CommittedInstance, Witness as NovaWitness,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
frontend::tests::CubicFCircuit,
|
frontend::tests::CubicFCircuit,
|
||||||
transcript::{
|
transcript::{
|
||||||
poseidon::{poseidon_canonical_config, PoseidonTranscript, PoseidonTranscriptVar},
|
poseidon::{poseidon_canonical_config, PoseidonTranscript, PoseidonTranscriptVar},
|
||||||
Transcript,
|
Transcript,
|
||||||
},
|
},
|
||||||
|
utils::get_cm_coordinates,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -858,13 +863,17 @@ mod tests {
|
|||||||
// Create the LCCCS instances out of z_lcccs
|
// Create the LCCCS instances out of z_lcccs
|
||||||
let mut lcccs_instances = Vec::new();
|
let mut lcccs_instances = Vec::new();
|
||||||
for z_i in z_lcccs.iter() {
|
for z_i in z_lcccs.iter() {
|
||||||
let (inst, _) = ccs.to_lcccs(&mut rng, &pedersen_params, z_i).unwrap();
|
let (inst, _) = ccs
|
||||||
|
.to_lcccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, z_i)
|
||||||
|
.unwrap();
|
||||||
lcccs_instances.push(inst);
|
lcccs_instances.push(inst);
|
||||||
}
|
}
|
||||||
// Create the CCCS instance out of z_cccs
|
// Create the CCCS instance out of z_cccs
|
||||||
let mut cccs_instances = Vec::new();
|
let mut cccs_instances = Vec::new();
|
||||||
for z_i in z_cccs.iter() {
|
for z_i in z_cccs.iter() {
|
||||||
let (inst, _) = ccs.to_cccs(&mut rng, &pedersen_params, z_i).unwrap();
|
let (inst, _) = ccs
|
||||||
|
.to_cccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, z_i)
|
||||||
|
.unwrap();
|
||||||
cccs_instances.push(inst);
|
cccs_instances.push(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -950,7 +959,9 @@ mod tests {
|
|||||||
let mut lcccs_instances = Vec::new();
|
let mut lcccs_instances = Vec::new();
|
||||||
let mut w_lcccs = Vec::new();
|
let mut w_lcccs = Vec::new();
|
||||||
for z_i in z_lcccs.iter() {
|
for z_i in z_lcccs.iter() {
|
||||||
let (running_instance, w) = ccs.to_lcccs(&mut rng, &pedersen_params, z_i).unwrap();
|
let (running_instance, w) = ccs
|
||||||
|
.to_lcccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, z_i)
|
||||||
|
.unwrap();
|
||||||
lcccs_instances.push(running_instance);
|
lcccs_instances.push(running_instance);
|
||||||
w_lcccs.push(w);
|
w_lcccs.push(w);
|
||||||
}
|
}
|
||||||
@@ -958,7 +969,9 @@ mod tests {
|
|||||||
let mut cccs_instances = Vec::new();
|
let mut cccs_instances = Vec::new();
|
||||||
let mut w_cccs = Vec::new();
|
let mut w_cccs = Vec::new();
|
||||||
for z_i in z_cccs.iter() {
|
for z_i in z_cccs.iter() {
|
||||||
let (new_instance, w) = ccs.to_cccs(&mut rng, &pedersen_params, z_i).unwrap();
|
let (new_instance, w) = ccs
|
||||||
|
.to_cccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, z_i)
|
||||||
|
.unwrap();
|
||||||
cccs_instances.push(new_instance);
|
cccs_instances.push(new_instance);
|
||||||
w_cccs.push(w);
|
w_cccs.push(w);
|
||||||
}
|
}
|
||||||
@@ -996,9 +1009,7 @@ mod tests {
|
|||||||
assert_eq!(folded_lcccs, folded_lcccs_v);
|
assert_eq!(folded_lcccs, folded_lcccs_v);
|
||||||
|
|
||||||
// Check that the folded LCCCS instance is a valid instance with respect to the folded witness
|
// Check that the folded LCCCS instance is a valid instance with respect to the folded witness
|
||||||
folded_lcccs
|
folded_lcccs.check_relation(&ccs, &folded_witness).unwrap();
|
||||||
.check_relation(&pedersen_params, &ccs, &folded_witness)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// allocate circuit inputs
|
// allocate circuit inputs
|
||||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||||
@@ -1042,7 +1053,9 @@ mod tests {
|
|||||||
let i = Fr::from(3_u32);
|
let i = Fr::from(3_u32);
|
||||||
let z_0 = vec![Fr::from(3_u32)];
|
let z_0 = vec![Fr::from(3_u32)];
|
||||||
let z_i = vec![Fr::from(3_u32)];
|
let z_i = vec![Fr::from(3_u32)];
|
||||||
let (lcccs, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1).unwrap();
|
let (lcccs, _) = ccs
|
||||||
|
.to_lcccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, &z1)
|
||||||
|
.unwrap();
|
||||||
let h = lcccs
|
let h = lcccs
|
||||||
.clone()
|
.clone()
|
||||||
.hash(&poseidon_config, i, z_0.clone(), z_i.clone())
|
.hash(&poseidon_config, i, z_0.clone(), z_i.clone())
|
||||||
@@ -1104,11 +1117,11 @@ mod tests {
|
|||||||
let mut z_i = z_0.clone();
|
let mut z_i = z_0.clone();
|
||||||
|
|
||||||
// prepare the dummy instances
|
// prepare the dummy instances
|
||||||
let W_dummy = Witness::<Fr>::new(vec![Fr::zero(); ccs.n - ccs.l - 1]);
|
let W_dummy = Witness::<Fr>::dummy(&ccs);
|
||||||
let U_dummy = LCCCS::<Projective>::dummy(ccs.l, ccs.t, ccs.s);
|
let U_dummy = LCCCS::<Projective>::dummy(ccs.l, ccs.t, ccs.s);
|
||||||
let w_dummy = W_dummy.clone();
|
let w_dummy = W_dummy.clone();
|
||||||
let u_dummy = CCCS::<Projective>::dummy(ccs.l);
|
let u_dummy = CCCS::<Projective>::dummy(ccs.l);
|
||||||
let (cf_w_dummy, cf_u_dummy): (NovaWitness<Projective2>, CommittedInstance<Projective2>) =
|
let (cf_W_dummy, cf_U_dummy): (NovaWitness<Projective2>, CommittedInstance<Projective2>) =
|
||||||
cf_r1cs.dummy_instance();
|
cf_r1cs.dummy_instance();
|
||||||
|
|
||||||
// set the initial dummy instances
|
// set the initial dummy instances
|
||||||
@@ -1116,8 +1129,8 @@ mod tests {
|
|||||||
let mut U_i = U_dummy.clone();
|
let mut U_i = U_dummy.clone();
|
||||||
let mut w_i = w_dummy.clone();
|
let mut w_i = w_dummy.clone();
|
||||||
let mut u_i = u_dummy.clone();
|
let mut u_i = u_dummy.clone();
|
||||||
let mut cf_W_i = cf_w_dummy.clone();
|
let mut cf_W_i = cf_W_dummy.clone();
|
||||||
let mut cf_U_i = cf_u_dummy.clone();
|
let mut cf_U_i = cf_U_dummy.clone();
|
||||||
u_i.x = vec![
|
u_i.x = vec![
|
||||||
U_i.hash(&poseidon_config, Fr::zero(), z_0.clone(), z_i.clone())
|
U_i.hash(&poseidon_config, Fr::zero(), z_0.clone(), z_i.clone())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
@@ -1128,28 +1141,19 @@ mod tests {
|
|||||||
let mut iFr = Fr::zero();
|
let mut iFr = Fr::zero();
|
||||||
for i in 0..n_steps {
|
for i in 0..n_steps {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let mut transcript_p: PoseidonTranscript<Projective> =
|
|
||||||
PoseidonTranscript::<Projective>::new(&poseidon_config.clone());
|
|
||||||
let (nimfs_proof, U_i1, W_i1, rho_bits) =
|
|
||||||
NIMFS::<Projective, PoseidonTranscript<Projective>>::prove(
|
|
||||||
&mut transcript_p,
|
|
||||||
&ccs,
|
|
||||||
&[U_i.clone()],
|
|
||||||
&[u_i.clone()],
|
|
||||||
&[W_i.clone()],
|
|
||||||
&[w_i.clone()],
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// sanity check: check the folded instance relation
|
|
||||||
U_i1.check_relation(&pedersen_params, &ccs, &W_i1).unwrap();
|
|
||||||
|
|
||||||
let z_i1 = F_circuit.step_native(i, z_i.clone(), vec![]).unwrap();
|
let z_i1 = F_circuit.step_native(i, z_i.clone(), vec![]).unwrap();
|
||||||
let u_i1_x = U_i1
|
|
||||||
.hash(&poseidon_config, iFr + Fr::one(), z_0.clone(), z_i1.clone())
|
let (U_i1, W_i1);
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
|
W_i1 = Witness::<Fr>::dummy(&ccs);
|
||||||
|
U_i1 = LCCCS::dummy(ccs.l, ccs.t, ccs.s);
|
||||||
|
|
||||||
|
let u_i1_x = U_i1
|
||||||
|
.hash(&poseidon_config, Fr::one(), z_0.clone(), z_i1.clone())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// hash the initial (dummy) CycleFold instance, which is used as the 2nd public
|
// hash the initial (dummy) CycleFold instance, which is used as the 2nd public
|
||||||
// input in the AugmentedFCircuit
|
// input in the AugmentedFCircuit
|
||||||
let cf_u_i1_x = cf_U_i.hash_cyclefold(&poseidon_config).unwrap();
|
let cf_u_i1_x = cf_U_i.hash_cyclefold(&poseidon_config).unwrap();
|
||||||
@@ -1160,8 +1164,8 @@ mod tests {
|
|||||||
_gc2: PhantomData,
|
_gc2: PhantomData,
|
||||||
poseidon_config: poseidon_config.clone(),
|
poseidon_config: poseidon_config.clone(),
|
||||||
ccs: ccs.clone(),
|
ccs: ccs.clone(),
|
||||||
i: Some(iFr),
|
i: Some(Fr::zero()),
|
||||||
i_usize: Some(i),
|
i_usize: Some(0),
|
||||||
z_0: Some(z_0.clone()),
|
z_0: Some(z_0.clone()),
|
||||||
z_i: Some(z_i.clone()),
|
z_i: Some(z_i.clone()),
|
||||||
external_inputs: Some(vec![]),
|
external_inputs: Some(vec![]),
|
||||||
@@ -1170,7 +1174,7 @@ mod tests {
|
|||||||
U_i1_C: Some(U_i1.C),
|
U_i1_C: Some(U_i1.C),
|
||||||
F: F_circuit,
|
F: F_circuit,
|
||||||
x: Some(u_i1_x),
|
x: Some(u_i1_x),
|
||||||
nimfs_proof: Some(nimfs_proof),
|
nimfs_proof: None,
|
||||||
|
|
||||||
// cyclefold values
|
// cyclefold values
|
||||||
cf_u_i_cmW: None,
|
cf_u_i_cmW: None,
|
||||||
@@ -1179,6 +1183,27 @@ mod tests {
|
|||||||
cf_cmT: None,
|
cf_cmT: None,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
let mut transcript_p: PoseidonTranscript<Projective> =
|
||||||
|
PoseidonTranscript::<Projective>::new(&poseidon_config.clone());
|
||||||
|
let (rho_bits, nimfs_proof);
|
||||||
|
(nimfs_proof, U_i1, W_i1, rho_bits) =
|
||||||
|
NIMFS::<Projective, PoseidonTranscript<Projective>>::prove(
|
||||||
|
&mut transcript_p,
|
||||||
|
&ccs,
|
||||||
|
&[U_i.clone()],
|
||||||
|
&[u_i.clone()],
|
||||||
|
&[W_i.clone()],
|
||||||
|
&[w_i.clone()],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// sanity check: check the folded instance relation
|
||||||
|
U_i1.check_relation(&ccs, &W_i1).unwrap();
|
||||||
|
|
||||||
|
let u_i1_x = U_i1
|
||||||
|
.hash(&poseidon_config, iFr + Fr::one(), z_0.clone(), z_i1.clone())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let rho_Fq = Fq::from_bigint(BigInteger::from_bits_le(&rho_bits)).unwrap();
|
let rho_Fq = Fq::from_bigint(BigInteger::from_bits_le(&rho_bits)).unwrap();
|
||||||
// CycleFold part:
|
// CycleFold part:
|
||||||
// get the vector used as public inputs 'x' in the CycleFold circuit
|
// get the vector used as public inputs 'x' in the CycleFold circuit
|
||||||
@@ -1260,8 +1285,10 @@ mod tests {
|
|||||||
let r1cs_z = [vec![Fr::one()], r1cs_x_i1.clone(), r1cs_w_i1.clone()].concat();
|
let r1cs_z = [vec![Fr::one()], r1cs_x_i1.clone(), r1cs_w_i1.clone()].concat();
|
||||||
// compute committed instances, w_{i+1}, u_{i+1}, which will be used as w_i, u_i, so we
|
// compute committed instances, w_{i+1}, u_{i+1}, which will be used as w_i, u_i, so we
|
||||||
// assign them directly to w_i, u_i.
|
// assign them directly to w_i, u_i.
|
||||||
(u_i, w_i) = ccs.to_cccs(&mut rng, &pedersen_params, &r1cs_z).unwrap();
|
(u_i, w_i) = ccs
|
||||||
u_i.check_relation(&pedersen_params, &ccs, &w_i).unwrap();
|
.to_cccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, &r1cs_z)
|
||||||
|
.unwrap();
|
||||||
|
u_i.check_relation(&ccs, &w_i).unwrap();
|
||||||
|
|
||||||
// sanity checks
|
// sanity checks
|
||||||
assert_eq!(w_i.w, r1cs_w_i1);
|
assert_eq!(w_i.w, r1cs_w_i1);
|
||||||
@@ -1284,9 +1311,9 @@ mod tests {
|
|||||||
W_i = W_i1.clone();
|
W_i = W_i1.clone();
|
||||||
|
|
||||||
// check the new LCCCS instance relation
|
// check the new LCCCS instance relation
|
||||||
U_i.check_relation(&pedersen_params, &ccs, &W_i).unwrap();
|
U_i.check_relation(&ccs, &W_i).unwrap();
|
||||||
// check the new CCCS instance relation
|
// check the new CCCS instance relation
|
||||||
u_i.check_relation(&pedersen_params, &ccs, &w_i).unwrap();
|
u_i.check_relation(&ccs, &w_i).unwrap();
|
||||||
|
|
||||||
// check the CycleFold instance relation
|
// check the CycleFold instance relation
|
||||||
cf_r1cs
|
cf_r1cs
|
||||||
|
|||||||
@@ -11,10 +11,7 @@ use ark_std::Zero;
|
|||||||
|
|
||||||
use super::Witness;
|
use super::Witness;
|
||||||
use crate::ccs::CCS;
|
use crate::ccs::CCS;
|
||||||
use crate::commitment::{
|
use crate::commitment::CommitmentScheme;
|
||||||
pedersen::{Params as PedersenParams, Pedersen},
|
|
||||||
CommitmentScheme,
|
|
||||||
};
|
|
||||||
use crate::folding::circuits::nonnative::affine::nonnative_affine_to_field_elements;
|
use crate::folding::circuits::nonnative::affine::nonnative_affine_to_field_elements;
|
||||||
use crate::utils::mle::dense_vec_to_dense_mle;
|
use crate::utils::mle::dense_vec_to_dense_mle;
|
||||||
use crate::utils::vec::mat_vec_mul;
|
use crate::utils::vec::mat_vec_mul;
|
||||||
@@ -36,10 +33,10 @@ pub struct LCCCS<C: CurveGroup> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<F: PrimeField> CCS<F> {
|
impl<F: PrimeField> CCS<F> {
|
||||||
pub fn to_lcccs<R: Rng, C: CurveGroup>(
|
pub fn to_lcccs<R: Rng, C: CurveGroup, CS: CommitmentScheme<C>>(
|
||||||
&self,
|
&self,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
pedersen_params: &PedersenParams<C>,
|
cs_params: &CS::ProverParams,
|
||||||
z: &[C::ScalarField],
|
z: &[C::ScalarField],
|
||||||
) -> Result<(LCCCS<C>, Witness<C::ScalarField>), Error>
|
) -> Result<(LCCCS<C>, Witness<C::ScalarField>), Error>
|
||||||
where
|
where
|
||||||
@@ -47,8 +44,13 @@ impl<F: PrimeField> CCS<F> {
|
|||||||
C: CurveGroup<ScalarField = F>,
|
C: CurveGroup<ScalarField = F>,
|
||||||
{
|
{
|
||||||
let w: Vec<C::ScalarField> = z[(1 + self.l)..].to_vec();
|
let w: Vec<C::ScalarField> = z[(1 + self.l)..].to_vec();
|
||||||
let r_w = C::ScalarField::rand(rng);
|
// if the commitment scheme is set to be hiding, set the random blinding parameter
|
||||||
let C = Pedersen::<C, true>::commit(pedersen_params, &w, &r_w)?;
|
let r_w = if CS::is_hiding() {
|
||||||
|
C::ScalarField::rand(rng)
|
||||||
|
} else {
|
||||||
|
C::ScalarField::zero()
|
||||||
|
};
|
||||||
|
let C = CS::commit(cs_params, &w, &r_w)?;
|
||||||
|
|
||||||
let r_x: Vec<C::ScalarField> = (0..self.s).map(|_| C::ScalarField::rand(rng)).collect();
|
let r_x: Vec<C::ScalarField> = (0..self.s).map(|_| C::ScalarField::rand(rng)).collect();
|
||||||
|
|
||||||
@@ -91,19 +93,13 @@ impl<C: CurveGroup> LCCCS<C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform the check of the LCCCS instance described at section 4.2
|
/// Perform the check of the LCCCS instance described at section 4.2,
|
||||||
|
/// notice that this method does not check the commitment correctness
|
||||||
pub fn check_relation(
|
pub fn check_relation(
|
||||||
&self,
|
&self,
|
||||||
pedersen_params: &PedersenParams<C>,
|
|
||||||
ccs: &CCS<C::ScalarField>,
|
ccs: &CCS<C::ScalarField>,
|
||||||
w: &Witness<C::ScalarField>,
|
w: &Witness<C::ScalarField>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// check that C is the commitment of w. Notice that this is not verifying a Pedersen
|
|
||||||
// opening, but checking that the Commitment comes from committing to the witness.
|
|
||||||
if self.C != Pedersen::<C, true>::commit(pedersen_params, &w.w, &w.r_w)? {
|
|
||||||
return Err(Error::NotSatisfied);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check CCS relation
|
// check CCS relation
|
||||||
let z: Vec<C::ScalarField> = [vec![self.u], self.x.clone(), w.w.to_vec()].concat();
|
let z: Vec<C::ScalarField> = [vec![self.u], self.x.clone(), w.w.to_vec()].concat();
|
||||||
|
|
||||||
@@ -172,6 +168,7 @@ pub mod tests {
|
|||||||
r1cs::R1CS,
|
r1cs::R1CS,
|
||||||
tests::{get_test_ccs, get_test_z},
|
tests::{get_test_ccs, get_test_z},
|
||||||
};
|
};
|
||||||
|
use crate::commitment::pedersen::Pedersen;
|
||||||
use crate::utils::hypercube::BooleanHypercube;
|
use crate::utils::hypercube::BooleanHypercube;
|
||||||
use crate::utils::virtual_polynomial::{build_eq_x_r_vec, VirtualPolynomial};
|
use crate::utils::virtual_polynomial::{build_eq_x_r_vec, VirtualPolynomial};
|
||||||
|
|
||||||
@@ -206,14 +203,16 @@ pub mod tests {
|
|||||||
|
|
||||||
let n_rows = 2_u32.pow(5) as usize;
|
let n_rows = 2_u32.pow(5) as usize;
|
||||||
let n_cols = 2_u32.pow(5) as usize;
|
let n_cols = 2_u32.pow(5) as usize;
|
||||||
let r1cs = R1CS::rand(&mut rng, n_rows, n_cols);
|
let r1cs = R1CS::<Fr>::rand(&mut rng, n_rows, n_cols);
|
||||||
let ccs = CCS::from_r1cs(r1cs);
|
let ccs = CCS::from_r1cs(r1cs);
|
||||||
let z: Vec<Fr> = (0..n_cols).map(|_| Fr::rand(&mut rng)).collect();
|
let z: Vec<Fr> = (0..n_cols).map(|_| Fr::rand(&mut rng)).collect();
|
||||||
|
|
||||||
let (pedersen_params, _) =
|
let (pedersen_params, _) =
|
||||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||||
|
|
||||||
let (lcccs, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z).unwrap();
|
let (lcccs, _) = ccs
|
||||||
|
.to_lcccs::<_, Projective, Pedersen<Projective>>(&mut rng, &pedersen_params, &z)
|
||||||
|
.unwrap();
|
||||||
// with our test vector coming from R1CS, v should have length 3
|
// with our test vector coming from R1CS, v should have length 3
|
||||||
assert_eq!(lcccs.v.len(), 3);
|
assert_eq!(lcccs.v.len(), 3);
|
||||||
|
|
||||||
@@ -245,7 +244,9 @@ pub mod tests {
|
|||||||
let (pedersen_params, _) =
|
let (pedersen_params, _) =
|
||||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||||
// Compute v_j with the right z
|
// Compute v_j with the right z
|
||||||
let (lcccs, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z).unwrap();
|
let (lcccs, _) = ccs
|
||||||
|
.to_lcccs::<_, Projective, Pedersen<Projective>>(&mut rng, &pedersen_params, &z)
|
||||||
|
.unwrap();
|
||||||
// with our test vector coming from R1CS, v should have length 3
|
// with our test vector coming from R1CS, v should have length 3
|
||||||
assert_eq!(lcccs.v.len(), 3);
|
assert_eq!(lcccs.v.len(), 3);
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,42 @@
|
|||||||
/// Implements the scheme described in [HyperNova](https://eprint.iacr.org/2023/573.pdf)
|
/// Implements the scheme described in [HyperNova](https://eprint.iacr.org/2023/573.pdf)
|
||||||
use crate::ccs::CCS;
|
use ark_crypto_primitives::sponge::{poseidon::PoseidonConfig, Absorb};
|
||||||
use ark_ff::PrimeField;
|
use ark_ec::{CurveGroup, Group};
|
||||||
|
use ark_ff::{BigInteger, PrimeField};
|
||||||
|
use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget};
|
||||||
|
use ark_std::rand::RngCore;
|
||||||
|
use ark_std::{One, Zero};
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
pub mod cccs;
|
pub mod cccs;
|
||||||
pub mod circuits;
|
pub mod circuits;
|
||||||
|
use circuits::AugmentedFCircuit;
|
||||||
pub mod lcccs;
|
pub mod lcccs;
|
||||||
pub mod nimfs;
|
pub mod nimfs;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
use cccs::CCCS;
|
||||||
|
use lcccs::LCCCS;
|
||||||
|
use nimfs::NIMFS;
|
||||||
|
|
||||||
|
use crate::commitment::CommitmentScheme;
|
||||||
|
use crate::folding::circuits::{
|
||||||
|
cyclefold::{fold_cyclefold_circuit, CycleFoldCircuit},
|
||||||
|
CF2,
|
||||||
|
};
|
||||||
|
use crate::folding::nova::{
|
||||||
|
get_r1cs_from_cs, traits::NovaR1CS, CommittedInstance, Witness as NovaWitness,
|
||||||
|
};
|
||||||
|
use crate::frontend::FCircuit;
|
||||||
|
use crate::utils::get_cm_coordinates;
|
||||||
|
use crate::Error;
|
||||||
|
use crate::FoldingScheme;
|
||||||
|
use crate::{
|
||||||
|
ccs::{
|
||||||
|
r1cs::{extract_w_x, R1CS},
|
||||||
|
CCS,
|
||||||
|
},
|
||||||
|
transcript::{poseidon::PoseidonTranscript, Transcript},
|
||||||
|
};
|
||||||
|
|
||||||
/// Witness for the LCCCS & CCCS, containing the w vector, and the r_w used as randomness in the Pedersen commitment.
|
/// Witness for the LCCCS & CCCS, containing the w vector, and the r_w used as randomness in the Pedersen commitment.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
@@ -25,3 +55,556 @@ impl<F: PrimeField> Witness<F> {
|
|||||||
Witness::<F>::new(vec![F::zero(); ccs.n - ccs.l - 1])
|
Witness::<F>::new(vec![F::zero(); ccs.n - ccs.l - 1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct PreprocessorParam<C1, C2, FC, CS1, CS2>
|
||||||
|
where
|
||||||
|
C1: CurveGroup,
|
||||||
|
C2: CurveGroup,
|
||||||
|
FC: FCircuit<C1::ScalarField>,
|
||||||
|
CS1: CommitmentScheme<C1>,
|
||||||
|
CS2: CommitmentScheme<C2>,
|
||||||
|
{
|
||||||
|
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||||
|
pub F: FC,
|
||||||
|
// cs_params & cf_cs_params: if not provided, will be generated at the preprocess method
|
||||||
|
pub cs_params: Option<CS1::ProverParams>,
|
||||||
|
pub cf_cs_params: Option<CS2::ProverParams>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ProverParams<C1, C2, CS1, CS2>
|
||||||
|
where
|
||||||
|
C1: CurveGroup,
|
||||||
|
C2: CurveGroup,
|
||||||
|
CS1: CommitmentScheme<C1>,
|
||||||
|
CS2: CommitmentScheme<C2>,
|
||||||
|
{
|
||||||
|
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||||
|
pub cs_params: CS1::ProverParams,
|
||||||
|
pub cf_cs_params: CS2::ProverParams,
|
||||||
|
// if ccs is set, it will be used, if not, it will be computed at runtime
|
||||||
|
pub ccs: Option<CCS<C1::ScalarField>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct VerifierParams<
|
||||||
|
C1: CurveGroup,
|
||||||
|
C2: CurveGroup,
|
||||||
|
CS1: CommitmentScheme<C1>,
|
||||||
|
CS2: CommitmentScheme<C2>,
|
||||||
|
> {
|
||||||
|
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||||
|
pub ccs: CCS<C1::ScalarField>,
|
||||||
|
pub cf_r1cs: R1CS<C2::ScalarField>,
|
||||||
|
pub cs_params: CS1::ProverParams,
|
||||||
|
pub cf_cs_params: CS2::ProverParams,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements HyperNova+CycleFold's IVC, described in
|
||||||
|
/// [HyperNova](https://eprint.iacr.org/2023/573.pdf) and
|
||||||
|
/// [CycleFold](https://eprint.iacr.org/2023/1192.pdf), following the FoldingScheme trait
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct HyperNova<C1, GC1, C2, GC2, FC, CS1, CS2>
|
||||||
|
where
|
||||||
|
C1: CurveGroup,
|
||||||
|
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
|
||||||
|
C2: CurveGroup,
|
||||||
|
GC2: CurveVar<C2, CF2<C2>>,
|
||||||
|
FC: FCircuit<C1::ScalarField>,
|
||||||
|
CS1: CommitmentScheme<C1>,
|
||||||
|
CS2: CommitmentScheme<C2>,
|
||||||
|
{
|
||||||
|
_gc1: PhantomData<GC1>,
|
||||||
|
_c2: PhantomData<C2>,
|
||||||
|
_gc2: PhantomData<GC2>,
|
||||||
|
|
||||||
|
/// CCS of the Augmented Function circuit
|
||||||
|
pub ccs: CCS<C1::ScalarField>,
|
||||||
|
/// R1CS of the CycleFold circuit
|
||||||
|
pub cf_r1cs: R1CS<C2::ScalarField>,
|
||||||
|
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||||
|
/// CommitmentScheme::ProverParams over C1
|
||||||
|
pub cs_params: CS1::ProverParams,
|
||||||
|
/// CycleFold CommitmentScheme::ProverParams, over C2
|
||||||
|
pub cf_cs_params: CS2::ProverParams,
|
||||||
|
/// F circuit, the circuit that is being folded
|
||||||
|
pub F: FC,
|
||||||
|
pub i: C1::ScalarField,
|
||||||
|
/// initial state
|
||||||
|
pub z_0: Vec<C1::ScalarField>,
|
||||||
|
/// current i-th state
|
||||||
|
pub z_i: Vec<C1::ScalarField>,
|
||||||
|
/// HyperNova instances
|
||||||
|
pub W_i: Witness<C1::ScalarField>,
|
||||||
|
pub U_i: LCCCS<C1>,
|
||||||
|
pub w_i: Witness<C1::ScalarField>,
|
||||||
|
pub u_i: CCCS<C1>,
|
||||||
|
|
||||||
|
/// CycleFold running instance
|
||||||
|
pub cf_W_i: NovaWitness<C2>,
|
||||||
|
pub cf_U_i: CommittedInstance<C2>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C1, GC1, C2, GC2, FC, CS1, CS2> FoldingScheme<C1, C2, FC>
|
||||||
|
for HyperNova<C1, GC1, C2, GC2, FC, CS1, CS2>
|
||||||
|
where
|
||||||
|
C1: CurveGroup,
|
||||||
|
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
|
||||||
|
C2: CurveGroup,
|
||||||
|
GC2: CurveVar<C2, CF2<C2>> + ToConstraintFieldGadget<CF2<C2>>,
|
||||||
|
FC: FCircuit<C1::ScalarField>,
|
||||||
|
CS1: CommitmentScheme<C1>,
|
||||||
|
CS2: CommitmentScheme<C2>,
|
||||||
|
<C1 as CurveGroup>::BaseField: PrimeField,
|
||||||
|
<C2 as CurveGroup>::BaseField: PrimeField,
|
||||||
|
<C1 as Group>::ScalarField: Absorb,
|
||||||
|
<C2 as Group>::ScalarField: Absorb,
|
||||||
|
C1: CurveGroup<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
|
||||||
|
for<'a> &'a GC1: GroupOpsBounds<'a, C1, GC1>,
|
||||||
|
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
|
||||||
|
{
|
||||||
|
type PreprocessorParam = PreprocessorParam<C1, C2, FC, CS1, CS2>;
|
||||||
|
type ProverParam = ProverParams<C1, C2, CS1, CS2>;
|
||||||
|
type VerifierParam = VerifierParams<C1, C2, CS1, CS2>;
|
||||||
|
type RunningInstance = (LCCCS<C1>, Witness<C1::ScalarField>);
|
||||||
|
type IncomingInstance = (CCCS<C1>, Witness<C1::ScalarField>);
|
||||||
|
type CFInstance = (CommittedInstance<C2>, NovaWitness<C2>);
|
||||||
|
|
||||||
|
fn preprocess(
|
||||||
|
mut rng: impl RngCore,
|
||||||
|
prep_param: &Self::PreprocessorParam,
|
||||||
|
) -> Result<(Self::ProverParam, Self::VerifierParam), Error> {
|
||||||
|
let augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC>::empty(
|
||||||
|
&prep_param.poseidon_config,
|
||||||
|
prep_param.F.clone(),
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
let ccs = augmented_f_circuit.ccs.clone();
|
||||||
|
|
||||||
|
let cf_circuit = CycleFoldCircuit::<C1, GC1>::empty();
|
||||||
|
let cf_r1cs = get_r1cs_from_cs::<C2::ScalarField>(cf_circuit)?;
|
||||||
|
|
||||||
|
// if cs_params & cf_cs_params exist, use them, if not, generate new ones
|
||||||
|
let cs_params: CS1::ProverParams;
|
||||||
|
let cf_cs_params: CS2::ProverParams;
|
||||||
|
if prep_param.cs_params.is_some() && prep_param.cf_cs_params.is_some() {
|
||||||
|
cs_params = prep_param.clone().cs_params.unwrap();
|
||||||
|
cf_cs_params = prep_param.clone().cf_cs_params.unwrap();
|
||||||
|
} else {
|
||||||
|
(cs_params, _) = CS1::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||||
|
(cf_cs_params, _) = CS2::setup(&mut rng, cf_r1cs.A.n_cols - cf_r1cs.l - 1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let pp = ProverParams::<C1, C2, CS1, CS2> {
|
||||||
|
poseidon_config: prep_param.poseidon_config.clone(),
|
||||||
|
cs_params: cs_params.clone(),
|
||||||
|
cf_cs_params: cf_cs_params.clone(),
|
||||||
|
ccs: Some(ccs.clone()),
|
||||||
|
};
|
||||||
|
let vp = VerifierParams::<C1, C2, CS1, CS2> {
|
||||||
|
poseidon_config: prep_param.poseidon_config.clone(),
|
||||||
|
ccs,
|
||||||
|
cf_r1cs,
|
||||||
|
cs_params: cs_params.clone(),
|
||||||
|
cf_cs_params: cf_cs_params.clone(),
|
||||||
|
};
|
||||||
|
Ok((pp, vp))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initializes the HyperNova+CycleFold's IVC for the given parameters and initial state `z_0`.
|
||||||
|
fn init(pp: &Self::ProverParam, F: FC, z_0: Vec<C1::ScalarField>) -> Result<Self, Error> {
|
||||||
|
// prepare the HyperNova's AugmentedFCircuit and CycleFold's circuits and obtain its CCS
|
||||||
|
// and R1CS respectively
|
||||||
|
let augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC>::empty(
|
||||||
|
&pp.poseidon_config,
|
||||||
|
F.clone(),
|
||||||
|
pp.ccs.clone(),
|
||||||
|
)?;
|
||||||
|
let ccs = augmented_f_circuit.ccs.clone();
|
||||||
|
|
||||||
|
let cf_circuit = CycleFoldCircuit::<C1, GC1>::empty();
|
||||||
|
let cf_r1cs = get_r1cs_from_cs::<C2::ScalarField>(cf_circuit)?;
|
||||||
|
|
||||||
|
// setup the dummy instances
|
||||||
|
let W_dummy = Witness::<C1::ScalarField>::dummy(&ccs);
|
||||||
|
let U_dummy = LCCCS::<C1>::dummy(ccs.l, ccs.t, ccs.s);
|
||||||
|
let w_dummy = W_dummy.clone();
|
||||||
|
let mut u_dummy = CCCS::<C1>::dummy(ccs.l);
|
||||||
|
let (cf_W_dummy, cf_U_dummy): (NovaWitness<C2>, CommittedInstance<C2>) =
|
||||||
|
cf_r1cs.dummy_instance();
|
||||||
|
u_dummy.x = vec![
|
||||||
|
U_dummy.hash(
|
||||||
|
&pp.poseidon_config,
|
||||||
|
C1::ScalarField::zero(),
|
||||||
|
z_0.clone(),
|
||||||
|
z_0.clone(),
|
||||||
|
)?,
|
||||||
|
cf_U_dummy.hash_cyclefold(&pp.poseidon_config)?,
|
||||||
|
];
|
||||||
|
|
||||||
|
// W_dummy=W_0 is a 'dummy witness', all zeroes, but with the size corresponding to the
|
||||||
|
// R1CS that we're working with.
|
||||||
|
Ok(Self {
|
||||||
|
_gc1: PhantomData,
|
||||||
|
_c2: PhantomData,
|
||||||
|
_gc2: PhantomData,
|
||||||
|
ccs,
|
||||||
|
cf_r1cs,
|
||||||
|
poseidon_config: pp.poseidon_config.clone(),
|
||||||
|
cs_params: pp.cs_params.clone(),
|
||||||
|
cf_cs_params: pp.cf_cs_params.clone(),
|
||||||
|
F,
|
||||||
|
i: C1::ScalarField::zero(),
|
||||||
|
z_0: z_0.clone(),
|
||||||
|
z_i: z_0,
|
||||||
|
W_i: W_dummy,
|
||||||
|
U_i: U_dummy,
|
||||||
|
w_i: w_dummy,
|
||||||
|
u_i: u_dummy,
|
||||||
|
// cyclefold running instance
|
||||||
|
cf_W_i: cf_W_dummy,
|
||||||
|
cf_U_i: cf_U_dummy,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements IVC.P of HyperNova+CycleFold
|
||||||
|
fn prove_step(
|
||||||
|
&mut self,
|
||||||
|
mut rng: impl RngCore,
|
||||||
|
external_inputs: Vec<C1::ScalarField>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let augmented_f_circuit: AugmentedFCircuit<C1, C2, GC2, FC>;
|
||||||
|
|
||||||
|
if self.z_i.len() != self.F.state_len() {
|
||||||
|
return Err(Error::NotSameLength(
|
||||||
|
"z_i.len()".to_string(),
|
||||||
|
self.z_i.len(),
|
||||||
|
"F.state_len()".to_string(),
|
||||||
|
self.F.state_len(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if external_inputs.len() != self.F.external_inputs_len() {
|
||||||
|
return Err(Error::NotSameLength(
|
||||||
|
"F.external_inputs_len()".to_string(),
|
||||||
|
self.F.external_inputs_len(),
|
||||||
|
"external_inputs.len()".to_string(),
|
||||||
|
external_inputs.len(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.i > C1::ScalarField::from_le_bytes_mod_order(&usize::MAX.to_le_bytes()) {
|
||||||
|
return Err(Error::MaxStep);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut i_bytes: [u8; 8] = [0; 8];
|
||||||
|
i_bytes.copy_from_slice(&self.i.into_bigint().to_bytes_le()[..8]);
|
||||||
|
let i_usize: usize = usize::from_le_bytes(i_bytes);
|
||||||
|
|
||||||
|
let z_i1 = self
|
||||||
|
.F
|
||||||
|
.step_native(i_usize, self.z_i.clone(), external_inputs.clone())?;
|
||||||
|
|
||||||
|
// u_{i+1}.x[1] = H(cf_U_{i+1})
|
||||||
|
let cf_u_i1_x: C1::ScalarField;
|
||||||
|
let (U_i1, W_i1);
|
||||||
|
|
||||||
|
if self.i == C1::ScalarField::zero() {
|
||||||
|
W_i1 = Witness::<C1::ScalarField>::dummy(&self.ccs);
|
||||||
|
U_i1 = LCCCS::dummy(self.ccs.l, self.ccs.t, self.ccs.s);
|
||||||
|
|
||||||
|
let u_i1_x = U_i1.hash(
|
||||||
|
&self.poseidon_config,
|
||||||
|
C1::ScalarField::one(),
|
||||||
|
self.z_0.clone(),
|
||||||
|
z_i1.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// hash the initial (dummy) CycleFold instance, which is used as the 2nd public
|
||||||
|
// input in the AugmentedFCircuit
|
||||||
|
cf_u_i1_x = self.cf_U_i.hash_cyclefold(&self.poseidon_config)?;
|
||||||
|
|
||||||
|
augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC> {
|
||||||
|
_c2: PhantomData,
|
||||||
|
_gc2: PhantomData,
|
||||||
|
poseidon_config: self.poseidon_config.clone(),
|
||||||
|
ccs: self.ccs.clone(),
|
||||||
|
i: Some(C1::ScalarField::zero()),
|
||||||
|
i_usize: Some(0),
|
||||||
|
z_0: Some(self.z_0.clone()),
|
||||||
|
z_i: Some(self.z_i.clone()),
|
||||||
|
external_inputs: Some(external_inputs.clone()),
|
||||||
|
u_i_C: Some(self.u_i.C),
|
||||||
|
U_i: Some(self.U_i.clone()),
|
||||||
|
U_i1_C: Some(U_i1.C),
|
||||||
|
F: self.F.clone(),
|
||||||
|
x: Some(u_i1_x),
|
||||||
|
nimfs_proof: None,
|
||||||
|
|
||||||
|
// cyclefold values
|
||||||
|
cf_u_i_cmW: None,
|
||||||
|
cf_U_i: None,
|
||||||
|
cf_x: Some(cf_u_i1_x),
|
||||||
|
cf_cmT: None,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
let mut transcript_p: PoseidonTranscript<C1> =
|
||||||
|
PoseidonTranscript::<C1>::new(&self.poseidon_config);
|
||||||
|
let (rho_bits, nimfs_proof);
|
||||||
|
(nimfs_proof, U_i1, W_i1, rho_bits) = NIMFS::<C1, PoseidonTranscript<C1>>::prove(
|
||||||
|
&mut transcript_p,
|
||||||
|
&self.ccs,
|
||||||
|
&[self.U_i.clone()],
|
||||||
|
&[self.u_i.clone()],
|
||||||
|
&[self.W_i.clone()],
|
||||||
|
&[self.w_i.clone()],
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// sanity check: check the folded instance relation
|
||||||
|
#[cfg(test)]
|
||||||
|
U_i1.check_relation(&self.ccs, &W_i1)?;
|
||||||
|
|
||||||
|
let u_i1_x = U_i1.hash(
|
||||||
|
&self.poseidon_config,
|
||||||
|
self.i + C1::ScalarField::one(),
|
||||||
|
self.z_0.clone(),
|
||||||
|
z_i1.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let rho_Fq = C2::ScalarField::from_bigint(BigInteger::from_bits_le(&rho_bits))
|
||||||
|
.ok_or(Error::OutOfBounds)?;
|
||||||
|
// CycleFold part:
|
||||||
|
// get the vector used as public inputs 'x' in the CycleFold circuit
|
||||||
|
// cyclefold circuit for cmW
|
||||||
|
let cf_u_i_x = [
|
||||||
|
vec![rho_Fq],
|
||||||
|
get_cm_coordinates(&self.U_i.C),
|
||||||
|
get_cm_coordinates(&self.u_i.C),
|
||||||
|
get_cm_coordinates(&U_i1.C),
|
||||||
|
]
|
||||||
|
.concat();
|
||||||
|
|
||||||
|
let cf_circuit = CycleFoldCircuit::<C1, GC1> {
|
||||||
|
_gc: PhantomData,
|
||||||
|
r_bits: Some(rho_bits.clone()),
|
||||||
|
p1: Some(self.U_i.clone().C),
|
||||||
|
p2: Some(self.u_i.clone().C),
|
||||||
|
x: Some(cf_u_i_x.clone()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let (_cf_w_i, cf_u_i, cf_W_i1, cf_U_i1, cf_cmT, _) =
|
||||||
|
fold_cyclefold_circuit::<C1, GC1, C2, GC2, FC, CS1, CS2>(
|
||||||
|
&self.poseidon_config,
|
||||||
|
self.cf_r1cs.clone(),
|
||||||
|
self.cf_cs_params.clone(),
|
||||||
|
self.cf_W_i.clone(), // CycleFold running instance witness
|
||||||
|
self.cf_U_i.clone(), // CycleFold running instance
|
||||||
|
cf_u_i_x,
|
||||||
|
cf_circuit,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
cf_u_i1_x = cf_U_i1.hash_cyclefold(&self.poseidon_config)?;
|
||||||
|
|
||||||
|
augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC> {
|
||||||
|
_c2: PhantomData,
|
||||||
|
_gc2: PhantomData,
|
||||||
|
poseidon_config: self.poseidon_config.clone(),
|
||||||
|
ccs: self.ccs.clone(),
|
||||||
|
i: Some(self.i),
|
||||||
|
i_usize: Some(i_usize),
|
||||||
|
z_0: Some(self.z_0.clone()),
|
||||||
|
z_i: Some(self.z_i.clone()),
|
||||||
|
external_inputs: Some(external_inputs),
|
||||||
|
u_i_C: Some(self.u_i.C),
|
||||||
|
U_i: Some(self.U_i.clone()),
|
||||||
|
U_i1_C: Some(U_i1.C),
|
||||||
|
F: self.F.clone(),
|
||||||
|
x: Some(u_i1_x),
|
||||||
|
nimfs_proof: Some(nimfs_proof),
|
||||||
|
|
||||||
|
// cyclefold values
|
||||||
|
cf_u_i_cmW: Some(cf_u_i.cmW),
|
||||||
|
cf_U_i: Some(self.cf_U_i.clone()),
|
||||||
|
cf_x: Some(cf_u_i1_x),
|
||||||
|
cf_cmT: Some(cf_cmT),
|
||||||
|
};
|
||||||
|
|
||||||
|
// assign the next round instances
|
||||||
|
self.cf_W_i = cf_W_i1;
|
||||||
|
self.cf_U_i = cf_U_i1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (cs, _) = augmented_f_circuit.compute_cs_ccs()?;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
assert!(cs.is_satisfied()?);
|
||||||
|
|
||||||
|
let (r1cs_w_i1, r1cs_x_i1) = extract_w_x::<C1::ScalarField>(&cs); // includes 1 and public inputs
|
||||||
|
|
||||||
|
let r1cs_z = [
|
||||||
|
vec![C1::ScalarField::one()],
|
||||||
|
r1cs_x_i1.clone(),
|
||||||
|
r1cs_w_i1.clone(),
|
||||||
|
]
|
||||||
|
.concat();
|
||||||
|
// compute committed instances, w_{i+1}, u_{i+1}, which will be used as w_i, u_i, so we
|
||||||
|
// assign them directly to w_i, u_i.
|
||||||
|
let (u_i, w_i) = self
|
||||||
|
.ccs
|
||||||
|
.to_cccs::<_, C1, CS1>(&mut rng, &self.cs_params, &r1cs_z)?;
|
||||||
|
self.u_i = u_i.clone();
|
||||||
|
self.w_i = w_i.clone();
|
||||||
|
|
||||||
|
// set values for next iteration
|
||||||
|
self.i += C1::ScalarField::one();
|
||||||
|
// assign z_{i+1} into z_i
|
||||||
|
self.z_i = z_i1.clone();
|
||||||
|
self.U_i = U_i1.clone();
|
||||||
|
self.W_i = W_i1.clone();
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
{
|
||||||
|
// check the new LCCCS instance relation
|
||||||
|
self.U_i.check_relation(&self.ccs, &self.W_i)?;
|
||||||
|
// check the new CCCS instance relation
|
||||||
|
self.u_i.check_relation(&self.ccs, &self.w_i)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state(&self) -> Vec<C1::ScalarField> {
|
||||||
|
self.z_i.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instances(
|
||||||
|
&self,
|
||||||
|
) -> (
|
||||||
|
Self::RunningInstance,
|
||||||
|
Self::IncomingInstance,
|
||||||
|
Self::CFInstance,
|
||||||
|
) {
|
||||||
|
(
|
||||||
|
(self.U_i.clone(), self.W_i.clone()),
|
||||||
|
(self.u_i.clone(), self.w_i.clone()),
|
||||||
|
(self.cf_U_i.clone(), self.cf_W_i.clone()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements IVC.V of HyperNova+CycleFold. Notice that this method does not include the
|
||||||
|
/// commitments verification, which is done in the Decider.
|
||||||
|
fn verify(
|
||||||
|
vp: Self::VerifierParam,
|
||||||
|
z_0: Vec<C1::ScalarField>, // initial state
|
||||||
|
z_i: Vec<C1::ScalarField>, // last state
|
||||||
|
num_steps: C1::ScalarField,
|
||||||
|
running_instance: Self::RunningInstance,
|
||||||
|
incoming_instance: Self::IncomingInstance,
|
||||||
|
cyclefold_instance: Self::CFInstance,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if num_steps == C1::ScalarField::zero() {
|
||||||
|
if z_0 != z_i {
|
||||||
|
return Err(Error::IVCVerificationFail);
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let (U_i, W_i) = running_instance;
|
||||||
|
let (u_i, w_i) = incoming_instance;
|
||||||
|
let (cf_U_i, cf_W_i) = cyclefold_instance;
|
||||||
|
if u_i.x.len() != 2 || U_i.x.len() != 2 {
|
||||||
|
return Err(Error::IVCVerificationFail);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that u_i's output points to the running instance
|
||||||
|
// u_i.X[0] == H(i, z_0, z_i, U_i)
|
||||||
|
let expected_u_i_x = U_i.hash(&vp.poseidon_config, num_steps, z_0, z_i.clone())?;
|
||||||
|
if expected_u_i_x != u_i.x[0] {
|
||||||
|
return Err(Error::IVCVerificationFail);
|
||||||
|
}
|
||||||
|
// u_i.X[1] == H(cf_U_i)
|
||||||
|
let expected_cf_u_i_x = cf_U_i.hash_cyclefold(&vp.poseidon_config)?;
|
||||||
|
if expected_cf_u_i_x != u_i.x[1] {
|
||||||
|
return Err(Error::IVCVerificationFail);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check LCCCS satisfiability
|
||||||
|
U_i.check_relation(&vp.ccs, &W_i)?;
|
||||||
|
// check CCCS satisfiability
|
||||||
|
u_i.check_relation(&vp.ccs, &w_i)?;
|
||||||
|
|
||||||
|
// check CycleFold's RelaxedR1CS satisfiability
|
||||||
|
vp.cf_r1cs
|
||||||
|
.check_relaxed_instance_relation(&cf_W_i, &cf_U_i)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::commitment::kzg::KZG;
|
||||||
|
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
|
||||||
|
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::commitment::pedersen::Pedersen;
|
||||||
|
use crate::frontend::tests::CubicFCircuit;
|
||||||
|
use crate::transcript::poseidon::poseidon_canonical_config;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_ivc() {
|
||||||
|
let poseidon_config = poseidon_canonical_config::<Fr>();
|
||||||
|
|
||||||
|
let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
|
||||||
|
|
||||||
|
// run the test using Pedersen commitments on both sides of the curve cycle
|
||||||
|
test_ivc_opt::<Pedersen<Projective>, Pedersen<Projective2>>(
|
||||||
|
poseidon_config.clone(),
|
||||||
|
F_circuit,
|
||||||
|
);
|
||||||
|
// run the test using KZG for the commitments on the main curve, and Pedersen for the
|
||||||
|
// commitments on the secondary curve
|
||||||
|
test_ivc_opt::<KZG<Bn254>, Pedersen<Projective2>>(poseidon_config, F_circuit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// test_ivc allowing to choose the CommitmentSchemes
|
||||||
|
fn test_ivc_opt<CS1: CommitmentScheme<Projective>, CS2: CommitmentScheme<Projective2>>(
|
||||||
|
poseidon_config: PoseidonConfig<Fr>,
|
||||||
|
F_circuit: CubicFCircuit<Fr>,
|
||||||
|
) {
|
||||||
|
let mut rng = ark_std::test_rng();
|
||||||
|
|
||||||
|
type HN<CS1, CS2> =
|
||||||
|
HyperNova<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2>;
|
||||||
|
|
||||||
|
let prep_param = PreprocessorParam::<Projective, Projective2, CubicFCircuit<Fr>, CS1, CS2> {
|
||||||
|
poseidon_config,
|
||||||
|
F: F_circuit,
|
||||||
|
cs_params: None,
|
||||||
|
cf_cs_params: None,
|
||||||
|
};
|
||||||
|
let (prover_params, verifier_params) = HN::preprocess(&mut rng, &prep_param).unwrap();
|
||||||
|
|
||||||
|
let z_0 = vec![Fr::from(3_u32)];
|
||||||
|
let mut hypernova = HN::init(&prover_params, F_circuit, z_0.clone()).unwrap();
|
||||||
|
|
||||||
|
let num_steps: usize = 3;
|
||||||
|
for _ in 0..num_steps {
|
||||||
|
hypernova.prove_step(&mut rng, vec![]).unwrap();
|
||||||
|
}
|
||||||
|
assert_eq!(Fr::from(num_steps as u32), hypernova.i);
|
||||||
|
|
||||||
|
let (running_instance, incoming_instance, cyclefold_instance) = hypernova.instances();
|
||||||
|
HN::verify(
|
||||||
|
verifier_params,
|
||||||
|
z_0,
|
||||||
|
hypernova.z_i,
|
||||||
|
hypernova.i,
|
||||||
|
running_instance,
|
||||||
|
incoming_instance,
|
||||||
|
cyclefold_instance,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,19 +32,21 @@ pub struct NIMFSProof<C: CurveGroup> {
|
|||||||
|
|
||||||
impl<C: CurveGroup> NIMFSProof<C> {
|
impl<C: CurveGroup> NIMFSProof<C> {
|
||||||
pub fn dummy(ccs: &CCS<C::ScalarField>, mu: usize, nu: usize) -> Self {
|
pub fn dummy(ccs: &CCS<C::ScalarField>, mu: usize, nu: usize) -> Self {
|
||||||
|
// use 'C::ScalarField::one()' instead of 'zero()' to enforce the NIMFSProof to have the
|
||||||
|
// same in-circuit representation to match the number of constraints of an actual proof.
|
||||||
NIMFSProof::<C> {
|
NIMFSProof::<C> {
|
||||||
sc_proof: SumCheckProof::<C::ScalarField> {
|
sc_proof: SumCheckProof::<C::ScalarField> {
|
||||||
point: vec![C::ScalarField::zero(); ccs.d],
|
point: vec![C::ScalarField::one(); ccs.s],
|
||||||
proofs: vec![
|
proofs: vec![
|
||||||
IOPProverMessage {
|
IOPProverMessage {
|
||||||
coeffs: vec![C::ScalarField::zero(); ccs.t + 1]
|
coeffs: vec![C::ScalarField::one(); ccs.t + 1]
|
||||||
};
|
};
|
||||||
ccs.s
|
ccs.s
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
sigmas_thetas: SigmasThetas(
|
sigmas_thetas: SigmasThetas(
|
||||||
vec![vec![C::ScalarField::zero(); ccs.t]; mu],
|
vec![vec![C::ScalarField::one(); ccs.t]; mu],
|
||||||
vec![vec![C::ScalarField::zero(); ccs.t]; nu],
|
vec![vec![C::ScalarField::one(); ccs.t]; nu],
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -432,11 +434,15 @@ pub mod tests {
|
|||||||
let (pedersen_params, _) =
|
let (pedersen_params, _) =
|
||||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||||
|
|
||||||
let (lcccs, w1) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1).unwrap();
|
let (lcccs, w1) = ccs
|
||||||
let (cccs, w2) = ccs.to_cccs(&mut rng, &pedersen_params, &z2).unwrap();
|
.to_lcccs::<_, Projective, Pedersen<Projective>>(&mut rng, &pedersen_params, &z1)
|
||||||
|
.unwrap();
|
||||||
|
let (cccs, w2) = ccs
|
||||||
|
.to_cccs::<_, Projective, Pedersen<Projective>>(&mut rng, &pedersen_params, &z2)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
lcccs.check_relation(&pedersen_params, &ccs, &w1).unwrap();
|
lcccs.check_relation(&ccs, &w1).unwrap();
|
||||||
cccs.check_relation(&pedersen_params, &ccs, &w2).unwrap();
|
cccs.check_relation(&ccs, &w2).unwrap();
|
||||||
|
|
||||||
let mut rng = test_rng();
|
let mut rng = test_rng();
|
||||||
let rho = Fr::rand(&mut rng);
|
let rho = Fr::rand(&mut rng);
|
||||||
@@ -453,9 +459,7 @@ pub mod tests {
|
|||||||
NIMFS::<Projective, PoseidonTranscript<Projective>>::fold_witness(&[w1], &[w2], rho);
|
NIMFS::<Projective, PoseidonTranscript<Projective>>::fold_witness(&[w1], &[w2], rho);
|
||||||
|
|
||||||
// check lcccs relation
|
// check lcccs relation
|
||||||
folded
|
folded.check_relation(&ccs, &w_folded).unwrap();
|
||||||
.check_relation(&pedersen_params, &ccs, &w_folded)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform multifolding of an LCCCS instance with a CCCS instance (as described in the paper)
|
/// Perform multifolding of an LCCCS instance with a CCCS instance (as described in the paper)
|
||||||
@@ -474,9 +478,13 @@ pub mod tests {
|
|||||||
let z_2 = get_test_z(4);
|
let z_2 = get_test_z(4);
|
||||||
|
|
||||||
// Create the LCCCS instance out of z_1
|
// Create the LCCCS instance out of z_1
|
||||||
let (running_instance, w1) = ccs.to_lcccs(&mut rng, &pedersen_params, &z_1).unwrap();
|
let (running_instance, w1) = ccs
|
||||||
|
.to_lcccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, &z_1)
|
||||||
|
.unwrap();
|
||||||
// Create the CCCS instance out of z_2
|
// Create the CCCS instance out of z_2
|
||||||
let (new_instance, w2) = ccs.to_cccs(&mut rng, &pedersen_params, &z_2).unwrap();
|
let (new_instance, w2) = ccs
|
||||||
|
.to_cccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, &z_2)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Prover's transcript
|
// Prover's transcript
|
||||||
let poseidon_config = poseidon_canonical_config::<Fr>();
|
let poseidon_config = poseidon_canonical_config::<Fr>();
|
||||||
@@ -513,9 +521,7 @@ pub mod tests {
|
|||||||
assert_eq!(folded_lcccs, folded_lcccs_v);
|
assert_eq!(folded_lcccs, folded_lcccs_v);
|
||||||
|
|
||||||
// Check that the folded LCCCS instance is a valid instance with respect to the folded witness
|
// Check that the folded LCCCS instance is a valid instance with respect to the folded witness
|
||||||
folded_lcccs
|
folded_lcccs.check_relation(&ccs, &folded_witness).unwrap();
|
||||||
.check_relation(&pedersen_params, &ccs, &folded_witness)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform multiple steps of multifolding of an LCCCS instance with a CCCS instance
|
/// Perform multiple steps of multifolding of an LCCCS instance with a CCCS instance
|
||||||
@@ -530,8 +536,9 @@ pub mod tests {
|
|||||||
|
|
||||||
// LCCCS witness
|
// LCCCS witness
|
||||||
let z_1 = get_test_z(2);
|
let z_1 = get_test_z(2);
|
||||||
let (mut running_instance, mut w1) =
|
let (mut running_instance, mut w1) = ccs
|
||||||
ccs.to_lcccs(&mut rng, &pedersen_params, &z_1).unwrap();
|
.to_lcccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, &z_1)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let poseidon_config = poseidon_canonical_config::<Fr>();
|
let poseidon_config = poseidon_canonical_config::<Fr>();
|
||||||
|
|
||||||
@@ -548,7 +555,9 @@ pub mod tests {
|
|||||||
// CCS witness
|
// CCS witness
|
||||||
let z_2 = get_test_z(i);
|
let z_2 = get_test_z(i);
|
||||||
|
|
||||||
let (new_instance, w2) = ccs.to_cccs(&mut rng, &pedersen_params, &z_2).unwrap();
|
let (new_instance, w2) = ccs
|
||||||
|
.to_cccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, &z_2)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// run the prover side of the multifolding
|
// run the prover side of the multifolding
|
||||||
let (proof, folded_lcccs, folded_witness, _) =
|
let (proof, folded_lcccs, folded_witness, _) =
|
||||||
@@ -574,9 +583,7 @@ pub mod tests {
|
|||||||
assert_eq!(folded_lcccs, folded_lcccs_v);
|
assert_eq!(folded_lcccs, folded_lcccs_v);
|
||||||
|
|
||||||
// check that the folded instance with the folded witness holds the LCCCS relation
|
// check that the folded instance with the folded witness holds the LCCCS relation
|
||||||
folded_lcccs
|
folded_lcccs.check_relation(&ccs, &folded_witness).unwrap();
|
||||||
.check_relation(&pedersen_params, &ccs, &folded_witness)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
running_instance = folded_lcccs;
|
running_instance = folded_lcccs;
|
||||||
w1 = folded_witness;
|
w1 = folded_witness;
|
||||||
@@ -612,7 +619,9 @@ pub mod tests {
|
|||||||
let mut lcccs_instances = Vec::new();
|
let mut lcccs_instances = Vec::new();
|
||||||
let mut w_lcccs = Vec::new();
|
let mut w_lcccs = Vec::new();
|
||||||
for z_i in z_lcccs.iter() {
|
for z_i in z_lcccs.iter() {
|
||||||
let (running_instance, w) = ccs.to_lcccs(&mut rng, &pedersen_params, z_i).unwrap();
|
let (running_instance, w) = ccs
|
||||||
|
.to_lcccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, z_i)
|
||||||
|
.unwrap();
|
||||||
lcccs_instances.push(running_instance);
|
lcccs_instances.push(running_instance);
|
||||||
w_lcccs.push(w);
|
w_lcccs.push(w);
|
||||||
}
|
}
|
||||||
@@ -620,7 +629,9 @@ pub mod tests {
|
|||||||
let mut cccs_instances = Vec::new();
|
let mut cccs_instances = Vec::new();
|
||||||
let mut w_cccs = Vec::new();
|
let mut w_cccs = Vec::new();
|
||||||
for z_i in z_cccs.iter() {
|
for z_i in z_cccs.iter() {
|
||||||
let (new_instance, w) = ccs.to_cccs(&mut rng, &pedersen_params, z_i).unwrap();
|
let (new_instance, w) = ccs
|
||||||
|
.to_cccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, z_i)
|
||||||
|
.unwrap();
|
||||||
cccs_instances.push(new_instance);
|
cccs_instances.push(new_instance);
|
||||||
w_cccs.push(w);
|
w_cccs.push(w);
|
||||||
}
|
}
|
||||||
@@ -660,9 +671,7 @@ pub mod tests {
|
|||||||
assert_eq!(folded_lcccs, folded_lcccs_v);
|
assert_eq!(folded_lcccs, folded_lcccs_v);
|
||||||
|
|
||||||
// Check that the folded LCCCS instance is a valid instance with respect to the folded witness
|
// Check that the folded LCCCS instance is a valid instance with respect to the folded witness
|
||||||
folded_lcccs
|
folded_lcccs.check_relation(&ccs, &folded_witness).unwrap();
|
||||||
.check_relation(&pedersen_params, &ccs, &folded_witness)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test that generates mu>1 and nu>1 instances, and folds them in a single multifolding step
|
/// Test that generates mu>1 and nu>1 instances, and folds them in a single multifolding step
|
||||||
@@ -710,7 +719,9 @@ pub mod tests {
|
|||||||
let mut lcccs_instances = Vec::new();
|
let mut lcccs_instances = Vec::new();
|
||||||
let mut w_lcccs = Vec::new();
|
let mut w_lcccs = Vec::new();
|
||||||
for z_i in z_lcccs.iter() {
|
for z_i in z_lcccs.iter() {
|
||||||
let (running_instance, w) = ccs.to_lcccs(&mut rng, &pedersen_params, z_i).unwrap();
|
let (running_instance, w) = ccs
|
||||||
|
.to_lcccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, z_i)
|
||||||
|
.unwrap();
|
||||||
lcccs_instances.push(running_instance);
|
lcccs_instances.push(running_instance);
|
||||||
w_lcccs.push(w);
|
w_lcccs.push(w);
|
||||||
}
|
}
|
||||||
@@ -718,7 +729,9 @@ pub mod tests {
|
|||||||
let mut cccs_instances = Vec::new();
|
let mut cccs_instances = Vec::new();
|
||||||
let mut w_cccs = Vec::new();
|
let mut w_cccs = Vec::new();
|
||||||
for z_i in z_cccs.iter() {
|
for z_i in z_cccs.iter() {
|
||||||
let (new_instance, w) = ccs.to_cccs(&mut rng, &pedersen_params, z_i).unwrap();
|
let (new_instance, w) = ccs
|
||||||
|
.to_cccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, z_i)
|
||||||
|
.unwrap();
|
||||||
cccs_instances.push(new_instance);
|
cccs_instances.push(new_instance);
|
||||||
w_cccs.push(w);
|
w_cccs.push(w);
|
||||||
}
|
}
|
||||||
@@ -748,9 +761,7 @@ pub mod tests {
|
|||||||
assert_eq!(folded_lcccs, folded_lcccs_v);
|
assert_eq!(folded_lcccs, folded_lcccs_v);
|
||||||
|
|
||||||
// Check that the folded LCCCS instance is a valid instance with respect to the folded witness
|
// Check that the folded LCCCS instance is a valid instance with respect to the folded witness
|
||||||
folded_lcccs
|
folded_lcccs.check_relation(&ccs, &folded_witness).unwrap();
|
||||||
.check_relation(&pedersen_params, &ccs, &folded_witness)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -239,7 +239,9 @@ pub mod tests {
|
|||||||
// Initialize a multifolding object
|
// Initialize a multifolding object
|
||||||
let (pedersen_params, _) =
|
let (pedersen_params, _) =
|
||||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||||
let (lcccs_instance, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1).unwrap();
|
let (lcccs_instance, _) = ccs
|
||||||
|
.to_lcccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, &z1)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let sigmas_thetas =
|
let sigmas_thetas =
|
||||||
compute_sigmas_thetas(&ccs, &[z1.clone()], &[z2.clone()], &r_x_prime).unwrap();
|
compute_sigmas_thetas(&ccs, &[z1.clone()], &[z2.clone()], &r_x_prime).unwrap();
|
||||||
@@ -287,7 +289,9 @@ pub mod tests {
|
|||||||
// Initialize a multifolding object
|
// Initialize a multifolding object
|
||||||
let (pedersen_params, _) =
|
let (pedersen_params, _) =
|
||||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||||
let (lcccs_instance, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1).unwrap();
|
let (lcccs_instance, _) = ccs
|
||||||
|
.to_lcccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, &z1)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Compute g(x) with that r_x
|
// Compute g(x) with that r_x
|
||||||
let g = compute_g::<Projective>(
|
let g = compute_g::<Projective>(
|
||||||
|
|||||||
@@ -62,12 +62,13 @@ where
|
|||||||
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
|
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
|
||||||
GC2: CurveVar<C2, CF2<C2>> + ToConstraintFieldGadget<CF2<C2>>,
|
GC2: CurveVar<C2, CF2<C2>> + ToConstraintFieldGadget<CF2<C2>>,
|
||||||
FC: FCircuit<C1::ScalarField>,
|
FC: FCircuit<C1::ScalarField>,
|
||||||
|
// CS1 is a KZG commitment, where challenge is C1::Fr elem
|
||||||
CS1: CommitmentScheme<
|
CS1: CommitmentScheme<
|
||||||
C1,
|
C1,
|
||||||
ProverChallenge = C1::ScalarField,
|
ProverChallenge = C1::ScalarField,
|
||||||
Challenge = C1::ScalarField,
|
Challenge = C1::ScalarField,
|
||||||
Proof = KZGProof<C1>,
|
Proof = KZGProof<C1>,
|
||||||
>, // KZG commitment, where challenge is C1::Fr elem
|
>,
|
||||||
// enforce that the CS2 is Pedersen commitment scheme, since we're at Ethereum's EVM decider
|
// enforce that the CS2 is Pedersen commitment scheme, since we're at Ethereum's EVM decider
|
||||||
CS2: CommitmentScheme<C2, ProverParams = PedersenParams<C2>>,
|
CS2: CommitmentScheme<C2, ProverParams = PedersenParams<C2>>,
|
||||||
S: SNARK<C1::ScalarField>,
|
S: SNARK<C1::ScalarField>,
|
||||||
@@ -77,20 +78,52 @@ where
|
|||||||
<C1 as Group>::ScalarField: Absorb,
|
<C1 as Group>::ScalarField: Absorb,
|
||||||
<C2 as Group>::ScalarField: Absorb,
|
<C2 as Group>::ScalarField: Absorb,
|
||||||
C1: CurveGroup<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
|
C1: CurveGroup<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
|
||||||
|
for<'b> &'b GC1: GroupOpsBounds<'b, C1, GC1>,
|
||||||
for<'b> &'b GC2: GroupOpsBounds<'b, C2, GC2>,
|
for<'b> &'b GC2: GroupOpsBounds<'b, C2, GC2>,
|
||||||
// constrain FS into Nova, since this is a Decider specifically for Nova
|
// constrain FS into Nova, since this is a Decider specifically for Nova
|
||||||
Nova<C1, GC1, C2, GC2, FC, CS1, CS2>: From<FS>,
|
Nova<C1, GC1, C2, GC2, FC, CS1, CS2>: From<FS>,
|
||||||
|
crate::folding::nova::ProverParams<C1, C2, CS1, CS2>:
|
||||||
|
From<<FS as FoldingScheme<C1, C2, FC>>::ProverParam>,
|
||||||
|
crate::folding::nova::VerifierParams<C1, C2, CS1, CS2>:
|
||||||
|
From<<FS as FoldingScheme<C1, C2, FC>>::VerifierParam>,
|
||||||
{
|
{
|
||||||
|
type PreprocessorParam = (FS::ProverParam, FS::VerifierParam);
|
||||||
type ProverParam = (S::ProvingKey, CS1::ProverParams);
|
type ProverParam = (S::ProvingKey, CS1::ProverParams);
|
||||||
type Proof = Proof<C1, CS1, S>;
|
type Proof = Proof<C1, CS1, S>;
|
||||||
type VerifierParam = (S::VerifyingKey, CS1::VerifierParams);
|
type VerifierParam = (S::VerifyingKey, CS1::VerifierParams);
|
||||||
type PublicInput = Vec<C1::ScalarField>;
|
type PublicInput = Vec<C1::ScalarField>;
|
||||||
type CommittedInstanceWithWitness = ();
|
|
||||||
type CommittedInstance = CommittedInstance<C1>;
|
type CommittedInstance = CommittedInstance<C1>;
|
||||||
|
|
||||||
fn prove(
|
fn preprocess(
|
||||||
pp: Self::ProverParam,
|
|
||||||
mut rng: impl RngCore + CryptoRng,
|
mut rng: impl RngCore + CryptoRng,
|
||||||
|
prep_param: &Self::PreprocessorParam,
|
||||||
|
fs: FS,
|
||||||
|
) -> Result<(Self::ProverParam, Self::VerifierParam), Error> {
|
||||||
|
let circuit =
|
||||||
|
DeciderEthCircuit::<C1, GC1, C2, GC2, CS1, CS2>::from_nova::<FC>(fs.into()).unwrap();
|
||||||
|
|
||||||
|
// get the Groth16 specific setup for the circuit
|
||||||
|
let (g16_pk, g16_vk) = S::circuit_specific_setup(circuit, &mut rng).unwrap();
|
||||||
|
|
||||||
|
// get the FoldingScheme prover & verifier params from Nova
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
let nova_pp:
|
||||||
|
<Nova<C1, GC1, C2, GC2, FC, CS1, CS2> as FoldingScheme<C1, C2, FC>>::ProverParam =
|
||||||
|
prep_param.0.clone().into()
|
||||||
|
;
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
let nova_vp:
|
||||||
|
<Nova<C1, GC1, C2, GC2, FC, CS1, CS2> as FoldingScheme<C1, C2, FC>>::VerifierParam =
|
||||||
|
prep_param.1.clone().into();
|
||||||
|
|
||||||
|
let pp = (g16_pk, nova_pp.cs_pp);
|
||||||
|
let vp = (g16_vk, nova_vp.cs_vp);
|
||||||
|
Ok((pp, vp))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prove(
|
||||||
|
mut rng: impl RngCore + CryptoRng,
|
||||||
|
pp: Self::ProverParam,
|
||||||
folding_scheme: FS,
|
folding_scheme: FS,
|
||||||
) -> Result<Self::Proof, Error> {
|
) -> Result<Self::Proof, Error> {
|
||||||
let (snark_pk, cs_pk): (S::ProvingKey, CS1::ProverParams) = pp;
|
let (snark_pk, cs_pk): (S::ProvingKey, CS1::ProverParams) = pp;
|
||||||
@@ -281,13 +314,13 @@ fn point2_to_eth_format(p: ark_bn254::G2Affine) -> Result<Vec<u8>, Error> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
|
||||||
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
|
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
|
||||||
use ark_groth16::Groth16;
|
use ark_groth16::Groth16;
|
||||||
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
||||||
use ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey;
|
use ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
use crate::commitment::kzg::{ProverKey as KZGProverKey, KZG};
|
use crate::commitment::kzg::{ProverKey as KZGProverKey, KZG};
|
||||||
use crate::commitment::pedersen::Pedersen;
|
use crate::commitment::pedersen::Pedersen;
|
||||||
use crate::folding::nova::{get_cs_params_len, ProverParams};
|
use crate::folding::nova::{get_cs_params_len, ProverParams};
|
||||||
@@ -297,7 +330,7 @@ pub mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_decider() {
|
fn test_decider() {
|
||||||
// use Nova as FoldingScheme
|
// use Nova as FoldingScheme
|
||||||
type NOVA = Nova<
|
type N = Nova<
|
||||||
Projective,
|
Projective,
|
||||||
GVar,
|
GVar,
|
||||||
Projective2,
|
Projective2,
|
||||||
@@ -306,7 +339,7 @@ pub mod tests {
|
|||||||
KZG<'static, Bn254>,
|
KZG<'static, Bn254>,
|
||||||
Pedersen<Projective2>,
|
Pedersen<Projective2>,
|
||||||
>;
|
>;
|
||||||
type DECIDER = Decider<
|
type D = Decider<
|
||||||
Projective,
|
Projective,
|
||||||
GVar,
|
GVar,
|
||||||
Projective2,
|
Projective2,
|
||||||
@@ -315,7 +348,7 @@ pub mod tests {
|
|||||||
KZG<'static, Bn254>,
|
KZG<'static, Bn254>,
|
||||||
Pedersen<Projective2>,
|
Pedersen<Projective2>,
|
||||||
Groth16<Bn254>, // here we define the Snark to use in the decider
|
Groth16<Bn254>, // here we define the Snark to use in the decider
|
||||||
NOVA, // here we define the FoldingScheme to use
|
N, // here we define the FoldingScheme to use
|
||||||
>;
|
>;
|
||||||
|
|
||||||
let mut rng = ark_std::test_rng();
|
let mut rng = ark_std::test_rng();
|
||||||
@@ -339,17 +372,17 @@ pub mod tests {
|
|||||||
let prover_params =
|
let prover_params =
|
||||||
ProverParams::<Projective, Projective2, KZG<Bn254>, Pedersen<Projective2>> {
|
ProverParams::<Projective, Projective2, KZG<Bn254>, Pedersen<Projective2>> {
|
||||||
poseidon_config: poseidon_config.clone(),
|
poseidon_config: poseidon_config.clone(),
|
||||||
cs_params: kzg_pk.clone(),
|
cs_pp: kzg_pk.clone(),
|
||||||
cf_cs_params: cf_pedersen_params,
|
cf_cs_pp: cf_pedersen_params,
|
||||||
};
|
};
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let mut nova = NOVA::init(&prover_params, F_circuit, z_0.clone()).unwrap();
|
let mut nova = N::init(&prover_params, F_circuit, z_0.clone()).unwrap();
|
||||||
println!("Nova initialized, {:?}", start.elapsed());
|
println!("Nova initialized, {:?}", start.elapsed());
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
nova.prove_step(vec![]).unwrap();
|
nova.prove_step(&mut rng, vec![]).unwrap();
|
||||||
println!("prove_step, {:?}", start.elapsed());
|
println!("prove_step, {:?}", start.elapsed());
|
||||||
nova.prove_step(vec![]).unwrap(); // do a 2nd step
|
nova.prove_step(&mut rng, vec![]).unwrap(); // do a 2nd step
|
||||||
|
|
||||||
// generate Groth16 setup
|
// generate Groth16 setup
|
||||||
let circuit = DeciderEthCircuit::<
|
let circuit = DeciderEthCircuit::<
|
||||||
@@ -371,13 +404,13 @@ pub mod tests {
|
|||||||
// decider proof generation
|
// decider proof generation
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let decider_pp = (g16_pk, kzg_pk);
|
let decider_pp = (g16_pk, kzg_pk);
|
||||||
let proof = DECIDER::prove(decider_pp, rng, nova.clone()).unwrap();
|
let proof = D::prove(rng, decider_pp, nova.clone()).unwrap();
|
||||||
println!("Decider prove, {:?}", start.elapsed());
|
println!("Decider prove, {:?}", start.elapsed());
|
||||||
|
|
||||||
// decider proof verification
|
// decider proof verification
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let decider_vp = (g16_vk, kzg_vk);
|
let decider_vp = (g16_vk, kzg_vk);
|
||||||
let verified = DECIDER::verify(
|
let verified = D::verify(
|
||||||
decider_vp, nova.i, nova.z_0, nova.z_i, &nova.U_i, &nova.u_i, &proof,
|
decider_vp, nova.i, nova.z_0, nova.z_i, &nova.U_i, &nova.u_i, &proof,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ where
|
|||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
// compute the U_{i+1}, W_{i+1}
|
// compute the U_{i+1}, W_{i+1}
|
||||||
let (T, cmT) = NIFS::<C1, CS1>::compute_cmT(
|
let (T, cmT) = NIFS::<C1, CS1>::compute_cmT(
|
||||||
&nova.cs_params,
|
&nova.cs_pp,
|
||||||
&nova.r1cs.clone(),
|
&nova.r1cs.clone(),
|
||||||
&nova.w_i.clone(),
|
&nova.w_i.clone(),
|
||||||
&nova.u_i.clone(),
|
&nova.u_i.clone(),
|
||||||
@@ -315,7 +315,7 @@ where
|
|||||||
cf_E_len: nova.cf_W_i.E.len(),
|
cf_E_len: nova.cf_W_i.E.len(),
|
||||||
r1cs: nova.r1cs,
|
r1cs: nova.r1cs,
|
||||||
cf_r1cs: nova.cf_r1cs,
|
cf_r1cs: nova.cf_r1cs,
|
||||||
cf_pedersen_params: nova.cf_cs_params,
|
cf_pedersen_params: nova.cf_cs_pp,
|
||||||
poseidon_config: nova.poseidon_config,
|
poseidon_config: nova.poseidon_config,
|
||||||
i: Some(nova.i),
|
i: Some(nova.i),
|
||||||
z_0: Some(nova.z_0),
|
z_0: Some(nova.z_0),
|
||||||
@@ -438,7 +438,7 @@ where
|
|||||||
// imports here instead of at the top of the file, so we avoid having multiple
|
// imports here instead of at the top of the file, so we avoid having multiple
|
||||||
// `#[cfg(not(test))]`
|
// `#[cfg(not(test))]`
|
||||||
use crate::commitment::pedersen::PedersenGadget;
|
use crate::commitment::pedersen::PedersenGadget;
|
||||||
use crate::folding::nova::cyclefold::{CycleFoldCommittedInstanceVar, CF_IO_LEN};
|
use crate::folding::circuits::cyclefold::{CycleFoldCommittedInstanceVar, CF_IO_LEN};
|
||||||
use ark_r1cs_std::ToBitsGadget;
|
use ark_r1cs_std::ToBitsGadget;
|
||||||
|
|
||||||
let cf_u_dummy_native = CommittedInstance::<C2>::dummy(CF_IO_LEN);
|
let cf_u_dummy_native = CommittedInstance::<C2>::dummy(CF_IO_LEN);
|
||||||
@@ -597,7 +597,6 @@ where
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
|
||||||
use ark_crypto_primitives::crh::{
|
use ark_crypto_primitives::crh::{
|
||||||
sha256::{
|
sha256::{
|
||||||
constraints::{Sha256Gadget, UnitVar},
|
constraints::{Sha256Gadget, UnitVar},
|
||||||
@@ -611,15 +610,15 @@ pub mod tests {
|
|||||||
use ark_std::{One, UniformRand};
|
use ark_std::{One, UniformRand};
|
||||||
use ark_vesta::{constraints::GVar as GVar2, Projective as Projective2};
|
use ark_vesta::{constraints::GVar as GVar2, Projective as Projective2};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::ccs::r1cs::tests::{get_test_r1cs, get_test_z};
|
||||||
|
use crate::ccs::r1cs::{extract_r1cs, extract_w_x};
|
||||||
use crate::commitment::pedersen::Pedersen;
|
use crate::commitment::pedersen::Pedersen;
|
||||||
use crate::folding::nova::{get_cs_params_len, ProverParams, VerifierParams};
|
use crate::folding::nova::{get_cs_params_len, ProverParams, VerifierParams};
|
||||||
use crate::frontend::tests::{CubicFCircuit, CustomFCircuit, WrapperCircuit};
|
use crate::frontend::tests::{CubicFCircuit, CustomFCircuit, WrapperCircuit};
|
||||||
use crate::transcript::poseidon::poseidon_canonical_config;
|
use crate::transcript::poseidon::poseidon_canonical_config;
|
||||||
use crate::FoldingScheme;
|
use crate::FoldingScheme;
|
||||||
|
|
||||||
use crate::ccs::r1cs::tests::{get_test_r1cs, get_test_z};
|
|
||||||
use crate::ccs::r1cs::{extract_r1cs, extract_w_x};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_relaxed_r1cs_small_gadget_handcrafted() {
|
fn test_relaxed_r1cs_small_gadget_handcrafted() {
|
||||||
let r1cs: R1CS<Fr> = get_test_r1cs();
|
let r1cs: R1CS<Fr> = get_test_r1cs();
|
||||||
@@ -786,11 +785,11 @@ pub mod tests {
|
|||||||
let prover_params =
|
let prover_params =
|
||||||
ProverParams::<Projective, Projective2, Pedersen<Projective>, Pedersen<Projective2>> {
|
ProverParams::<Projective, Projective2, Pedersen<Projective>, Pedersen<Projective2>> {
|
||||||
poseidon_config: poseidon_config.clone(),
|
poseidon_config: poseidon_config.clone(),
|
||||||
cs_params: pedersen_params,
|
cs_pp: pedersen_params.clone(),
|
||||||
cf_cs_params: cf_pedersen_params,
|
cf_cs_pp: cf_pedersen_params.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
type NOVA = Nova<
|
type N = Nova<
|
||||||
Projective,
|
Projective,
|
||||||
GVar,
|
GVar,
|
||||||
Projective2,
|
Projective2,
|
||||||
@@ -801,16 +800,23 @@ pub mod tests {
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
// generate a Nova instance and do a step of it
|
// generate a Nova instance and do a step of it
|
||||||
let mut nova = NOVA::init(&prover_params, F_circuit, z_0.clone()).unwrap();
|
let mut nova = N::init(&prover_params, F_circuit, z_0.clone()).unwrap();
|
||||||
nova.prove_step(vec![]).unwrap();
|
nova.prove_step(&mut rng, vec![]).unwrap();
|
||||||
let ivc_v = nova.clone();
|
let ivc_v = nova.clone();
|
||||||
let verifier_params = VerifierParams::<Projective, Projective2> {
|
let verifier_params = VerifierParams::<
|
||||||
|
Projective,
|
||||||
|
Projective2,
|
||||||
|
Pedersen<Projective>,
|
||||||
|
Pedersen<Projective2>,
|
||||||
|
> {
|
||||||
poseidon_config: poseidon_config.clone(),
|
poseidon_config: poseidon_config.clone(),
|
||||||
r1cs: ivc_v.clone().r1cs,
|
r1cs: ivc_v.clone().r1cs,
|
||||||
cf_r1cs: ivc_v.clone().cf_r1cs,
|
cf_r1cs: ivc_v.clone().cf_r1cs,
|
||||||
|
cs_vp: pedersen_params,
|
||||||
|
cf_cs_vp: cf_pedersen_params,
|
||||||
};
|
};
|
||||||
let (running_instance, incoming_instance, cyclefold_instance) = ivc_v.instances();
|
let (running_instance, incoming_instance, cyclefold_instance) = ivc_v.instances();
|
||||||
NOVA::verify(
|
N::verify(
|
||||||
verifier_params,
|
verifier_params,
|
||||||
z_0,
|
z_0,
|
||||||
ivc_v.z_i,
|
ivc_v.z_i,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldG
|
|||||||
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem};
|
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem};
|
||||||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
||||||
use ark_std::fmt::Debug;
|
use ark_std::fmt::Debug;
|
||||||
|
use ark_std::rand::RngCore;
|
||||||
use ark_std::{One, Zero};
|
use ark_std::{One, Zero};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use std::usize;
|
use std::usize;
|
||||||
@@ -24,7 +25,7 @@ use crate::folding::circuits::{
|
|||||||
CF2,
|
CF2,
|
||||||
};
|
};
|
||||||
use crate::frontend::FCircuit;
|
use crate::frontend::FCircuit;
|
||||||
use crate::utils::vec::is_zero_vec;
|
use crate::utils::{get_cm_coordinates, vec::is_zero_vec};
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use crate::FoldingScheme;
|
use crate::FoldingScheme;
|
||||||
|
|
||||||
@@ -186,6 +187,44 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct PreprocessorParam<C1, C2, FC, CS1, CS2>
|
||||||
|
where
|
||||||
|
C1: CurveGroup,
|
||||||
|
C2: CurveGroup,
|
||||||
|
FC: FCircuit<C1::ScalarField>,
|
||||||
|
CS1: CommitmentScheme<C1>,
|
||||||
|
CS2: CommitmentScheme<C2>,
|
||||||
|
{
|
||||||
|
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||||
|
pub F: FC,
|
||||||
|
// cs params if not provided, will be generated at the preprocess method
|
||||||
|
pub cs_pp: Option<CS1::ProverParams>,
|
||||||
|
pub cs_vp: Option<CS1::VerifierParams>,
|
||||||
|
pub cf_cs_pp: Option<CS2::ProverParams>,
|
||||||
|
pub cf_cs_vp: Option<CS2::VerifierParams>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C1, C2, FC, CS1, CS2> PreprocessorParam<C1, C2, FC, CS1, CS2>
|
||||||
|
where
|
||||||
|
C1: CurveGroup,
|
||||||
|
C2: CurveGroup,
|
||||||
|
FC: FCircuit<C1::ScalarField>,
|
||||||
|
CS1: CommitmentScheme<C1>,
|
||||||
|
CS2: CommitmentScheme<C2>,
|
||||||
|
{
|
||||||
|
pub fn new(poseidon_config: PoseidonConfig<C1::ScalarField>, F: FC) -> Self {
|
||||||
|
Self {
|
||||||
|
poseidon_config,
|
||||||
|
F,
|
||||||
|
cs_pp: None,
|
||||||
|
cs_vp: None,
|
||||||
|
cf_cs_pp: None,
|
||||||
|
cf_cs_vp: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ProverParams<C1, C2, CS1, CS2>
|
pub struct ProverParams<C1, C2, CS1, CS2>
|
||||||
where
|
where
|
||||||
@@ -195,15 +234,23 @@ where
|
|||||||
CS2: CommitmentScheme<C2>,
|
CS2: CommitmentScheme<C2>,
|
||||||
{
|
{
|
||||||
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||||
pub cs_params: CS1::ProverParams,
|
pub cs_pp: CS1::ProverParams,
|
||||||
pub cf_cs_params: CS2::ProverParams,
|
pub cf_cs_pp: CS2::ProverParams,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct VerifierParams<C1: CurveGroup, C2: CurveGroup> {
|
pub struct VerifierParams<C1, C2, CS1, CS2>
|
||||||
|
where
|
||||||
|
C1: CurveGroup,
|
||||||
|
C2: CurveGroup,
|
||||||
|
CS1: CommitmentScheme<C1>,
|
||||||
|
CS2: CommitmentScheme<C2>,
|
||||||
|
{
|
||||||
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||||
pub r1cs: R1CS<C1::ScalarField>,
|
pub r1cs: R1CS<C1::ScalarField>,
|
||||||
pub cf_r1cs: R1CS<C2::ScalarField>,
|
pub cf_r1cs: R1CS<C2::ScalarField>,
|
||||||
|
pub cs_vp: CS1::VerifierParams,
|
||||||
|
pub cf_cs_vp: CS2::VerifierParams,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements Nova+CycleFold's IVC, described in [Nova](https://eprint.iacr.org/2021/370.pdf) and
|
/// Implements Nova+CycleFold's IVC, described in [Nova](https://eprint.iacr.org/2021/370.pdf) and
|
||||||
@@ -228,9 +275,9 @@ where
|
|||||||
pub cf_r1cs: R1CS<C2::ScalarField>,
|
pub cf_r1cs: R1CS<C2::ScalarField>,
|
||||||
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||||
/// CommitmentScheme::ProverParams over C1
|
/// CommitmentScheme::ProverParams over C1
|
||||||
pub cs_params: CS1::ProverParams,
|
pub cs_pp: CS1::ProverParams,
|
||||||
/// CycleFold CommitmentScheme::ProverParams, over C2
|
/// CycleFold CommitmentScheme::ProverParams, over C2
|
||||||
pub cf_cs_params: CS2::ProverParams,
|
pub cf_cs_pp: CS2::ProverParams,
|
||||||
/// F circuit, the circuit that is being folded
|
/// F circuit, the circuit that is being folded
|
||||||
pub F: FC,
|
pub F: FC,
|
||||||
pub i: C1::ScalarField,
|
pub i: C1::ScalarField,
|
||||||
@@ -267,24 +314,50 @@ where
|
|||||||
for<'a> &'a GC1: GroupOpsBounds<'a, C1, GC1>,
|
for<'a> &'a GC1: GroupOpsBounds<'a, C1, GC1>,
|
||||||
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
|
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
|
||||||
{
|
{
|
||||||
type PreprocessorParam = (Self::ProverParam, FC);
|
type PreprocessorParam = PreprocessorParam<C1, C2, FC, CS1, CS2>;
|
||||||
type ProverParam = ProverParams<C1, C2, CS1, CS2>;
|
type ProverParam = ProverParams<C1, C2, CS1, CS2>;
|
||||||
type VerifierParam = VerifierParams<C1, C2>;
|
type VerifierParam = VerifierParams<C1, C2, CS1, CS2>;
|
||||||
type CommittedInstanceWithWitness = (CommittedInstance<C1>, Witness<C1>);
|
type RunningInstance = (CommittedInstance<C1>, Witness<C1>);
|
||||||
type CFCommittedInstanceWithWitness = (CommittedInstance<C2>, Witness<C2>);
|
type IncomingInstance = (CommittedInstance<C1>, Witness<C1>);
|
||||||
|
type CFInstance = (CommittedInstance<C2>, Witness<C2>);
|
||||||
|
|
||||||
fn preprocess(
|
fn preprocess(
|
||||||
|
mut rng: impl RngCore,
|
||||||
prep_param: &Self::PreprocessorParam,
|
prep_param: &Self::PreprocessorParam,
|
||||||
) -> Result<(Self::ProverParam, Self::VerifierParam), Error> {
|
) -> Result<(Self::ProverParam, Self::VerifierParam), Error> {
|
||||||
let (prover_params, F_circuit) = prep_param;
|
|
||||||
|
|
||||||
let (r1cs, cf_r1cs) =
|
let (r1cs, cf_r1cs) =
|
||||||
get_r1cs::<C1, GC1, C2, GC2, FC>(&prover_params.poseidon_config, F_circuit.clone())?;
|
get_r1cs::<C1, GC1, C2, GC2, FC>(&prep_param.poseidon_config, prep_param.F.clone())?;
|
||||||
|
|
||||||
let verifier_params = VerifierParams::<C1, C2> {
|
// if cs params exist, use them, if not, generate new ones
|
||||||
poseidon_config: prover_params.poseidon_config.clone(),
|
let cs_pp: CS1::ProverParams;
|
||||||
|
let cs_vp: CS1::VerifierParams;
|
||||||
|
let cf_cs_pp: CS2::ProverParams;
|
||||||
|
let cf_cs_vp: CS2::VerifierParams;
|
||||||
|
if prep_param.cs_pp.is_some()
|
||||||
|
&& prep_param.cf_cs_pp.is_some()
|
||||||
|
&& prep_param.cs_vp.is_some()
|
||||||
|
&& prep_param.cf_cs_vp.is_some()
|
||||||
|
{
|
||||||
|
cs_pp = prep_param.clone().cs_pp.unwrap();
|
||||||
|
cs_vp = prep_param.clone().cs_vp.unwrap();
|
||||||
|
cf_cs_pp = prep_param.clone().cf_cs_pp.unwrap();
|
||||||
|
cf_cs_vp = prep_param.clone().cf_cs_vp.unwrap();
|
||||||
|
} else {
|
||||||
|
(cs_pp, cs_vp) = CS1::setup(&mut rng, r1cs.A.n_rows).unwrap();
|
||||||
|
(cf_cs_pp, cf_cs_vp) = CS2::setup(&mut rng, cf_r1cs.A.n_rows).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let prover_params = ProverParams::<C1, C2, CS1, CS2> {
|
||||||
|
poseidon_config: prep_param.poseidon_config.clone(),
|
||||||
|
cs_pp: cs_pp.clone(),
|
||||||
|
cf_cs_pp: cf_cs_pp.clone(),
|
||||||
|
};
|
||||||
|
let verifier_params = VerifierParams::<C1, C2, CS1, CS2> {
|
||||||
|
poseidon_config: prep_param.poseidon_config.clone(),
|
||||||
r1cs,
|
r1cs,
|
||||||
cf_r1cs,
|
cf_r1cs,
|
||||||
|
cs_vp: cs_vp.clone(),
|
||||||
|
cf_cs_vp: cf_cs_vp.clone(),
|
||||||
};
|
};
|
||||||
Ok((prover_params.clone(), verifier_params))
|
Ok((prover_params.clone(), verifier_params))
|
||||||
}
|
}
|
||||||
@@ -322,8 +395,8 @@ where
|
|||||||
r1cs,
|
r1cs,
|
||||||
cf_r1cs,
|
cf_r1cs,
|
||||||
poseidon_config: pp.poseidon_config.clone(),
|
poseidon_config: pp.poseidon_config.clone(),
|
||||||
cs_params: pp.cs_params.clone(),
|
cs_pp: pp.cs_pp.clone(),
|
||||||
cf_cs_params: pp.cf_cs_params.clone(),
|
cf_cs_pp: pp.cf_cs_pp.clone(),
|
||||||
F,
|
F,
|
||||||
i: C1::ScalarField::zero(),
|
i: C1::ScalarField::zero(),
|
||||||
z_0: z_0.clone(),
|
z_0: z_0.clone(),
|
||||||
@@ -339,7 +412,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Implements IVC.P of Nova+CycleFold
|
/// Implements IVC.P of Nova+CycleFold
|
||||||
fn prove_step(&mut self, external_inputs: Vec<C1::ScalarField>) -> Result<(), Error> {
|
fn prove_step(
|
||||||
|
&mut self,
|
||||||
|
_rng: impl RngCore,
|
||||||
|
external_inputs: Vec<C1::ScalarField>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
let augmented_F_circuit: AugmentedFCircuit<C1, C2, GC2, FC>;
|
let augmented_F_circuit: AugmentedFCircuit<C1, C2, GC2, FC>;
|
||||||
|
|
||||||
if self.z_i.len() != self.F.state_len() {
|
if self.z_i.len() != self.F.state_len() {
|
||||||
@@ -535,7 +612,7 @@ where
|
|||||||
self.i += C1::ScalarField::one();
|
self.i += C1::ScalarField::one();
|
||||||
self.z_i = z_i1;
|
self.z_i = z_i1;
|
||||||
self.w_i = Witness::<C1>::new(w_i1, self.r1cs.A.n_rows);
|
self.w_i = Witness::<C1>::new(w_i1, self.r1cs.A.n_rows);
|
||||||
self.u_i = self.w_i.commit::<CS1>(&self.cs_params, x_i1)?;
|
self.u_i = self.w_i.commit::<CS1>(&self.cs_pp, x_i1)?;
|
||||||
self.W_i = W_i1;
|
self.W_i = W_i1;
|
||||||
self.U_i = U_i1;
|
self.U_i = U_i1;
|
||||||
|
|
||||||
@@ -552,12 +629,13 @@ where
|
|||||||
fn state(&self) -> Vec<C1::ScalarField> {
|
fn state(&self) -> Vec<C1::ScalarField> {
|
||||||
self.z_i.clone()
|
self.z_i.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn instances(
|
fn instances(
|
||||||
&self,
|
&self,
|
||||||
) -> (
|
) -> (
|
||||||
Self::CommittedInstanceWithWitness,
|
Self::RunningInstance,
|
||||||
Self::CommittedInstanceWithWitness,
|
Self::IncomingInstance,
|
||||||
Self::CFCommittedInstanceWithWitness,
|
Self::CFInstance,
|
||||||
) {
|
) {
|
||||||
(
|
(
|
||||||
(self.U_i.clone(), self.W_i.clone()),
|
(self.U_i.clone(), self.W_i.clone()),
|
||||||
@@ -566,16 +644,24 @@ where
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements IVC.V of Nova+CycleFold
|
/// Implements IVC.V of Nova+CycleFold. Notice that this method does not include the
|
||||||
|
/// commitments verification, which is done in the Decider.
|
||||||
fn verify(
|
fn verify(
|
||||||
vp: Self::VerifierParam,
|
vp: Self::VerifierParam,
|
||||||
z_0: Vec<C1::ScalarField>, // initial state
|
z_0: Vec<C1::ScalarField>, // initial state
|
||||||
z_i: Vec<C1::ScalarField>, // last state
|
z_i: Vec<C1::ScalarField>, // last state
|
||||||
num_steps: C1::ScalarField,
|
num_steps: C1::ScalarField,
|
||||||
running_instance: Self::CommittedInstanceWithWitness,
|
running_instance: Self::RunningInstance,
|
||||||
incoming_instance: Self::CommittedInstanceWithWitness,
|
incoming_instance: Self::IncomingInstance,
|
||||||
cyclefold_instance: Self::CFCommittedInstanceWithWitness,
|
cyclefold_instance: Self::CFInstance,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
if num_steps == C1::ScalarField::zero() {
|
||||||
|
if z_0 != z_i {
|
||||||
|
return Err(Error::IVCVerificationFail);
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let (U_i, W_i) = running_instance;
|
let (U_i, W_i) = running_instance;
|
||||||
let (u_i, w_i) = incoming_instance;
|
let (u_i, w_i) = incoming_instance;
|
||||||
let (cf_U_i, cf_W_i) = cyclefold_instance;
|
let (cf_U_i, cf_W_i) = cyclefold_instance;
|
||||||
@@ -631,7 +717,7 @@ where
|
|||||||
// computes T and cmT for the AugmentedFCircuit
|
// computes T and cmT for the AugmentedFCircuit
|
||||||
fn compute_cmT(&self) -> Result<(Vec<C1::ScalarField>, C1), Error> {
|
fn compute_cmT(&self) -> Result<(Vec<C1::ScalarField>, C1), Error> {
|
||||||
NIFS::<C1, CS1>::compute_cmT(
|
NIFS::<C1, CS1>::compute_cmT(
|
||||||
&self.cs_params,
|
&self.cs_pp,
|
||||||
&self.r1cs,
|
&self.r1cs,
|
||||||
&self.w_i,
|
&self.w_i,
|
||||||
&self.u_i,
|
&self.u_i,
|
||||||
@@ -680,7 +766,7 @@ where
|
|||||||
fold_cyclefold_circuit::<C1, GC1, C2, GC2, FC, CS1, CS2>(
|
fold_cyclefold_circuit::<C1, GC1, C2, GC2, FC, CS1, CS2>(
|
||||||
&self.poseidon_config,
|
&self.poseidon_config,
|
||||||
self.cf_r1cs.clone(),
|
self.cf_r1cs.clone(),
|
||||||
self.cf_cs_params.clone(),
|
self.cf_cs_pp.clone(),
|
||||||
cf_W_i,
|
cf_W_i,
|
||||||
cf_U_i,
|
cf_U_i,
|
||||||
cf_u_i_x,
|
cf_u_i_x,
|
||||||
@@ -753,23 +839,13 @@ where
|
|||||||
Ok((r1cs.A.n_rows, cf_r1cs.A.n_rows))
|
Ok((r1cs.A.n_rows, cf_r1cs.A.n_rows))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns the coordinates of a commitment point. This is compatible with the arkworks
|
|
||||||
/// GC.to_constraint_field()[..2]
|
|
||||||
pub(crate) fn get_cm_coordinates<C: CurveGroup>(cm: &C) -> Vec<C::BaseField> {
|
|
||||||
let zero = (&C::BaseField::zero(), &C::BaseField::zero());
|
|
||||||
let cm = cm.into_affine();
|
|
||||||
let (cm_x, cm_y) = cm.xy().unwrap_or(zero);
|
|
||||||
vec![*cm_x, *cm_y]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
use crate::commitment::kzg::KZG;
|
||||||
use crate::commitment::kzg::{ProverKey as KZGProverKey, KZG};
|
|
||||||
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
|
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
|
||||||
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
||||||
use ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey;
|
|
||||||
|
|
||||||
|
use super::*;
|
||||||
use crate::commitment::pedersen::Pedersen;
|
use crate::commitment::pedersen::Pedersen;
|
||||||
use crate::frontend::tests::CubicFCircuit;
|
use crate::frontend::tests::CubicFCircuit;
|
||||||
use crate::transcript::poseidon::poseidon_canonical_config;
|
use crate::transcript::poseidon::poseidon_canonical_config;
|
||||||
@@ -778,71 +854,49 @@ pub mod tests {
|
|||||||
/// AugmentedFCircuit
|
/// AugmentedFCircuit
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ivc() {
|
fn test_ivc() {
|
||||||
let mut rng = ark_std::test_rng();
|
|
||||||
let poseidon_config = poseidon_canonical_config::<Fr>();
|
let poseidon_config = poseidon_canonical_config::<Fr>();
|
||||||
|
|
||||||
let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
|
let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
|
||||||
|
|
||||||
let (cs_len, cf_cs_len) =
|
|
||||||
get_cs_params_len::<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>>(
|
|
||||||
&poseidon_config,
|
|
||||||
F_circuit,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let (kzg_pk, _): (KZGProverKey<Projective>, KZGVerifierKey<Bn254>) =
|
|
||||||
KZG::<Bn254>::setup(&mut rng, cs_len).unwrap();
|
|
||||||
let (pedersen_params, _) = Pedersen::<Projective>::setup(&mut rng, cs_len).unwrap();
|
|
||||||
let (cf_pedersen_params, _) = Pedersen::<Projective2>::setup(&mut rng, cf_cs_len).unwrap();
|
|
||||||
|
|
||||||
// run the test using Pedersen commitments on both sides of the curve cycle
|
// run the test using Pedersen commitments on both sides of the curve cycle
|
||||||
test_ivc_opt::<Pedersen<Projective>, Pedersen<Projective2>>(
|
test_ivc_opt::<Pedersen<Projective>, Pedersen<Projective2>>(
|
||||||
poseidon_config.clone(),
|
poseidon_config.clone(),
|
||||||
pedersen_params,
|
|
||||||
cf_pedersen_params.clone(),
|
|
||||||
F_circuit,
|
F_circuit,
|
||||||
);
|
);
|
||||||
// run the test using KZG for the commitments on the main curve, and Pedersen for the
|
// run the test using KZG for the commitments on the main curve, and Pedersen for the
|
||||||
// commitments on the secondary curve
|
// commitments on the secondary curve
|
||||||
test_ivc_opt::<KZG<Bn254>, Pedersen<Projective2>>(
|
test_ivc_opt::<KZG<Bn254>, Pedersen<Projective2>>(poseidon_config, F_circuit);
|
||||||
poseidon_config,
|
|
||||||
kzg_pk,
|
|
||||||
cf_pedersen_params,
|
|
||||||
F_circuit,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// test_ivc allowing to choose the CommitmentSchemes
|
// test_ivc allowing to choose the CommitmentSchemes
|
||||||
fn test_ivc_opt<CS1: CommitmentScheme<Projective>, CS2: CommitmentScheme<Projective2>>(
|
fn test_ivc_opt<CS1: CommitmentScheme<Projective>, CS2: CommitmentScheme<Projective2>>(
|
||||||
poseidon_config: PoseidonConfig<Fr>,
|
poseidon_config: PoseidonConfig<Fr>,
|
||||||
cs_params: CS1::ProverParams,
|
|
||||||
cf_cs_params: CS2::ProverParams,
|
|
||||||
F_circuit: CubicFCircuit<Fr>,
|
F_circuit: CubicFCircuit<Fr>,
|
||||||
) {
|
) {
|
||||||
type NOVA<CS1, CS2> =
|
let mut rng = ark_std::test_rng();
|
||||||
Nova<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2>;
|
type N<CS1, CS2> = Nova<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2>;
|
||||||
|
|
||||||
let prover_params = ProverParams::<Projective, Projective2, CS1, CS2> {
|
let prep_param = PreprocessorParam::<Projective, Projective2, CubicFCircuit<Fr>, CS1, CS2> {
|
||||||
poseidon_config: poseidon_config.clone(),
|
poseidon_config,
|
||||||
cs_params,
|
F: F_circuit,
|
||||||
cf_cs_params,
|
cs_pp: None,
|
||||||
|
cs_vp: None,
|
||||||
|
cf_cs_pp: None,
|
||||||
|
cf_cs_vp: None,
|
||||||
};
|
};
|
||||||
|
let (prover_params, verifier_params) = N::preprocess(&mut rng, &prep_param).unwrap();
|
||||||
|
|
||||||
let z_0 = vec![Fr::from(3_u32)];
|
let z_0 = vec![Fr::from(3_u32)];
|
||||||
let mut nova = NOVA::init(&prover_params, F_circuit, z_0.clone()).unwrap();
|
let mut nova = N::init(&prover_params, F_circuit, z_0.clone()).unwrap();
|
||||||
|
|
||||||
let num_steps: usize = 3;
|
let num_steps: usize = 3;
|
||||||
for _ in 0..num_steps {
|
for _ in 0..num_steps {
|
||||||
nova.prove_step(vec![]).unwrap();
|
nova.prove_step(&mut rng, vec![]).unwrap();
|
||||||
}
|
}
|
||||||
assert_eq!(Fr::from(num_steps as u32), nova.i);
|
assert_eq!(Fr::from(num_steps as u32), nova.i);
|
||||||
|
|
||||||
let verifier_params = VerifierParams::<Projective, Projective2> {
|
|
||||||
poseidon_config,
|
|
||||||
r1cs: nova.clone().r1cs,
|
|
||||||
cf_r1cs: nova.clone().cf_r1cs,
|
|
||||||
};
|
|
||||||
let (running_instance, incoming_instance, cyclefold_instance) = nova.instances();
|
let (running_instance, incoming_instance, cyclefold_instance) = nova.instances();
|
||||||
NOVA::<CS1, CS2>::verify(
|
N::<CS1, CS2>::verify(
|
||||||
verifier_params,
|
verifier_params,
|
||||||
z_0,
|
z_0,
|
||||||
nova.z_i,
|
nova.z_i,
|
||||||
|
|||||||
@@ -1,10 +1,3 @@
|
|||||||
use super::{circuits::AugmentedFCircuit, Nova, ProverParams};
|
|
||||||
pub use super::{CommittedInstance, Witness};
|
|
||||||
pub use crate::folding::circuits::{cyclefold::CycleFoldCircuit, CF2};
|
|
||||||
use crate::{
|
|
||||||
ccs::r1cs::extract_r1cs, commitment::CommitmentScheme, folding::circuits::CF1,
|
|
||||||
frontend::FCircuit,
|
|
||||||
};
|
|
||||||
use ark_crypto_primitives::sponge::{poseidon::PoseidonConfig, Absorb};
|
use ark_crypto_primitives::sponge::{poseidon::PoseidonConfig, Absorb};
|
||||||
use ark_ec::{CurveGroup, Group};
|
use ark_ec::{CurveGroup, Group};
|
||||||
use ark_ff::PrimeField;
|
use ark_ff::PrimeField;
|
||||||
@@ -17,6 +10,14 @@ use ark_relations::r1cs::ConstraintSystem;
|
|||||||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError, Write};
|
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError, Write};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use super::{circuits::AugmentedFCircuit, Nova, ProverParams};
|
||||||
|
use super::{CommittedInstance, Witness};
|
||||||
|
use crate::folding::circuits::{cyclefold::CycleFoldCircuit, CF2};
|
||||||
|
use crate::{
|
||||||
|
ccs::r1cs::extract_r1cs, commitment::CommitmentScheme, folding::circuits::CF1,
|
||||||
|
frontend::FCircuit,
|
||||||
|
};
|
||||||
|
|
||||||
impl<C1, GC1, C2, GC2, FC, CS1, CS2> CanonicalSerialize for Nova<C1, GC1, C2, GC2, FC, CS1, CS2>
|
impl<C1, GC1, C2, GC2, FC, CS1, CS2> CanonicalSerialize for Nova<C1, GC1, C2, GC2, FC, CS1, CS2>
|
||||||
where
|
where
|
||||||
C1: CurveGroup,
|
C1: CurveGroup,
|
||||||
@@ -150,8 +151,8 @@ where
|
|||||||
_gc1: PhantomData,
|
_gc1: PhantomData,
|
||||||
_c2: PhantomData,
|
_c2: PhantomData,
|
||||||
_gc2: PhantomData,
|
_gc2: PhantomData,
|
||||||
cs_params: prover_params.cs_params,
|
cs_pp: prover_params.cs_pp,
|
||||||
cf_cs_params: prover_params.cf_cs_params,
|
cf_cs_pp: prover_params.cf_cs_pp,
|
||||||
i,
|
i,
|
||||||
z_0,
|
z_0,
|
||||||
z_i,
|
z_i,
|
||||||
@@ -171,6 +172,12 @@ where
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
|
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
|
||||||
|
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
||||||
|
use ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey;
|
||||||
|
use ark_serialize::{CanonicalSerialize, Compress, Validate};
|
||||||
|
use std::{fs, io::Write};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commitment::{
|
commitment::{
|
||||||
kzg::{ProverKey as KZGProverKey, KZG},
|
kzg::{ProverKey as KZGProverKey, KZG},
|
||||||
@@ -182,11 +189,6 @@ pub mod tests {
|
|||||||
transcript::poseidon::poseidon_canonical_config,
|
transcript::poseidon::poseidon_canonical_config,
|
||||||
FoldingScheme,
|
FoldingScheme,
|
||||||
};
|
};
|
||||||
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
|
|
||||||
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
|
||||||
use ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey;
|
|
||||||
use ark_serialize::{CanonicalSerialize, Compress, Validate};
|
|
||||||
use std::{fs, io::Write};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serde_nova() {
|
fn test_serde_nova() {
|
||||||
@@ -204,21 +206,28 @@ pub mod tests {
|
|||||||
let (cf_pedersen_params, _) = Pedersen::<Projective2>::setup(&mut rng, cf_cs_len).unwrap();
|
let (cf_pedersen_params, _) = Pedersen::<Projective2>::setup(&mut rng, cf_cs_len).unwrap();
|
||||||
|
|
||||||
// Initialize nova and make multiple `prove_step()`
|
// Initialize nova and make multiple `prove_step()`
|
||||||
type NOVA<CS1, CS2> =
|
type N = Nova<
|
||||||
Nova<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2>;
|
Projective,
|
||||||
|
GVar,
|
||||||
|
Projective2,
|
||||||
|
GVar2,
|
||||||
|
CubicFCircuit<Fr>,
|
||||||
|
KZG<'static, Bn254>,
|
||||||
|
Pedersen<Projective2>,
|
||||||
|
>;
|
||||||
let prover_params =
|
let prover_params =
|
||||||
ProverParams::<Projective, Projective2, KZG<Bn254>, Pedersen<Projective2>> {
|
ProverParams::<Projective, Projective2, KZG<Bn254>, Pedersen<Projective2>> {
|
||||||
poseidon_config: poseidon_config.clone(),
|
poseidon_config: poseidon_config.clone(),
|
||||||
cs_params: kzg_pk.clone(),
|
cs_pp: kzg_pk.clone(),
|
||||||
cf_cs_params: cf_pedersen_params.clone(),
|
cf_cs_pp: cf_pedersen_params.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let z_0 = vec![Fr::from(3_u32)];
|
let z_0 = vec![Fr::from(3_u32)];
|
||||||
let mut nova = NOVA::init(&prover_params, F_circuit, z_0.clone()).unwrap();
|
let mut nova = N::init(&prover_params, F_circuit, z_0.clone()).unwrap();
|
||||||
|
|
||||||
let num_steps: usize = 3;
|
let num_steps: usize = 3;
|
||||||
for _ in 0..num_steps {
|
for _ in 0..num_steps {
|
||||||
nova.prove_step(vec![]).unwrap();
|
nova.prove_step(&mut rng, vec![]).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut writer = vec![];
|
let mut writer = vec![];
|
||||||
@@ -257,8 +266,8 @@ pub mod tests {
|
|||||||
|
|
||||||
let num_steps: usize = 3;
|
let num_steps: usize = 3;
|
||||||
for _ in 0..num_steps {
|
for _ in 0..num_steps {
|
||||||
deserialized_nova.prove_step(vec![]).unwrap();
|
deserialized_nova.prove_step(&mut rng, vec![]).unwrap();
|
||||||
nova.prove_step(vec![]).unwrap();
|
nova.prove_step(&mut rng, vec![]).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(deserialized_nova.w_i, nova.w_i);
|
assert_eq!(deserialized_nova.w_i, nova.w_i);
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ where
|
|||||||
(w_dummy, u_dummy)
|
(w_dummy, u_dummy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// notice that this method does not check the commitment correctness
|
||||||
fn check_instance_relation(
|
fn check_instance_relation(
|
||||||
&self,
|
&self,
|
||||||
W: &Witness<C>,
|
W: &Witness<C>,
|
||||||
@@ -52,6 +53,7 @@ where
|
|||||||
self.check_relation(&Z)
|
self.check_relation(&Z)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// notice that this method does not check the commitment correctness
|
||||||
fn check_relaxed_instance_relation(
|
fn check_relaxed_instance_relation(
|
||||||
&self,
|
&self,
|
||||||
W: &Witness<C>,
|
W: &Witness<C>,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
#![allow(non_upper_case_globals)]
|
#![allow(non_upper_case_globals)]
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
#![allow(clippy::upper_case_acronyms)]
|
|
||||||
|
|
||||||
use ark_ec::{pairing::Pairing, CurveGroup};
|
use ark_ec::{pairing::Pairing, CurveGroup};
|
||||||
use ark_ff::PrimeField;
|
use ark_ff::PrimeField;
|
||||||
@@ -110,13 +109,15 @@ where
|
|||||||
C2::BaseField: PrimeField,
|
C2::BaseField: PrimeField,
|
||||||
FC: FCircuit<C1::ScalarField>,
|
FC: FCircuit<C1::ScalarField>,
|
||||||
{
|
{
|
||||||
type PreprocessorParam: Debug;
|
type PreprocessorParam: Debug + Clone;
|
||||||
type ProverParam: Debug;
|
type ProverParam: Debug + Clone;
|
||||||
type VerifierParam: Debug;
|
type VerifierParam: Debug + Clone;
|
||||||
type CommittedInstanceWithWitness: Debug;
|
type RunningInstance: Debug; // contains the CommittedInstance + Witness
|
||||||
type CFCommittedInstanceWithWitness: Debug; // CycleFold CommittedInstance & Witness
|
type IncomingInstance: Debug; // contains the CommittedInstance + Witness
|
||||||
|
type CFInstance: Debug; // CycleFold CommittedInstance & Witness
|
||||||
|
|
||||||
fn preprocess(
|
fn preprocess(
|
||||||
|
rng: impl RngCore,
|
||||||
prep_param: &Self::PreprocessorParam,
|
prep_param: &Self::PreprocessorParam,
|
||||||
) -> Result<(Self::ProverParam, Self::VerifierParam), Error>;
|
) -> Result<(Self::ProverParam, Self::VerifierParam), Error>;
|
||||||
|
|
||||||
@@ -126,7 +127,11 @@ where
|
|||||||
z_0: Vec<C1::ScalarField>, // initial state
|
z_0: Vec<C1::ScalarField>, // initial state
|
||||||
) -> Result<Self, Error>;
|
) -> Result<Self, Error>;
|
||||||
|
|
||||||
fn prove_step(&mut self, external_inputs: Vec<C1::ScalarField>) -> Result<(), Error>;
|
fn prove_step(
|
||||||
|
&mut self,
|
||||||
|
rng: impl RngCore,
|
||||||
|
external_inputs: Vec<C1::ScalarField>,
|
||||||
|
) -> Result<(), Error>;
|
||||||
|
|
||||||
// returns the state at the current step
|
// returns the state at the current step
|
||||||
fn state(&self) -> Vec<C1::ScalarField>;
|
fn state(&self) -> Vec<C1::ScalarField>;
|
||||||
@@ -136,9 +141,9 @@ where
|
|||||||
fn instances(
|
fn instances(
|
||||||
&self,
|
&self,
|
||||||
) -> (
|
) -> (
|
||||||
Self::CommittedInstanceWithWitness,
|
Self::RunningInstance,
|
||||||
Self::CommittedInstanceWithWitness,
|
Self::IncomingInstance,
|
||||||
Self::CFCommittedInstanceWithWitness,
|
Self::CFInstance,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn verify(
|
fn verify(
|
||||||
@@ -147,9 +152,9 @@ where
|
|||||||
z_i: Vec<C1::ScalarField>, // last state
|
z_i: Vec<C1::ScalarField>, // last state
|
||||||
// number of steps between the initial state and the last state
|
// number of steps between the initial state and the last state
|
||||||
num_steps: C1::ScalarField,
|
num_steps: C1::ScalarField,
|
||||||
running_instance: Self::CommittedInstanceWithWitness,
|
running_instance: Self::RunningInstance,
|
||||||
incoming_instance: Self::CommittedInstanceWithWitness,
|
incoming_instance: Self::IncomingInstance,
|
||||||
cyclefold_instance: Self::CFCommittedInstanceWithWitness,
|
cyclefold_instance: Self::CFInstance,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,16 +167,22 @@ pub trait Decider<
|
|||||||
C1: CurveGroup<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
|
C1: CurveGroup<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
|
||||||
C2::BaseField: PrimeField,
|
C2::BaseField: PrimeField,
|
||||||
{
|
{
|
||||||
|
type PreprocessorParam: Debug;
|
||||||
type ProverParam: Clone;
|
type ProverParam: Clone;
|
||||||
type Proof;
|
type Proof;
|
||||||
type VerifierParam;
|
type VerifierParam;
|
||||||
type PublicInput: Debug;
|
type PublicInput: Debug;
|
||||||
type CommittedInstanceWithWitness: Debug;
|
|
||||||
type CommittedInstance: Clone + Debug;
|
type CommittedInstance: Clone + Debug;
|
||||||
|
|
||||||
fn prove(
|
fn preprocess(
|
||||||
pp: Self::ProverParam,
|
|
||||||
rng: impl RngCore + CryptoRng,
|
rng: impl RngCore + CryptoRng,
|
||||||
|
prep_param: &Self::PreprocessorParam,
|
||||||
|
fs: FS,
|
||||||
|
) -> Result<(Self::ProverParam, Self::VerifierParam), Error>;
|
||||||
|
|
||||||
|
fn prove(
|
||||||
|
rng: impl RngCore + CryptoRng,
|
||||||
|
pp: Self::ProverParam,
|
||||||
folding_scheme: FS,
|
folding_scheme: FS,
|
||||||
) -> Result<Self::Proof, Error>;
|
) -> Result<Self::Proof, Error>;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
use ark_ec::{AffineRepr, CurveGroup};
|
||||||
use ark_ff::PrimeField;
|
use ark_ff::PrimeField;
|
||||||
|
use ark_std::Zero;
|
||||||
|
|
||||||
pub mod gadgets;
|
pub mod gadgets;
|
||||||
pub mod hypercube;
|
pub mod hypercube;
|
||||||
@@ -21,3 +23,12 @@ pub fn powers_of<F: PrimeField>(x: F, n: usize) -> Vec<F> {
|
|||||||
}
|
}
|
||||||
c
|
c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns the coordinates of a commitment point. This is compatible with the arkworks
|
||||||
|
/// GC.to_constraint_field()[..2]
|
||||||
|
pub fn get_cm_coordinates<C: CurveGroup>(cm: &C) -> Vec<C::BaseField> {
|
||||||
|
let zero = (&C::BaseField::zero(), &C::BaseField::zero());
|
||||||
|
let cm = cm.into_affine();
|
||||||
|
let (cm_x, cm_y) = cm.xy().unwrap_or(zero);
|
||||||
|
vec![*cm_x, *cm_y]
|
||||||
|
}
|
||||||
|
|||||||
@@ -85,15 +85,16 @@ impl From<(Groth16VerifierKey, KZG10VerifierKey, usize)> for NovaCycleFoldVerifi
|
|||||||
|
|
||||||
// implements From assuming that the 'batchCheck' method from the KZG10 template will not be used
|
// implements From assuming that the 'batchCheck' method from the KZG10 template will not be used
|
||||||
// in the NovaCycleFoldDecider verifier contract
|
// in the NovaCycleFoldDecider verifier contract
|
||||||
impl From<(VerifyingKey<Bn254>, VerifierKey<Bn254>, usize)> for NovaCycleFoldVerifierKey {
|
impl From<((VerifyingKey<Bn254>, VerifierKey<Bn254>), usize)> for NovaCycleFoldVerifierKey {
|
||||||
fn from(value: (VerifyingKey<Bn254>, VerifierKey<Bn254>, usize)) -> Self {
|
fn from(value: ((VerifyingKey<Bn254>, VerifierKey<Bn254>), usize)) -> Self {
|
||||||
let g16_vk = Groth16VerifierKey::from(value.0);
|
let decider_vp = value.0;
|
||||||
|
let g16_vk = Groth16VerifierKey::from(decider_vp.0);
|
||||||
// pass `Vec::new()` since batchCheck will not be used
|
// pass `Vec::new()` since batchCheck will not be used
|
||||||
let kzg_vk = KZG10VerifierKey::from((value.1, Vec::new()));
|
let kzg_vk = KZG10VerifierKey::from((decider_vp.1, Vec::new()));
|
||||||
Self {
|
Self {
|
||||||
g16_vk,
|
g16_vk,
|
||||||
kzg_vk,
|
kzg_vk,
|
||||||
z_len: value.2,
|
z_len: value.1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,7 +259,7 @@ mod tests {
|
|||||||
let (_, kzg_vk, _, g16_vk, _) = setup(DEFAULT_SETUP_LEN);
|
let (_, kzg_vk, _, g16_vk, _) = setup(DEFAULT_SETUP_LEN);
|
||||||
|
|
||||||
let mut bytes = vec![];
|
let mut bytes = vec![];
|
||||||
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from((g16_vk, kzg_vk, 1));
|
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from(((g16_vk, kzg_vk), 1));
|
||||||
|
|
||||||
nova_cyclefold_vk
|
nova_cyclefold_vk
|
||||||
.serialize_protocol_verifier_key(&mut bytes)
|
.serialize_protocol_verifier_key(&mut bytes)
|
||||||
@@ -272,7 +273,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn nova_cyclefold_decider_template_renders() {
|
fn nova_cyclefold_decider_template_renders() {
|
||||||
let (_, kzg_vk, _, g16_vk, _) = setup(DEFAULT_SETUP_LEN);
|
let (_, kzg_vk, _, g16_vk, _) = setup(DEFAULT_SETUP_LEN);
|
||||||
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from((g16_vk, kzg_vk, 1));
|
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from(((g16_vk, kzg_vk), 1));
|
||||||
|
|
||||||
let decider_solidity_code = HeaderInclusion::<NovaCycleFoldDecider>::builder()
|
let decider_solidity_code = HeaderInclusion::<NovaCycleFoldDecider>::builder()
|
||||||
.template(nova_cyclefold_vk)
|
.template(nova_cyclefold_vk)
|
||||||
@@ -296,8 +297,8 @@ mod tests {
|
|||||||
let (cf_pedersen_params, _) = Pedersen::<G2>::setup(&mut rng, cf_cs_len).unwrap();
|
let (cf_pedersen_params, _) = Pedersen::<G2>::setup(&mut rng, cf_cs_len).unwrap();
|
||||||
let fs_prover_params = ProverParams::<G1, G2, KZG<Bn254>, Pedersen<G2>> {
|
let fs_prover_params = ProverParams::<G1, G2, KZG<Bn254>, Pedersen<G2>> {
|
||||||
poseidon_config: poseidon_config.clone(),
|
poseidon_config: poseidon_config.clone(),
|
||||||
cs_params: kzg_pk.clone(),
|
cs_pp: kzg_pk.clone(),
|
||||||
cf_cs_params: cf_pedersen_params,
|
cf_cs_pp: cf_pedersen_params,
|
||||||
};
|
};
|
||||||
(fs_prover_params, kzg_vk)
|
(fs_prover_params, kzg_vk)
|
||||||
}
|
}
|
||||||
@@ -371,22 +372,22 @@ mod tests {
|
|||||||
>;
|
>;
|
||||||
let f_circuit = FC::new(()).unwrap();
|
let f_circuit = FC::new(()).unwrap();
|
||||||
|
|
||||||
let nova_cyclefold_vk =
|
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from((
|
||||||
NovaCycleFoldVerifierKey::from((g16_vk.clone(), kzg_vk.clone(), f_circuit.state_len()));
|
(g16_vk.clone(), kzg_vk.clone()),
|
||||||
|
f_circuit.state_len(),
|
||||||
|
));
|
||||||
|
|
||||||
|
let mut rng = rand::rngs::OsRng;
|
||||||
|
|
||||||
let mut nova = NOVA_FCircuit::init(&fs_prover_params, f_circuit, z_0).unwrap();
|
let mut nova = NOVA_FCircuit::init(&fs_prover_params, f_circuit, z_0).unwrap();
|
||||||
for _ in 0..n_steps {
|
for _ in 0..n_steps {
|
||||||
nova.prove_step(vec![]).unwrap();
|
nova.prove_step(&mut rng, vec![]).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let rng = rand::rngs::OsRng;
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let proof = DECIDERETH_FCircuit::prove(
|
let proof =
|
||||||
(g16_pk, fs_prover_params.cs_params.clone()),
|
DECIDERETH_FCircuit::prove(rng, (g16_pk, fs_prover_params.cs_pp.clone()), nova.clone())
|
||||||
rng,
|
.unwrap();
|
||||||
nova.clone(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
println!("generated Decider proof: {:?}", start.elapsed());
|
println!("generated Decider proof: {:?}", start.elapsed());
|
||||||
|
|
||||||
let verified = DECIDERETH_FCircuit::<FC>::verify(
|
let verified = DECIDERETH_FCircuit::<FC>::verify(
|
||||||
|
|||||||
Reference in New Issue
Block a user