@ -1,3 +1,6 @@
use crate ::frontend ::FCircuit ;
use crate ::frontend ::FpVar ::Var ;
use crate ::Error ;
use ark_circom ::circom ::{ CircomCircuit , R1CS as CircomR1CS } ;
use ark_circom ::circom ::{ CircomCircuit , R1CS as CircomR1CS } ;
use ark_ff ::PrimeField ;
use ark_ff ::PrimeField ;
use ark_r1cs_std ::alloc ::AllocVar ;
use ark_r1cs_std ::alloc ::AllocVar ;
@ -8,9 +11,6 @@ use ark_std::fmt::Debug;
use num_bigint ::BigInt ;
use num_bigint ::BigInt ;
use std ::path ::PathBuf ;
use std ::path ::PathBuf ;
use crate ::frontend ::FCircuit ;
use crate ::Error ;
pub mod utils ;
pub mod utils ;
use utils ::CircomWrapper ;
use utils ::CircomWrapper ;
@ -97,11 +97,11 @@ impl FCircuit for CircomFCircuit {
#[ cfg(test) ]
#[ cfg(test) ]
assert_eq ! ( external_inputs . len ( ) , self . external_inputs_len ( ) ) ;
assert_eq ! ( external_inputs . len ( ) , self . external_inputs_len ( ) ) ;
let input_values = self . fpvars_to_bigints ( z_i ) ? ;
let input_values = self . fpvars_to_bigints ( & z_i ) ? ;
let mut inputs_map = vec ! [ ( "ivc_input" . to_string ( ) , input_values ) ] ;
let mut inputs_map = vec ! [ ( "ivc_input" . to_string ( ) , input_values ) ] ;
if self . external_inputs_len ( ) > 0 {
if self . external_inputs_len ( ) > 0 {
let external_inputs_bi = self . fpvars_to_bigints ( external_inputs ) ? ;
let external_inputs_bi = self . fpvars_to_bigints ( & external_inputs ) ? ;
inputs_map . push ( ( "external_inputs" . to_string ( ) , external_inputs_bi ) ) ;
inputs_map . push ( ( "external_inputs" . to_string ( ) , external_inputs_bi ) ) ;
}
}
@ -110,20 +110,32 @@ impl FCircuit for CircomFCircuit {
. extract_witness ( & inputs_map )
. extract_witness ( & inputs_map )
. map_err ( | _ | SynthesisError ::AssignmentMissing ) ? ;
. map_err ( | _ | SynthesisError ::AssignmentMissing ) ? ;
// Since public inputs are already allocated variables, we will tell `circom-compat` to not re-allocate those
let mut already_allocated_public_inputs = vec ! [ ] ;
for var in z_i . iter ( ) {
match var {
Var ( var ) = > already_allocated_public_inputs . push ( var . variable ) ,
_ = > return Err ( SynthesisError ::Unsatisfiable ) , // allocated z_i should be Var
}
}
// Initializes the CircomCircuit.
// Initializes the CircomCircuit.
let circom_circuit = CircomCircuit {
let circom_circuit = CircomCircuit {
r1cs : self . r1cs . clone ( ) ,
r1cs : self . r1cs . clone ( ) ,
witness : Some ( witness . clone ( ) ) ,
witness : Some ( witness . clone ( ) ) ,
inputs_already_allocated : true ,
public_inputs_indexes : already_allocated_public_inputs ,
allocate_inputs_as_witnesses : true ,
} ;
} ;
// Generates the constraints for the circom_circuit.
// Generates the constraints for the circom_circuit.
circom_circuit . generate_constraints ( cs . clone ( ) ) ? ;
circom_circuit . generate_constraints ( cs . clone ( ) ) ? ;
// TODO: https://github.com/privacy-scaling-explorations/sonobe/issues/104
// We disable checking constraints for now
// Checks for constraint satisfaction.
// Checks for constraint satisfaction.
if ! cs . is_satisfied ( ) . unwrap ( ) {
return Err ( SynthesisError ::Unsatisfiable ) ;
}
// if !cs.is_satisfied().unwrap() {
// return Err(SynthesisError::Unsatisfiable);
// }
// Extracts the z_i1(next state) from the witness vector.
// Extracts the z_i1(next state) from the witness vector.
let z_i1 : Vec < FpVar < F > > = Vec ::< FpVar < F > > ::new_witness ( cs . clone ( ) , | | {
let z_i1 : Vec < FpVar < F > > = Vec ::< FpVar < F > > ::new_witness ( cs . clone ( ) , | | {
@ -135,7 +147,7 @@ impl FCircuit for CircomFCircuit {
}
}
impl < F : PrimeField > CircomFCircuit < F > {
impl < F : PrimeField > CircomFCircuit < F > {
fn fpvars_to_bigints ( & self , fpVars : Vec < FpVar < F > > ) -> Result < Vec < BigInt > , SynthesisError > {
fn fpvars_to_bigints ( & self , fpVars : & [ FpVar < F > ] ) -> Result < Vec < BigInt > , SynthesisError > {
let mut input_values = Vec ::new ( ) ;
let mut input_values = Vec ::new ( ) ;
// converts each FpVar to PrimeField value, then to num_bigint::BigInt.
// converts each FpVar to PrimeField value, then to num_bigint::BigInt.
for fp_var in fpVars . iter ( ) {
for fp_var in fpVars . iter ( ) {
@ -154,7 +166,7 @@ impl CircomFCircuit {
#[ cfg(test) ]
#[ cfg(test) ]
pub mod tests {
pub mod tests {
use super ::* ;
use super ::* ;
use ark_pallas ::Fr ;
use ark_bn254 ::Fr ;
use ark_r1cs_std ::alloc ::AllocVar ;
use ark_r1cs_std ::alloc ::AllocVar ;
use ark_relations ::r1cs ::{ ConstraintSynthesizer , ConstraintSystem } ;
use ark_relations ::r1cs ::{ ConstraintSynthesizer , ConstraintSystem } ;
@ -186,8 +198,6 @@ pub mod tests {
let z_i = vec ! [ Fr ::from ( 3 u32 ) ] ;
let z_i = vec ! [ Fr ::from ( 3 u32 ) ] ;
let z_i_var = Vec ::< FpVar < Fr > > ::new_witness ( cs . clone ( ) , | | Ok ( z_i ) ) . unwrap ( ) ;
let z_i_var = Vec ::< FpVar < Fr > > ::new_witness ( cs . clone ( ) , | | Ok ( z_i ) ) . unwrap ( ) ;
let cs = ConstraintSystem ::< Fr > ::new_ref ( ) ;
let z_i1_var = circom_fcircuit
let z_i1_var = circom_fcircuit
. generate_step_constraints ( cs . clone ( ) , 1 , z_i_var , vec ! [ ] )
. generate_step_constraints ( cs . clone ( ) , 1 , z_i_var , vec ! [ ] )
. unwrap ( ) ;
. unwrap ( ) ;
@ -222,32 +232,77 @@ pub mod tests {
#[ test ]
#[ test ]
fn test_circom_external_inputs ( ) {
fn test_circom_external_inputs ( ) {
let r1cs_path = PathBuf ::from ( "./src/frontend/circom/test_folder/external_inputs.r1cs" ) ;
let r1cs_path =
PathBuf ::from ( "./src/frontend/circom/test_folder/with_external_inputs.r1cs" ) ;
let wasm_path = PathBuf ::from (
let wasm_path = PathBuf ::from (
"./src/frontend/circom/test_folder/external_inputs_js/external_inputs.wasm" ,
"./src/frontend/circom/test_folder/with_ external_inputs_js/with_ external_inputs.wasm" ,
) ;
) ;
let circom_fcircuit = CircomFCircuit ::< Fr > ::new ( ( r1cs_path , wasm_path , 1 , 2 ) ) . unwrap ( ) ; // state_len:1, external_inputs_len:2
let circom_fcircuit = CircomFCircuit ::< Fr > ::new ( ( r1cs_path , wasm_path , 1 , 2 ) ) . unwrap ( ) ; // state_len:1, external_inputs_len:2
let cs = ConstraintSystem ::< Fr > ::new_ref ( ) ;
let cs = ConstraintSystem ::< Fr > ::new_ref ( ) ;
let z_i = vec ! [ Fr ::from ( 3 u32 ) ] ;
let z_i = vec ! [ Fr ::from ( 3 u32 ) ] ;
let external_inputs = vec ! [ Fr ::from ( 6 u32 ) , Fr ::from ( 7 u32 ) ] ;
let external_inputs = vec ! [ Fr ::from ( 6 u32 ) , Fr ::from ( 7 u32 ) ] ;
// run native step
// run native step
let z_i1 = circom_fcircuit
let z_i1_native = circom_fcircuit
. step_native ( 1 , z_i . clone ( ) , external_inputs . clone ( ) )
. step_native ( 1 , z_i . clone ( ) , external_inputs . clone ( ) )
. unwrap ( ) ;
. unwrap ( ) ;
assert_eq ! ( z_i1 , vec ! [ Fr ::from ( 52 u32 ) ] ) ;
// run gadget step
// run gadget step
let z_i_var = Vec ::< FpVar < Fr > > ::new_witness ( cs . clone ( ) , | | Ok ( z_i ) ) . unwrap ( ) ;
let z_i_var = Vec ::< FpVar < Fr > > ::new_witness ( cs . clone ( ) , | | Ok ( z_i ) ) . unwrap ( ) ;
let external_inputs_var =
Vec ::< FpVar < Fr > > ::new_witness ( cs . clone ( ) , | | Ok ( external_inputs . clone ( ) ) ) . unwrap ( ) ;
let z_i1_var = circom_fcircuit
. generate_step_constraints ( cs . clone ( ) , 1 , z_i_var , external_inputs_var )
. unwrap ( ) ;
assert_eq ! ( z_i1_var . value ( ) . unwrap ( ) , z_i1_native ) ;
// re-init cs and run gadget step with wrong ivc inputs (first ivc should not be zero)
let cs = ConstraintSystem ::< Fr > ::new_ref ( ) ;
let wrong_z_i = vec ! [ Fr ::from ( 0 ) ] ;
let wrong_z_i_var = Vec ::< FpVar < Fr > > ::new_witness ( cs . clone ( ) , | | Ok ( wrong_z_i ) ) . unwrap ( ) ;
let external_inputs_var =
let external_inputs_var =
Vec ::< FpVar < Fr > > ::new_witness ( cs . clone ( ) , | | Ok ( external_inputs ) ) . unwrap ( ) ;
Vec ::< FpVar < Fr > > ::new_witness ( cs . clone ( ) , | | Ok ( external_inputs ) ) . unwrap ( ) ;
let _z_i1_var = circom_fcircuit . generate_step_constraints (
cs . clone ( ) ,
1 ,
wrong_z_i_var ,
external_inputs_var ,
) ;
// TODO:: https://github.com/privacy-scaling-explorations/sonobe/issues/104
// Disable check for now
// assert!(z_i1_var.is_err());
}
#[ test ]
fn test_circom_no_external_inputs ( ) {
let r1cs_path = PathBuf ::from ( "./src/frontend/circom/test_folder/no_external_inputs.r1cs" ) ;
let wasm_path = PathBuf ::from (
"./src/frontend/circom/test_folder/no_external_inputs_js/no_external_inputs.wasm" ,
) ;
let circom_fcircuit = CircomFCircuit ::< Fr > ::new ( ( r1cs_path , wasm_path , 3 , 0 ) ) . unwrap ( ) ;
let cs = ConstraintSystem ::< Fr > ::new_ref ( ) ;
let z_i = vec ! [ Fr ::from ( 3 u32 ) , Fr ::from ( 4 u32 ) , Fr ::from ( 5 u32 ) ] ;
let z_i_var = Vec ::< FpVar < Fr > > ::new_witness ( cs . clone ( ) , | | Ok ( z_i . clone ( ) ) ) . unwrap ( ) ;
// run native step
let z_i1_native = circom_fcircuit . step_native ( 1 , z_i . clone ( ) , vec ! [ ] ) . unwrap ( ) ;
// run gadget step
let z_i1_var = circom_fcircuit
let z_i1_var = circom_fcircuit
. generate_step_constraints ( cs . clone ( ) , 1 , z_i_var , external_inputs_var )
. generate_step_constraints ( cs . clone ( ) , 1 , z_i_var , vec ! [ ] )
. unwrap ( ) ;
. unwrap ( ) ;
assert_eq ! ( z_i1_var . value ( ) . unwrap ( ) , vec ! [ Fr ::from ( 52 u32 ) ] ) ;
assert_eq ! ( z_i1_var . value ( ) . unwrap ( ) , z_i1_native ) ;
// re-init cs and run gadget step with wrong ivc inputs (first ivc input should not be zero)
let cs = ConstraintSystem ::< Fr > ::new_ref ( ) ;
let wrong_z_i = vec ! [ Fr ::from ( 0 u32 ) , Fr ::from ( 4 u32 ) , Fr ::from ( 5 u32 ) ] ;
let wrong_z_i_var = Vec ::< FpVar < Fr > > ::new_witness ( cs . clone ( ) , | | Ok ( wrong_z_i ) ) . unwrap ( ) ;
let _z_i1_var =
circom_fcircuit . generate_step_constraints ( cs . clone ( ) , 1 , wrong_z_i_var , vec ! [ ] ) ;
// TODO:: https://github.com/privacy-scaling-explorations/sonobe/issues/104
// Disable check for now
// assert!(z_i1_var.is_err())
}
}
}
}