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}