arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/folding-schemes/src/folding/circuits/nonnative.rs
folding-schemes/src/folding/circuits/nonnative.rsRaw
  1use ark_ec::{AffineRepr, CurveGroup};
  2use ark_r1cs_std::fields::nonnative::{params::OptimizationType, AllocatedNonNativeFieldVar};
  3use ark_r1cs_std::{
  4    alloc::{AllocVar, AllocationMode},
  5    fields::nonnative::NonNativeFieldVar,
  6};
  7use ark_relations::r1cs::{Namespace, SynthesisError};
  8use ark_std::{One, Zero};
  9use core::borrow::Borrow;
 10
 11/// NonNativeAffineVar represents an elliptic curve point in Affine representation in the non-native
 12/// field, over the constraint field. It is not intended to perform operations, but just to contain
 13/// the affine coordinates in order to perform hash operations of the point.
 14#[derive(Debug, Clone)]
 15pub struct NonNativeAffineVar<C: CurveGroup>
 16where
 17    <C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
 18{
 19    pub x: NonNativeFieldVar<C::BaseField, C::ScalarField>,
 20    pub y: NonNativeFieldVar<C::BaseField, C::ScalarField>,
 21}
 22
 23impl<C> AllocVar<C, C::ScalarField> for NonNativeAffineVar<C>
 24where
 25    C: CurveGroup,
 26    <C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
 27{
 28    fn new_variable<T: Borrow<C>>(
 29        cs: impl Into<Namespace<C::ScalarField>>,
 30        f: impl FnOnce() -> Result<T, SynthesisError>,
 31        mode: AllocationMode,
 32    ) -> Result<Self, SynthesisError> {
 33        f().and_then(|val| {
 34            let cs = cs.into();
 35
 36            let affine = val.borrow().into_affine();
 37            let zero_point = (&C::BaseField::zero(), &C::BaseField::one());
 38            let xy = affine.xy().unwrap_or(zero_point);
 39
 40            let x = NonNativeFieldVar::<C::BaseField, C::ScalarField>::new_variable(
 41                cs.clone(),
 42                || Ok(xy.0),
 43                mode,
 44            )?;
 45            let y = NonNativeFieldVar::<C::BaseField, C::ScalarField>::new_variable(
 46                cs.clone(),
 47                || Ok(xy.1),
 48                mode,
 49            )?;
 50
 51            Ok(Self { x, y })
 52        })
 53    }
 54}
 55
 56/// Wrapper on top of [`point_to_nonnative_limbs_custom_opt`] which always uses
 57/// [`OptimizationType::Weight`].
 58#[allow(clippy::type_complexity)]
 59pub fn point_to_nonnative_limbs<C: CurveGroup>(
 60    p: C,
 61) -> Result<(Vec<C::ScalarField>, Vec<C::ScalarField>), SynthesisError>
 62where
 63    <C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
 64{
 65    point_to_nonnative_limbs_custom_opt(p, OptimizationType::Weight)
 66}
 67
 68/// Used to compute (outside the circuit) the limbs representation of a point that matches the one
 69/// used in-circuit, and in particular this method allows to specify which [`OptimizationType`] to
 70/// use.
 71#[allow(clippy::type_complexity)]
 72pub fn point_to_nonnative_limbs_custom_opt<C: CurveGroup>(
 73    p: C,
 74    optimization_type: OptimizationType,
 75) -> Result<(Vec<C::ScalarField>, Vec<C::ScalarField>), SynthesisError>
 76where
 77    <C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
 78{
 79    let affine = p.into_affine();
 80    if affine.is_zero() {
 81        let x =
 82            AllocatedNonNativeFieldVar::<C::BaseField, C::ScalarField>::get_limbs_representations(
 83                &C::BaseField::zero(),
 84                optimization_type,
 85            )?;
 86        let y =
 87            AllocatedNonNativeFieldVar::<C::BaseField, C::ScalarField>::get_limbs_representations(
 88                &C::BaseField::one(),
 89                optimization_type,
 90            )?;
 91        return Ok((x, y));
 92    }
 93
 94    let (x, y) = affine.xy().unwrap();
 95    let x = AllocatedNonNativeFieldVar::<C::BaseField, C::ScalarField>::get_limbs_representations(
 96        x,
 97        optimization_type,
 98    )?;
 99    let y = AllocatedNonNativeFieldVar::<C::BaseField, C::ScalarField>::get_limbs_representations(
100        y,
101        optimization_type,
102    )?;
103    Ok((x, y))
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109    use ark_pallas::{Fr, Projective};
110    use ark_r1cs_std::{alloc::AllocVar, R1CSVar, ToConstraintFieldGadget};
111    use ark_relations::r1cs::ConstraintSystem;
112    use ark_std::{UniformRand, Zero};
113
114    #[test]
115    fn test_alloc_nonnativeaffinevar() {
116        let cs = ConstraintSystem::<Fr>::new_ref();
117
118        // dealing with the 'zero' point should not panic when doing the unwrap
119        let p = Projective::zero();
120        NonNativeAffineVar::<Projective>::new_witness(cs.clone(), || Ok(p)).unwrap();
121
122        // check that point_to_nonnative_limbs returns the expected values
123        let mut rng = ark_std::test_rng();
124        let p = Projective::rand(&mut rng);
125        let pVar = NonNativeAffineVar::<Projective>::new_witness(cs.clone(), || Ok(p)).unwrap();
126        let (x, y) = point_to_nonnative_limbs(p).unwrap();
127        assert_eq!(pVar.x.to_constraint_field().unwrap().value().unwrap(), x);
128        assert_eq!(pVar.y.to_constraint_field().unwrap().value().unwrap(), y);
129    }
130}