arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/src/groups/curves/short_weierstrass/non_zero_affine.rs
src/groups/curves/short_weierstrass/non_zero_affine.rsRaw
  1use super::*;
  2/// An affine representation of a prime order curve point that is guaranteed
  3/// to *not* be the point at infinity.
  4#[derive(Derivative)]
  5#[derivative(Debug, Clone)]
  6#[must_use]
  7pub struct NonZeroAffineVar<
  8    P: SWModelParameters,
  9    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
 10> where
 11    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
 12{
 13    /// The x-coordinate.
 14    pub x: F,
 15    /// The y-coordinate.
 16    pub y: F,
 17    #[derivative(Debug = "ignore")]
 18    _params: PhantomData<P>,
 19}
 20
 21impl<P, F> NonZeroAffineVar<P, F>
 22where
 23    P: SWModelParameters,
 24    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
 25    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
 26{
 27    pub(crate) fn new(x: F, y: F) -> Self {
 28        Self {
 29            x,
 30            y,
 31            _params: PhantomData,
 32        }
 33    }
 34
 35    /// Converts self into a non-zero projective point.
 36    #[tracing::instrument(target = "r1cs", skip(self))]
 37    pub(crate) fn into_projective(&self) -> ProjectiveVar<P, F> {
 38        ProjectiveVar::new(self.x.clone(), self.y.clone(), F::one())
 39    }
 40
 41    /// Performs an addition without checking that other != ±self.
 42    #[tracing::instrument(target = "r1cs", skip(self, other))]
 43    pub(crate) fn add_unchecked(&self, other: &Self) -> Result<Self, SynthesisError> {
 44        if [self, other].is_constant() {
 45            let result =
 46                (self.value()?.into_projective() + other.value()?.into_projective()).into_affine();
 47            Ok(Self::new(F::constant(result.x), F::constant(result.y)))
 48        } else {
 49            let (x1, y1) = (&self.x, &self.y);
 50            let (x2, y2) = (&other.x, &other.y);
 51            // Then,
 52            // slope lambda := (y2 - y1)/(x2 - x1);
 53            // x3 = lambda^2 - x1 - x2;
 54            // y3 = lambda * (x1 - x3) - y1
 55            let numerator = y2 - y1;
 56            let denominator = x2 - x1;
 57            let lambda = numerator.mul_by_inverse(&denominator)?;
 58            let x3 = lambda.square()? - x1 - x2;
 59            let y3 = lambda * &(x1 - &x3) - y1;
 60            Ok(Self::new(x3, y3))
 61        }
 62    }
 63
 64    /// Doubles `self`. As this is a prime order curve point,
 65    /// the output is guaranteed to not be the point at infinity.
 66    #[tracing::instrument(target = "r1cs", skip(self))]
 67    pub(crate) fn double(&self) -> Result<Self, SynthesisError> {
 68        if [self].is_constant() {
 69            let result = self.value()?.into_projective().double().into_affine();
 70            // Panic if the result is zero.
 71            assert!(!result.is_zero());
 72            Ok(Self::new(F::constant(result.x), F::constant(result.y)))
 73        } else {
 74            let (x1, y1) = (&self.x, &self.y);
 75            let x1_sqr = x1.square()?;
 76            // Then,
 77            // tangent lambda := (3 * x1^2 + a) / y1·;
 78            // x3 = lambda^2 - 2x1
 79            // y3 = lambda * (x1 - x3) - y1
 80            let numerator = x1_sqr.double()? + &x1_sqr + P::COEFF_A;
 81            let denominator = y1.double()?;
 82            let lambda = numerator.mul_by_inverse(&denominator)?;
 83            let x3 = lambda.square()? - x1.double()?;
 84            let y3 = lambda * &(x1 - &x3) - y1;
 85            Ok(Self::new(x3, y3))
 86        }
 87    }
 88
 89    /// Doubles `self` in place.
 90    #[tracing::instrument(target = "r1cs", skip(self))]
 91    pub(crate) fn double_in_place(&mut self) -> Result<(), SynthesisError> {
 92        *self = self.double()?;
 93        Ok(())
 94    }
 95}
 96
 97impl<P, F> R1CSVar<<P::BaseField as Field>::BasePrimeField> for NonZeroAffineVar<P, F>
 98where
 99    P: SWModelParameters,
100    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
101    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
102{
103    type Value = SWAffine<P>;
104
105    fn cs(&self) -> ConstraintSystemRef<<P::BaseField as Field>::BasePrimeField> {
106        self.x.cs().or(self.y.cs())
107    }
108
109    fn value(&self) -> Result<SWAffine<P>, SynthesisError> {
110        Ok(SWAffine::new(self.x.value()?, self.y.value()?, false))
111    }
112}
113
114impl<P, F> CondSelectGadget<<P::BaseField as Field>::BasePrimeField> for NonZeroAffineVar<P, F>
115where
116    P: SWModelParameters,
117    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
118    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
119{
120    #[inline]
121    #[tracing::instrument(target = "r1cs")]
122    fn conditionally_select(
123        cond: &Boolean<<P::BaseField as Field>::BasePrimeField>,
124        true_value: &Self,
125        false_value: &Self,
126    ) -> Result<Self, SynthesisError> {
127        let x = cond.select(&true_value.x, &false_value.x)?;
128        let y = cond.select(&true_value.y, &false_value.y)?;
129
130        Ok(Self::new(x, y))
131    }
132}