openzeppelin_crypto/curve/sw/
affine.rs

1//! Affine coordinates for a point on a Short Weierstrass curve
2//! ([Affine Space]).
3//!
4//! [Affine Space]: https://en.wikipedia.org/wiki/Affine_space
5
6use core::{
7    borrow::Borrow,
8    fmt::{Debug, Display, Formatter},
9    ops::{Add, Mul, Neg, Sub},
10};
11
12use educe::Educe;
13use num_traits::{One, Zero};
14use zeroize::Zeroize;
15
16use super::{Projective, SWCurveConfig};
17use crate::{
18    bits::BitIteratorBE,
19    curve::AffineRepr,
20    field::{group::AdditiveGroup, prime::PrimeField, Field},
21};
22
23/// Affine coordinates for a point on an elliptic curve in short Weierstrass
24/// form, over the base field `P::BaseField`.
25#[derive(Educe)]
26#[educe(Copy, Clone, PartialEq, Eq, Hash)]
27#[must_use]
28pub struct Affine<P: SWCurveConfig> {
29    #[doc(hidden)]
30    pub x: P::BaseField,
31    #[doc(hidden)]
32    pub y: P::BaseField,
33    #[doc(hidden)]
34    pub infinity: bool,
35}
36
37impl<P: SWCurveConfig> PartialEq<Projective<P>> for Affine<P> {
38    fn eq(&self, other: &Projective<P>) -> bool {
39        self.into_group() == *other
40    }
41}
42
43impl<P: SWCurveConfig> Display for Affine<P> {
44    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
45        if self.infinity {
46            write!(f, "infinity")
47        } else {
48            write!(f, "({}, {})", self.x, self.y)
49        }
50    }
51}
52
53impl<P: SWCurveConfig> Debug for Affine<P> {
54    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
55        if self.infinity {
56            write!(f, "infinity")
57        } else {
58            write!(f, "({}, {})", self.x, self.y)
59        }
60    }
61}
62
63impl<P: SWCurveConfig> Affine<P> {
64    /// Constructs a group element from `x` and `y` coordinates.
65    /// Performs checks to ensure that the point is on the curve and is in the
66    /// right subgroup.
67    ///
68    /// # Panics
69    ///
70    /// * If point is not on curve.
71    /// * If point is not in the prime-order subgroup.
72    pub fn new(x: P::BaseField, y: P::BaseField) -> Self {
73        let point = Self { x, y, infinity: false };
74        assert!(point.is_on_curve());
75        assert!(point.is_in_prime_order_subgroup());
76        point
77    }
78
79    /// Constructs a group element from `x` and `y` coordinates.
80    ///
81    /// # Warning
82    ///
83    /// Does *not* perform any checks to ensure the point is in the curve or
84    /// is in the right subgroup.
85    pub const fn new_unchecked(x: P::BaseField, y: P::BaseField) -> Self {
86        Self { x, y, infinity: false }
87    }
88
89    /// Additive identity element of the curve group.
90    pub const fn identity() -> Self {
91        Self { x: P::BaseField::ZERO, y: P::BaseField::ZERO, infinity: true }
92    }
93
94    /// Checks if `self` is a valid point on the curve.
95    pub fn is_on_curve(&self) -> bool {
96        if self.infinity {
97            return true;
98        }
99
100        let mut x3b = P::add_b(self.x.square() * self.x);
101        // Optimise addition with zero.
102        if !P::COEFF_A.is_zero() {
103            x3b += P::mul_by_a(self.x);
104        }
105        self.y.square() == x3b
106    }
107}
108
109impl<P: SWCurveConfig> Affine<P> {
110    /// Checks if `self` is in the subgroup having order that equaling that of
111    /// `P::ScalarField`.
112    // DISCUSS Maybe these function names are too verbose?
113    pub fn is_in_prime_order_subgroup(&self) -> bool {
114        P::is_in_prime_order_subgroup(self)
115    }
116}
117
118impl<P: SWCurveConfig> Zeroize for Affine<P> {
119    fn zeroize(&mut self) {
120        self.x.zeroize();
121        self.y.zeroize();
122        self.infinity.zeroize();
123    }
124}
125
126impl<P: SWCurveConfig> AffineRepr for Affine<P> {
127    type BaseField = P::BaseField;
128    type Config = P;
129    type Group = Projective<P>;
130    type ScalarField = P::ScalarField;
131
132    fn xy(&self) -> Option<(Self::BaseField, Self::BaseField)> {
133        (!self.infinity).then_some((self.x, self.y))
134    }
135
136    #[inline]
137    fn generator() -> Self {
138        P::GENERATOR
139    }
140
141    fn zero() -> Self {
142        Self { x: P::BaseField::ZERO, y: P::BaseField::ZERO, infinity: true }
143    }
144
145    fn mul_bigint(&self, by: impl BitIteratorBE) -> Self::Group {
146        P::mul_affine(self, by)
147    }
148
149    /// Multiplies this element by the cofactor and output the
150    /// resulting projective element.
151    fn mul_by_cofactor_to_group(&self) -> Self::Group {
152        P::mul_affine(self, Self::Config::COFACTOR)
153    }
154
155    /// Performs cofactor clearing.
156    /// The default method is simply to multiply by the cofactor.
157    /// Some curves can implement a more efficient algorithm.
158    fn clear_cofactor(&self) -> Self {
159        P::clear_cofactor(self)
160    }
161}
162
163impl<P: SWCurveConfig> Neg for Affine<P> {
164    type Output = Self;
165
166    /// If `self.is_zero()`, returns `self` (`== Self::zero()`).
167    /// Else, returns `(x, -y)`, where `self = (x, y)`.
168    #[inline]
169    fn neg(mut self) -> Self {
170        self.y.neg_in_place();
171        self
172    }
173}
174
175impl<P: SWCurveConfig, T: Borrow<Self>> Add<T> for Affine<P> {
176    type Output = Projective<P>;
177
178    fn add(self, other: T) -> Projective<P> {
179        let mut copy = self.into_group();
180        copy += other.borrow();
181        copy
182    }
183}
184
185impl<P: SWCurveConfig> Add<Projective<P>> for Affine<P> {
186    type Output = Projective<P>;
187
188    fn add(self, other: Projective<P>) -> Projective<P> {
189        other + self
190    }
191}
192
193impl<'a, P: SWCurveConfig> Add<&'a Projective<P>> for Affine<P> {
194    type Output = Projective<P>;
195
196    fn add(self, other: &'a Projective<P>) -> Projective<P> {
197        *other + self
198    }
199}
200
201impl<P: SWCurveConfig, T: Borrow<Self>> Sub<T> for Affine<P> {
202    type Output = Projective<P>;
203
204    fn sub(self, other: T) -> Projective<P> {
205        let mut copy = self.into_group();
206        copy -= other.borrow();
207        copy
208    }
209}
210
211impl<P: SWCurveConfig> Sub<Projective<P>> for Affine<P> {
212    type Output = Projective<P>;
213
214    fn sub(self, other: Projective<P>) -> Projective<P> {
215        self + (-other)
216    }
217}
218
219impl<'a, P: SWCurveConfig> Sub<&'a Projective<P>> for Affine<P> {
220    type Output = Projective<P>;
221
222    fn sub(self, other: &'a Projective<P>) -> Projective<P> {
223        self + (-*other)
224    }
225}
226
227impl<P: SWCurveConfig> Default for Affine<P> {
228    #[inline]
229    fn default() -> Self {
230        Self::identity()
231    }
232}
233
234impl<P: SWCurveConfig, T: Borrow<P::ScalarField>> Mul<T> for Affine<P> {
235    type Output = Projective<P>;
236
237    #[inline]
238    fn mul(self, other: T) -> Self::Output {
239        self.mul_bigint(other.borrow().into_bigint())
240    }
241}
242
243// The projective point X, Y, Z is represented in the affine
244// coordinates as X/Z^2, Y/Z^3.
245impl<P: SWCurveConfig> From<Projective<P>> for Affine<P> {
246    #[inline]
247    fn from(p: Projective<P>) -> Affine<P> {
248        if p.is_zero() {
249            Affine::identity()
250        } else if p.z.is_one() {
251            // If Z is one, the point is already normalized.
252            Affine::new_unchecked(p.x, p.y)
253        } else {
254            // Z is nonzero, so it must have an inverse in a field.
255            let zinv = p.z.inverse().unwrap();
256            let zinv_squared = zinv.square();
257
258            // X/Z^2
259            let x = p.x * zinv_squared;
260
261            // Y/Z^3
262            let y = p.y * zinv_squared * zinv;
263
264            Affine::new_unchecked(x, y)
265        }
266    }
267}