/// Implements the C_{EC} circuit described in [CycleFold paper](https://eprint.iacr.org/2023/1192.pdf) use ark_ec::CurveGroup; use ark_r1cs_std::{boolean::Boolean, prelude::CurveVar}; use ark_relations::r1cs::SynthesisError; use core::marker::PhantomData; use super::CF; /// ECRLC implements gadget that checks the Elliptic Curve points RandomLinearCombination described /// in [CycleFold](https://eprint.iacr.org/2023/1192.pdf). #[derive(Debug)] pub struct ECRLC>> { _c: PhantomData, _gc: PhantomData, } impl>> ECRLC { pub fn check( // get r in bits format, so it can be reused across many instances of ECRLC gadget, // reducing the number of constraints needed r_bits: Vec>>, p1: GC, p2: GC, p3: GC, ) -> Result<(), SynthesisError> { p3.enforce_equal(&(p1 + p2.scalar_mul_le(r_bits.iter())?))?; Ok(()) } } #[cfg(test)] mod tests { use super::*; use ark_ff::{BigInteger, PrimeField}; use ark_pallas::{constraints::GVar, Fq, Fr, Projective}; use ark_r1cs_std::alloc::AllocVar; use ark_relations::r1cs::ConstraintSystem; use ark_std::UniformRand; use std::ops::Mul; /// Let Curve1=pallas and Curve2=vesta. Here our constraints system will work over Curve2::Fr = /// vesta::Fr (=pallas::Fq), thus our points are P_i \in Curve1 (=pasta). #[test] fn test_ecrlc_check() { let mut rng = ark_std::test_rng(); let r = Fr::rand(&mut rng); let p1 = Projective::rand(&mut rng); let p2 = Projective::rand(&mut rng); let p3 = p1 + p2.mul(r); let cs = ConstraintSystem::::new_ref(); // CS over Curve2::Fr = Curve1::Fq // prepare circuit inputs let rbitsVar: Vec> = Vec::new_witness(cs.clone(), || Ok(r.into_bigint().to_bits_le())).unwrap(); let p1Var = GVar::new_witness(cs.clone(), || Ok(p1)).unwrap(); let p2Var = GVar::new_witness(cs.clone(), || Ok(p2)).unwrap(); let p3Var = GVar::new_witness(cs.clone(), || Ok(p3)).unwrap(); // check ECRLC circuit ECRLC::::check(rbitsVar, p1Var, p2Var, p3Var).unwrap(); assert!(cs.is_satisfied().unwrap()); } }