Hi, sorry I should have been more specific. Thank you very much for helping. Below is the entire error message.
type annotations needed
multiple `impl`s satisfying `for<'a> &'a _: ark_r1cs_std::groups::GroupOpsBounds<'a, _, _>` found in the `ark_r1cs_std` crate:
- impl<'a, P, F> ark_r1cs_std::groups::GroupOpsBounds<'a, ark_ec::short_weierstrass::Projective<P>, ProjectiveVar<P, F>> for &'a ProjectiveVar<P, F>
where P: SWCurveConfig, F: FieldVar<<P as CurveConfig>::BaseField, <<P as CurveConfig>::BaseField as Field>::BasePrimeField>, for<'b> &'b F: FieldOpsBounds<'b, <P as CurveConfig>::BaseField, F>;
- impl<'a, P, F> ark_r1cs_std::groups::GroupOpsBounds<'a, ark_ec::twisted_edwards::Projective<P>, ark_r1cs_std::groups::curves::twisted_edwards::AffineVar<P, F>> for &'a ark_r1cs_std::groups::curves::twisted_edwards::AffineVar<P, F>
where <F as TwoBitLookupGadget<<<P as CurveConfig>::BaseField as Field>::BasePrimeField>>::TableConstant == <P as CurveConfig>::BaseField, P: TECurveConfig, F: FieldVar<<P as CurveConfig>::BaseField, <<P as CurveConfig>::BaseField as Field>::BasePrimeField>, F: TwoBitLookupGadget<<<P as CurveConfig>::BaseField as Field>::BasePrimeField>, for<'b> &'b F: FieldOpsBounds<'b, <P as CurveConfig>::BaseField, F>;
subcircuit_ask.rs(119, 16): required for `subcircuit_ask::CombinedCircuit<_, _, _>` to implement `ConstraintSynthesizer<ark_ff::Fp<MontBackend<ark_bls12_381::FrConfig, 4>, 4>>`
lib.rs(85, 17): required by a bound in `ark_snark::CircuitSpecificSetupSNARK::setup`
The error comes from the following part of the code (the entirety of which I pasted below):
let (pk, vk) = Groth16::<E>::setup(CombinedCircuit {
bls_circuit: None,
rest_circuit: None,
}, rng).unwrap();
Below is the entire code.
use ark_std::vec::Vec;
use ark_snark::{CircuitSpecificSetupSNARK, SNARK};
use rand::rngs::OsRng;
use ark_groth16::Groth16;
use std::borrow::Borrow;
use ark_ec::bls12::Bls12Config;
use ark_crypto_primitives::encryption::elgamal::{Parameters as EncParams, PublicKey as EncPubKey, Randomness as EncRand};
use ark_relations::r1cs::{ConstraintSystem, SynthesisError, ConstraintSynthesizer, ConstraintSystemRef};
use bls_verify_gadget::{constraints::{BlsSignatureVerifyGadget, SignatureVar, ParametersVar as BlsParametersVar, PublicKeyVar as BlsPublicKeyVar},
bls::{PublicKey as BlsPublicKey, Signature, Parameters as BlsParams}};
use ark_crypto_primitives::signature::constraints::SigVerifyGadget;
use ark_bls12_381::Bls12_381 as E;
use ark_r1cs_std::{alloc::AllocVar, prelude::*};
use ark_ec::{twisted_edwards::Affine, CurveGroup, hashing::curve_maps::wb::WBConfig};
use ark_ff::Field;
use ark_serialize::{CanonicalSerialize, Compress};
use ark_ed_on_bls12_381::{constraints::EdwardsVar, EdwardsConfig, EdwardsProjective as JubJub};
use ark_std::marker::PhantomData;
type ConstraintF1<C> = <<C as CurveGroup>::BaseField as Field>::BasePrimeField; // In main(), C=JubJub and GG=EdwardsVar, which uses ark_ff::Fq<MontBackend<ark_bls12_381::FrConfig, 4>, 4>
type ConstraintF2<P> = <P as Bls12Config>::Fp; // This uses ark_ff::Fq<MontBackend<ark_bls12_381::FqConfig, 6>, 6>
pub struct BlsCircuit<P: Bls12Config> {
bls_params: Option<BlsParams<P>>, /* BLS parameters */
apk: Option<BlsPublicKey<P>>,
sig: Option<Signature<P>>,
msg: Option<Vec<u8>>,
}
pub struct RestCircuit<C: CurveGroup, GG: CurveVar<C, ConstraintF1<C>>> {
elgamal_rand: Option<EncRand<C>>, /* Elgamal parameters */
elgamal_ptxt_x: Option<ark_bls12_381::Fr>,
elgamal_ptxt_y: Option<ark_bls12_381::Fr>,
elgamal_pk: Option<EncPubKey<C>>,
elgamal_params: Option<EncParams<C>>,
_curve_var: PhantomData<GG>,
}
impl<P> ConstraintSynthesizer<ConstraintF2<P>> for BlsCircuit<P> where
P: Bls12Config,
ConstraintF2<P>: Field,
<P as Bls12Config>::G2Config: WBConfig,
{
fn generate_constraints(self, cs: ConstraintSystemRef<ConstraintF2<P>>) -> Result<(), SynthesisError> {
// 1. Check BLS signature
let bls_params_wtns = BlsParametersVar::<P>::new_variable(
cs.clone(),
|| self.bls_params.as_ref().ok_or(SynthesisError::AssignmentMissing),
AllocationMode::Witness,
)?;
let apk_input = BlsPublicKeyVar::<P>::new_variable(
cs.clone(),
|| self.apk.as_ref().ok_or(SynthesisError::AssignmentMissing),
AllocationMode::Input,
)?;
let msg_wtns_vec = [0u8; 32]; // Populate this with something in actual code
let msg_wtns = UInt8::<P::Fp>::new_witness_vec(cs.clone(), &msg_wtns_vec)?;
let sig_wtns = SignatureVar::<P>::new_variable(
cs.clone(),
|| self.sig.as_ref().ok_or(SynthesisError::AssignmentMissing),
AllocationMode::Witness,
)?;
// All inputs to verify() are based on '<ark_ff::Fq<MontBackend<ark_bls12_377::FqConfig, 6>, 6>'
let verified = BlsSignatureVerifyGadget::<P>::verify(&bls_params_wtns, &apk_input, &msg_wtns, &sig_wtns)?;
verified.enforce_equal(&Boolean::TRUE)?;
Ok(())
}
}
impl<C, GG> ConstraintSynthesizer<ConstraintF1<C>> for RestCircuit<C, GG> where
ConstraintF1<C>: Field,
C: CurveGroup,
GG: CurveVar<C, ConstraintF1<C>>,
for<'a> &'a GG: ark_r1cs_std::groups::GroupOpsBounds<'a, C, GG>,
ark_ec::twisted_edwards::Affine<EdwardsConfig>: Borrow<<C as CurveGroup>::Affine>,
{
fn generate_constraints(self, cs: ConstraintSystemRef<ConstraintF1<C>>) -> Result<(), SynthesisError> {
let elgamal_ptxt_x_value: ark_ff::Fp<ark_ff::MontBackend<ark_bls12_381::FrConfig, 4>, 4> = self.elgamal_ptxt_x.ok_or(SynthesisError::AssignmentMissing)?;
let elgamal_ptxt_y_value: ark_ff::Fp<ark_ff::MontBackend<ark_bls12_381::FrConfig, 4>, 4> = self.elgamal_ptxt_y.ok_or(SynthesisError::AssignmentMissing)?;
// Reconstruct plaintext passed in as Affine x and y coordinates (bytes)
let mut ptxt_x_bytes = vec![];
elgamal_ptxt_x_value.serialize_with_mode(&mut ptxt_x_bytes, Compress::No).unwrap();
let mut ptxt_y_bytes = vec![];
elgamal_ptxt_y_value.serialize_with_mode(&mut ptxt_y_bytes, Compress::No).unwrap();
// Declare input for circuit syntax, no need to actually use
let elgamal_ptxt_x_input = UInt8::<ConstraintF1<C>>::new_input_vec(
cs.clone(),
&ptxt_x_bytes,
);
let elgamal_ptxt_y_input = UInt8::<ConstraintF1<C>>::new_input_vec(
cs.clone(),
&ptxt_y_bytes,
);
// let elgamal_ptxt_x: ark_ff::Fq<MontBackend<ark_bls12_381::FrConfig, 4>, 4> = self.elgamal_ptxt_x.unwrap();
let point = Affine::<EdwardsConfig>::new(elgamal_ptxt_x_value, elgamal_ptxt_y_value);
// Do some zero knowledge proof with 'point'
Ok(())
}
}
pub struct CombinedCircuit<P: Bls12Config, C: CurveGroup, GG: CurveVar<C, ConstraintF1<C>>> {
bls_circuit: Option<BlsCircuit<P>>,
rest_circuit: Option<RestCircuit<C,GG>>,
}
impl<P, C, GG> ConstraintSynthesizer<ConstraintF2<P>> for CombinedCircuit<P, C, GG> where
P: Bls12Config,
C: CurveGroup,
GG: CurveVar<C, ConstraintF1<C>>,
<P as Bls12Config>::G2Config: WBConfig,
ConstraintF1<C>: Field,
for<'a> &'a GG: ark_r1cs_std::groups::GroupOpsBounds<'a, C, GG>,
ark_ec::twisted_edwards::Affine<EdwardsConfig>: Borrow<<C as CurveGroup>::Affine>,
{
fn generate_constraints(self, cs: ConstraintSystemRef<ConstraintF2<P>>) -> Result<(), SynthesisError> {
let bls_ns = ConstraintSystem::<ConstraintF2<P>>::new_ref();
self.bls_circuit.unwrap().generate_constraints(bls_ns)?;
let elgamal_ns = ConstraintSystem::<ConstraintF1<C>>::new_ref();
self.rest_circuit.unwrap().generate_constraints(elgamal_ns)?;
Ok(())
}
}
fn main() {
type C = JubJub; // Assuming JubJub is the curve used, update if different
type GG = EdwardsVar; // This uses
let rng = &mut OsRng;
// type Bls12Config = ark_bls12_381::Config;
let (pk, vk) = Groth16::<E>::setup(CombinedCircuit {
bls_circuit: None,
rest_circuit: None,
}, rng).unwrap();
let pvk = Groth16::<E>::process_vk(&vk).unwrap();
// Then prove circuit and verify the proof with Groth16
}
So suppose I explicitly defined the types for CombinedCircuit like below.
fn main() {
type P = ark_bls12_381::Config;
type C = JubJub;
type GG = EdwardsVar;
let rng = &mut OsRng;
type ImplCircuit = CombinedCircuit<P, C, GG>;
let (pk, vk) = Groth16::<E>::setup(ImplCircuit {
bls_circuit: None,
rest_circuit: None,
}, rng).unwrap();
let pvk = Groth16::<E>::process_vk(&vk).unwrap();
// Prove circuit and verify the proof with Groth16
}
Then it errors out saying this:
type mismatch resolving `<Config as Bls12Config>::Fp == Fp<MontBackend<FrConfig, 4>, 4>`
expected struct `ark_ff::Fp<MontBackend<ark_bls12_381::FrConfig, 4>, 4>`
found struct `ark_ff::Fp<MontBackend<ark_bls12_381::FqConfig, 6>, 6>` subcircuit_ask.rs(145, 20): required by a bound introduced by this call
lib.rs(85, 17): required by a bound in `ark_snark::CircuitSpecificSetupSNARK::setup`
Essentially, the problem seems to be that I'm using fields (ConstraintF1 and ConstraintF2
) that are configured on different MontBackEnds. Assume I must use the exact fields and curve groups defined in the codes. Is it not allowed in Rust to mix fields like this?