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

Multiple external inputs for circom frontend #181

Open
saharAP opened this issue Dec 2, 2024 · 3 comments
Open

Multiple external inputs for circom frontend #181

saharAP opened this issue Dec 2, 2024 · 3 comments

Comments

@saharAP
Copy link

saharAP commented Dec 2, 2024

Can we have multiple external inputs for Circom circuits, as shown below? If yes, how can we integrate them with Nova in the Rust code?

  signal input ivc_input[1];
    signal input external_inputs[2];
  signal input external_inputs_2[10];
signal input external_inputs_3;
    signal output ivc_output[1];
@arnaucube
Copy link
Collaborator

Could the same be achieved by placing the various external inputs that you list into a single external_inputs vector? like concatenating them, and inside the circuit extracting them from the unified vector into their respective vectors.
eg.

external_inputs_1 = external_inputs[0..2];
external_inputs_2 = external_inputs[2..10];
external_inputs_3 = external_inputs[10];




Not for the use case you mention but just in case:
Some times, a bit of more structure is useful. In those cases extra helper methods can be added, but probably agnostic to Sonobe.
For example, recently I was working on an example of usage where the external inputs are tuples of msg + signature + publickey. In order to 'flatten' it into a vector of field elements to feed it as external inputs I defined the following methods:

#[derive(Clone, Debug, PartialEq)]
pub struct ExtInp<C: CurveGroup> {
    msg: C::BaseField,
    pk: PublicKey<C>,
    sig: Signature<C>,
}

impl<C: CurveGroup> ExtInp<C>
where
    C: CurveGroup<BaseField = ark_bn254::Fr>,
    C: CurveGroup<Affine = ark_ec::twisted_edwards::Affine<EdwardsConfig>>,
{
    pub fn len() -> usize {
        5 + 253
    }
    /// returns a vector of BaseField elements
    pub fn to_f_vec(&self) -> Vec<C::BaseField> {
        let (pk_x, pk_y) = self.pk.xy();
        let (sig_r_x, sig_r_y) = self.sig.r().xy().unwrap();
        let s_bits = self.sig.s().into_bigint().to_bits_le();
        let s_vec = s_bits
            .iter()
            .map(|&b| {
                if b {
                    C::BaseField::ONE
                } else {
                    C::BaseField::ZERO
                }
            })
            .collect();

        vec![vec![self.msg, *pk_x, *pk_y, *sig_r_x, *sig_r_y], s_vec].concat()
    }
    /// gets a vector of BaseField elements and returns the ExtInp struct
    pub fn from_f_vec(v: &[C::BaseField]) -> Self {
        let msg = v[0];

        let (pk_x, pk_y) = (v[1], v[2]);
        let pk_point = TEAffine::new(pk_x, pk_y);
        let pk = PublicKey::<C>(pk_point);

        let (sig_r_x, sig_r_y) = (v[3], v[4]);
        let sig_r = TEAffine::new(sig_r_x, sig_r_y);
        let s_bits: Vec<bool> = v[5..5 + 253]
            .iter()
            .map(|b| if b.is_zero() { false } else { true })
            .collect();
        let sig_s = C::ScalarField::from_bigint(BigInteger::from_bits_le(&s_bits)).unwrap();
        let sig = Signature::<C>::new(sig_r, sig_s);

        Self { msg, sig, pk }
    }

And then to call the .prove_step(rng, external_inputs, None) it is just
.prove_step(rng, ext_inp.to_f_vec(), None).
And inside the FCircuit.step_native() it would use the method ExtInp::from_f_vec to recover the structs from the external_inputs: Vec<F> vector. And similarly for the generate_step_constraints method in-circuit.

@arnaucube
Copy link
Collaborator

Sorry I just realized that you were referring to the Circom frontend, and the examples I've mentioned are not with Circom but with Rust. Anyways hopefully the same logic/ideas can be done in the Circom case.

@saharAP
Copy link
Author

saharAP commented Dec 3, 2024

Sorry I just realized that you were referring to the Circom frontend, and the examples I've mentioned are not with Circom but with Rust. Anyways hopefully the same logic/ideas can be done in the Circom case.

No worries. Thanks for your response; it’s very helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants