Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update the FCircuit trait, so that it supports custom data structures for the external inputs. #191

Merged
merged 2 commits into from
Dec 27, 2024

Conversation

arnaucube
Copy link
Collaborator

@arnaucube arnaucube commented Dec 25, 2024

Update the FCircuit trait, so that it supports custom data structures for the external inputs.

This also eliminates the need of having the external_inputs_len method in the FCircuit.

The motivation for this change is that in most practical use cases, the external inputs have a not-naive structure, and the old interface required that to convert the external inputs structure into a vector of finite field elements, which inside the FCircuit would be converted back into a custom data structure. This is specially tedious when dealing with curve points, which converting them from point to field elements and back to the point (both outside (rust native) and inside the circuit (constraints)) is a bit cumbersome. With this update, it's much more straight forward to define the FCircuit with custom external inputs data structures.

For the experimental-frontends, the external inputs keep being an array of field elements.

When reviewing this PR: the main change is in the file folding-schemes/src/frontend/mod.rs, most of the rest of the git diff is just updating the code to the new FCircuit interface.

Context/motivation

When doing more 'real world' use cases, it is convenient to don't have the limitation to just arrays of field elements for the external inputs on the FCircuit. For example, when dealing with elliptic curve points, it required to convert the points to affine to get their coordinates as field elements, then concatenate the various field elements (coordinates) from various points to pass it as Vec<FpVar<F>> as the external_inputs to the FCircuit, which then inside the FCircuit that vector gets decomposed back into separated coordinates to rebuild the elliptic curve points (which in order to do so, need to break some of the abstractions to be able to build the specific curve points).
This grows in complexity as the data structures needed are more rich.

As an example, suppose we want to have as external inputs the following structure ExtInpVar:

pub struct ExtInpVar<C: CurveGroup, GC: CurveVar<C, CF<C>>> {
    msg: FpVar<CF<C>>,
    pk: GC,
    sig_r: GC,
    sig_s: Vec<Boolean<CF<C>>>,
}

with this PR, in the FCircuit we just need to set the trait parameters:

type ExternalInputs = ExtInp<C>;
type ExternalInputsVar = ExtInpVar<C, GC>;

And then we can just directly use that type for the external_inputs:

    fn generate_step_constraints(
        &self,
        cs: ConstraintSystemRef<F>,
        _i: usize,
        z_i: Vec<FpVar<F>>,
        external_inputs: Self::ExternalInputsVar,
    ) -> Result<Vec<FpVar<F>>, SynthesisError> {
        let mut count = z_i[0].clone();
        let res = verify::<C, GC>(
            cs.clone(),
            self.config.clone(),
            external_inputs.pk,
            (external_inputs.sig_r, external_inputs.sig_s),
            external_inputs.msg,
        )?;
        res.enforce_equal(&Boolean::<F>::TRUE)?;
        count = count.clone() + FpVar::<F>::one();

        Ok(vec![count])
    }
}

The same use case before this PR, would have required much more code, and furthermore it would have needed to remove some of the curve abstractions in order to be able to reconstruct the GC points from their coordinates inside the FCircuit.

Full use case example code available at: https://github.com/arnaucube/fold-babyjubjubs/blob/main/src/fcircuit.rs#L53

… for the external inputs.

This also eliminates the need of having the `external_inputs_len` method in the `FCircuit`.

The motivation for this change is that in most practical use cases, the
external inputs have a not-naive structure, and the old interface required that
to convert the external inputs structure into a vector of finite field
elements, which inside the FCircuit would be converted back into a custom data
structure. This is specially tedious when dealing with curve points, which
converting them from point to field elements and back to the point (both
outside (rust native) and inside the circuit (constraints)) is a bit
cumbersome.  With this update, it's much more straight forward to define the
FCircuit with custom external inputs data structures.

For the experimental-frontends, the external inputs keep being an array of field elements.
Copy link
Collaborator

@winderica winderica left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work! I like the design of ExternalInputs and ExternalInputsVar, which makes the step circuits more flexible!

For the experimental-frontends, the external inputs keep being an array of field elements.

It is sad that rust does not implement Default for [T; N] where T already satisfies Default, and we need to wrap arrays of field elements by VecF and VecFpVar. But anyway the changes still look good to me!

folding-schemes/src/frontend/mod.rs Outdated Show resolved Hide resolved
examples/external_inputs.rs Outdated Show resolved Hide resolved
@arnaucube arnaucube added this pull request to the merge queue Dec 27, 2024
Merged via the queue into main with commit c6f1a24 Dec 27, 2024
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants