From d328ae7d16ed9c8b78663ae95445bb50941744d9 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Wed, 8 May 2024 13:34:59 +0200 Subject: [PATCH] update usage sections to last interfaces --- src/usage/fold.md | 3 +- src/usage/frontend-arkworks.md | 69 ++++++++++++++++++++-------------- src/usage/frontend-circom.md | 24 ++++++++---- src/usage/frontend.md | 6 +++ 4 files changed, 64 insertions(+), 38 deletions(-) diff --git a/src/usage/fold.md b/src/usage/fold.md index 0c55461..90c0bad 100644 --- a/src/usage/fold.md +++ b/src/usage/fold.md @@ -30,7 +30,8 @@ let mut folding_scheme = NOVA::init(&prover_params, F_circuit, initial_state.clo // compute a step of the IVC for i in 0..num_steps { let start = Instant::now(); - folding_scheme.prove_step().unwrap(); + // here we pass an empty vec since it does not use external_inputs + folding_scheme.prove_step(vec![]).unwrap(); println!("Nova::prove_step {}: {:?}", i, start.elapsed()); } diff --git a/src/usage/frontend-arkworks.md b/src/usage/frontend-arkworks.md index a18c794..0f33da0 100644 --- a/src/usage/frontend-arkworks.md +++ b/src/usage/frontend-arkworks.md @@ -22,7 +22,10 @@ impl FCircuit for CubicFCircuit { fn state_len(&self) -> usize { 1 } - fn step_native(&self, _i: usize, z_i: Vec) -> Result, Error> { + fn external_inputs_len(&self) -> usize { + 0 + } + fn step_native(&self, _i: usize, z_i: Vec, _external_inputs: Vec) -> Result, Error> { Ok(vec![z_i[0] * z_i[0] * z_i[0] + z_i[0] + F::from(5_u32)]) } fn generate_step_constraints( @@ -30,6 +33,7 @@ impl FCircuit for CubicFCircuit { cs: ConstraintSystemRef, _i: usize, z_i: Vec>, + _external_inputs: Vec>, ) -> Result>, SynthesisError> { let five = FpVar::::new_constant(cs.clone(), F::from(5u32))?; let z_i = z_i[0].clone(); @@ -70,10 +74,13 @@ impl FCircuit for MultiInputsFCircuit { fn state_len(&self) -> usize { 5 // This circuit has 5 inputs } + fn external_inputs_len(&self) -> usize { + 0 + } // Computes the next state values in place, assigning z_{i+1} into z_i, and computing the new z_{i+1} // We want the `step_native` method to implement the same logic as the `generate_step_constraints` method - fn step_native(&self, _i: usize, z_i: Vec) -> Result, Error> { + fn step_native(&self, _i: usize, z_i: Vec, _external_inputs: Vec) -> Result, Error> { let a = z_i[0] + F::from(4_u32); let b = z_i[1] + F::from(40_u32); let c = z_i[2] * F::from(4_u32); @@ -89,6 +96,7 @@ impl FCircuit for MultiInputsFCircuit { cs: ConstraintSystemRef, _i: usize, z_i: Vec>, + _external_inputs: Vec>, ) -> Result>, SynthesisError> { // Implementing the circuit constraints let four = FpVar::::new_constant(cs.clone(), F::from(4u32))?; @@ -129,10 +137,13 @@ impl FCircuit for Sha256FCircuit { fn state_len(&self) -> usize { 1 } + fn external_inputs_len(&self) -> usize { + 0 + } /// Computes the next state values in place, assigning z_{i+1} into z_i, and computing the new /// z_{i+1} - fn step_native(&self, _i: usize, z_i: Vec) -> Result, Error> { + fn step_native(&self, _i: usize, z_i: Vec, _external_inputs: Vec) -> Result, Error> { let out_bytes = Sha256::evaluate(&(), z_i[0].into_bigint().to_bytes_le()).unwrap(); let out: Vec = out_bytes.to_field_elements().unwrap(); @@ -145,6 +156,7 @@ impl FCircuit for Sha256FCircuit { _cs: ConstraintSystemRef, _i: usize, z_i: Vec>, + _external_inputs: Vec>, ) -> Result>, SynthesisError> { let unit_var = UnitVar::default(); let out_bytes = Sha256Gadget::evaluate(&unit_var, &z_i[0].to_bytes()?)?; @@ -172,22 +184,20 @@ This is useful for example if we want to fold multiple verifications of signatur where each F is: - w_i - │ ┌────────────────────┐ - │ │FCircuit │ - │ │ │ - └────►│ h =Hash(z_i[0],w_i)│ - │ │ =Hash(v, w_i) │ - ────────►│ │ ├───────► -z_i=[v,0] │ └──►z_{i+1}=[h, 0] │ z_{i+1}=[h,0] - │ │ - └────────────────────┘ + w_i + │ ┌────────────────────┐ + │ │FCircuit │ + │ │ │ + └────►│ h =Hash(z_i[0],w_i)│ +────────►│ │ ├───────► + z_i │ └──►z_{i+1}=[h] │ z_{i+1} + │ │ + └────────────────────┘ ``` where each $w_i$ value is set at the `external_inputs` array. The last state $z_i$ is used together with the external input w_i as inputs to compute the new state $z_{i+1}$. -The function F will output the new state in an array of two elements, where the second element is a 0. In other words, $z_{i+1} = [F([z_i, w_i]), 0]$, and the 0 will be replaced by $w_{i+1}$ in the next iteration, so $z_{i+2} = [F([z_{i+1}, w_{i+1}]), 0]$. ```rust #[derive(Clone, Debug)] @@ -197,47 +207,48 @@ where { _f: PhantomData, poseidon_config: PoseidonConfig, - external_inputs: Vec, } impl FCircuit for ExternalInputsCircuits where F: Absorb, { - type Params = (PoseidonConfig, Vec); // where Vec contains the external inputs + type Params = (PoseidonConfig); fn new(params: Self::Params) -> Self { Self { _f: PhantomData, poseidon_config: params.0, - external_inputs: params.1, } } fn state_len(&self) -> usize { - 2 + 1 + } + fn external_inputs_len(&self) -> usize { + 1 } - /// computes the next state values in place, assigning z_{i+1} into z_i, and computing the new + /// computes the next state value for the step of F for the given z_i and external_inputs /// z_{i+1} - fn step_native(&self, i: usize, z_i: Vec) -> Result, Error> { - let input: [F; 2] = [z_i[0], self.external_inputs[i]]; - let h = CRH::::evaluate(&self.poseidon_config, input).unwrap(); - Ok(vec![h, F::zero()]) + fn step_native(&self, i: usize, z_i: Vec, external_inputs: Vec) -> Result, Error> { + let hash_input: [F; 2] = [z_i[0], external_inputs[0]]; + let h = CRH::::evaluate(&self.poseidon_config, hash_input).unwrap(); + Ok(vec![h]) } - /// generates the constraints for the step of F for the given z_i + /// generates the constraints and returns the next state value for the step of F for the given + /// z_i and external_inputs fn generate_step_constraints( &self, cs: ConstraintSystemRef, i: usize, z_i: Vec>, + external_inputs: Vec>, ) -> Result>, SynthesisError> { let crh_params = CRHParametersVar::::new_constant(cs.clone(), self.poseidon_config.clone())?; - let external_inputVar = - FpVar::::new_witness(cs.clone(), || Ok(self.external_inputs[i])).unwrap(); - let input: [FpVar; 2] = [z_i[0].clone(), external_inputVar.clone()]; - let h = CRHGadget::::evaluate(&crh_params, &input)?; - Ok(vec![h, FpVar::::zero()]) + let hash_input: [FpVar; 2] = [z_i[0].clone(), external_inputs[0].clone()]; + let h = CRHGadget::::evaluate(&crh_params, &hash_input)?; + Ok(vec![h]) } } ``` diff --git a/src/usage/frontend-circom.md b/src/usage/frontend-circom.md index 3bfb477..fc7cbef 100644 --- a/src/usage/frontend-circom.md +++ b/src/usage/frontend-circom.md @@ -5,8 +5,11 @@ We can define the circuit to be folded in Circom. The only interface that we nee ```c template FCircuit() { - signal input ivc_input[1]; - signal output ivc_output[1]; + signal input ivc_input[1]; // IVC state + signal input external_inputs[2]; // not state + + signal output ivc_output[1]; // next IVC state + // [...] } component main {public [ivc_input]} = Example(); @@ -14,18 +17,23 @@ component main {public [ivc_input]} = Example(); The `ivc_input` is the array that defines the initial state, and the `ivc_output` is the array that defines the output state after the step. -So for example, the following circuit does the traditional example at each step, which proves knowledge of $x$ such that $y==x^3 + x + 5$ for a known $y$: +So for example, the following circuit does the traditional example at each step, which proves knowledge of $x$ such that $y==x^3 + x + e_0 + e_1$ for a known $y$ ($e_i$ are the `external_inputs[i]`): ```c pragma circom 2.0.3; template Example () { - signal input ivc_input[1]; - signal output ivc_output[1]; - signal temp; + signal input ivc_input[1]; // IVC state + signal input external_inputs[2]; // not state + + signal output ivc_output[1]; // next IVC state + + signal temp1; + signal temp2; - temp <== ivc_input[0] * ivc_input[0]; - ivc_output[0] <== temp * ivc_input[0] + ivc_input[0] + 5; + temp1 <== ivc_input[0] * ivc_input[0]; + temp2 <== ivc_input[0] * external_inputs[0]; + ivc_output[0] <== temp1 * ivc_input[0] + temp2 + external_inputs[1]; } component main {public [ivc_input]} = Example(); diff --git a/src/usage/frontend.md b/src/usage/frontend.md index 5819054..c8d18ce 100644 --- a/src/usage/frontend.md +++ b/src/usage/frontend.md @@ -20,6 +20,10 @@ pub trait FCircuit: Clone + Debug { /// Returns the number of elements in the state of the FCircuit, which corresponds to the /// FCircuit inputs. fn state_len(&self) -> usize; + + /// returns the number of elements in the external inputs used by the FCircuit. External inputs + /// are optional, and in case no external inputs are used, this method should return 0. + fn external_inputs_len(&self) -> usize; /// Computes the next state values in place, assigning z_{i+1} into z_i, and computing the new /// z_{i+1} @@ -29,6 +33,7 @@ pub trait FCircuit: Clone + Debug { &self, i: usize, z_i: Vec, + external_inputs: Vec, // inputs that are not part of the state ) -> Result, Error>; /// Generates the constraints for the step of F for the given z_i @@ -39,6 +44,7 @@ pub trait FCircuit: Clone + Debug { cs: ConstraintSystemRef, i: usize, z_i: Vec>, + external_inputs: Vec>, // inputs that are not part of the state ) -> Result>, SynthesisError>; } ```