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}