openzeppelin_crypto/curve/te/
affine.rs1use core::{
5 borrow::Borrow,
6 fmt::{Debug, Display, Formatter},
7 ops::{Add, Mul, Neg, Sub},
8};
9
10use educe::Educe;
11use num_traits::{One, Zero};
12use zeroize::Zeroize;
13
14use super::{Projective, TECurveConfig};
15use crate::{
16 bits::BitIteratorBE,
17 curve::AffineRepr,
18 field::{group::AdditiveGroup, prime::PrimeField, Field},
19};
20
21#[derive(Educe)]
24#[educe(Copy, Clone, PartialEq, Eq, Hash)]
25#[must_use]
26pub struct Affine<P: TECurveConfig> {
27 pub x: P::BaseField,
29 pub y: P::BaseField,
31}
32
33impl<P: TECurveConfig> Display for Affine<P> {
34 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
35 if self.is_zero() {
36 write!(f, "infinity")
37 } else {
38 write!(f, "({}, {})", self.x, self.y)
39 }
40 }
41}
42
43impl<P: TECurveConfig> Debug for Affine<P> {
44 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
45 if self.is_zero() {
46 write!(f, "infinity")
47 } else {
48 write!(f, "({}, {})", self.x, self.y)
49 }
50 }
51}
52
53impl<P: TECurveConfig> PartialEq<Projective<P>> for Affine<P> {
54 fn eq(&self, other: &Projective<P>) -> bool {
55 &self.into_group() == other
56 }
57}
58
59impl<P: TECurveConfig> Affine<P> {
60 pub const fn new_unchecked(x: P::BaseField, y: P::BaseField) -> Self {
63 Self { x, y }
64 }
65
66 pub fn new(x: P::BaseField, y: P::BaseField) -> Self {
74 let p = Self::new_unchecked(x, y);
75 assert!(p.is_on_curve());
76 assert!(p.is_in_prime_order_subgroup());
77 p
78 }
79
80 pub const fn zero() -> Self {
82 Self::new_unchecked(P::BaseField::ZERO, P::BaseField::ONE)
83 }
84
85 pub fn is_zero(&self) -> bool {
87 self.x.is_zero() && self.y.is_one()
88 }
89
90 pub fn is_on_curve(&self) -> bool {
92 let x2 = self.x.square();
93 let y2 = self.y.square();
94
95 let lhs = y2 + P::mul_by_a(x2);
96 let rhs = P::BaseField::one() + (P::COEFF_D * (x2 * y2));
97
98 lhs == rhs
99 }
100}
101
102impl<P: TECurveConfig> Affine<P> {
103 pub fn is_in_prime_order_subgroup(&self) -> bool {
108 P::is_in_prime_order_subgroup(self)
109 }
110}
111
112impl<P: TECurveConfig> AffineRepr for Affine<P> {
113 type BaseField = P::BaseField;
114 type Config = P;
115 type Group = Projective<P>;
116 type ScalarField = P::ScalarField;
117
118 fn xy(&self) -> Option<(Self::BaseField, Self::BaseField)> {
119 (!self.is_zero()).then_some((self.x, self.y))
120 }
121
122 fn generator() -> Self {
123 P::GENERATOR
124 }
125
126 fn zero() -> Self {
127 Self::new_unchecked(P::BaseField::ZERO, P::BaseField::ONE)
128 }
129
130 fn mul_bigint(&self, by: impl BitIteratorBE) -> Self::Group {
131 P::mul_affine(self, by)
132 }
133
134 fn mul_by_cofactor_to_group(&self) -> Self::Group {
137 P::mul_affine(self, Self::Config::COFACTOR)
138 }
139
140 fn clear_cofactor(&self) -> Self {
144 P::clear_cofactor(self)
145 }
146}
147
148impl<P: TECurveConfig> Zeroize for Affine<P> {
149 fn zeroize(&mut self) {
150 self.x.zeroize();
151 self.y.zeroize();
152 }
153}
154
155impl<P: TECurveConfig> Neg for Affine<P> {
156 type Output = Self;
157
158 fn neg(self) -> Self {
159 Self::new_unchecked(-self.x, self.y)
160 }
161}
162
163impl<P: TECurveConfig, T: Borrow<Self>> Add<T> for Affine<P> {
164 type Output = Projective<P>;
165
166 fn add(self, other: T) -> Self::Output {
167 let mut copy = self.into_group();
168 copy += other.borrow();
169 copy
170 }
171}
172
173impl<P: TECurveConfig> Add<Projective<P>> for Affine<P> {
174 type Output = Projective<P>;
175
176 fn add(self, other: Projective<P>) -> Projective<P> {
177 other + self
178 }
179}
180
181impl<'a, P: TECurveConfig> Add<&'a Projective<P>> for Affine<P> {
182 type Output = Projective<P>;
183
184 fn add(self, other: &'a Projective<P>) -> Projective<P> {
185 *other + self
186 }
187}
188
189impl<P: TECurveConfig, T: Borrow<Self>> Sub<T> for Affine<P> {
190 type Output = Projective<P>;
191
192 fn sub(self, other: T) -> Self::Output {
193 let mut copy = self.into_group();
194 copy -= other.borrow();
195 copy
196 }
197}
198
199impl<P: TECurveConfig> Sub<Projective<P>> for Affine<P> {
200 type Output = Projective<P>;
201
202 fn sub(self, other: Projective<P>) -> Projective<P> {
203 self + (-other)
204 }
205}
206
207impl<'a, P: TECurveConfig> Sub<&'a Projective<P>> for Affine<P> {
208 type Output = Projective<P>;
209
210 fn sub(self, other: &'a Projective<P>) -> Projective<P> {
211 self + (-*other)
212 }
213}
214
215impl<P: TECurveConfig> Default for Affine<P> {
216 #[inline]
217 fn default() -> Self {
218 Self::zero()
219 }
220}
221
222impl<P: TECurveConfig, T: Borrow<P::ScalarField>> Mul<T> for Affine<P> {
223 type Output = Projective<P>;
224
225 #[inline]
226 fn mul(self, other: T) -> Self::Output {
227 self.mul_bigint(other.borrow().into_bigint())
228 }
229}
230
231impl<P: TECurveConfig> From<Projective<P>> for Affine<P> {
234 fn from(p: Projective<P>) -> Affine<P> {
235 if p.is_zero() {
236 Affine::zero()
237 } else if p.z.is_one() {
238 Affine::new_unchecked(p.x, p.y)
240 } else {
241 let z_inv =
244 p.z.inverse()
245 .expect("projective Z coordinate should not be zero");
246 let x = p.x * z_inv;
247 let y = p.y * z_inv;
248 Affine::new_unchecked(x, y)
249 }
250 }
251}