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