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