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