short_weierstrass/
projective.rs1use core::{hint::black_box, borrow::Borrow, ops::*, iter::Sum};
2
3use subtle::{Choice, ConstantTimeEq, ConditionallySelectable, ConditionallyNegatable};
4use zeroize::{Zeroize, DefaultIsZeroes};
5
6use rand_core::RngCore;
7
8use group::{
9 ff::{Field, PrimeFieldBits},
10 Group,
11};
12
13use crate::{ShortWeierstrass, Affine};
14
15#[derive(Debug)]
17pub struct Projective<C: ShortWeierstrass> {
18 pub(crate) x: C::FieldElement,
19 pub(crate) y: C::FieldElement,
20 pub(crate) z: C::FieldElement,
21}
22impl<C: ShortWeierstrass> Clone for Projective<C> {
23 fn clone(&self) -> Self {
24 *self
25 }
26}
27impl<C: ShortWeierstrass> Copy for Projective<C> {}
28
29impl<C: ShortWeierstrass> From<Affine<C>> for Projective<C> {
30 fn from(affine: Affine<C>) -> Self {
31 Self { x: affine.x, y: affine.y, z: C::FieldElement::ONE }
32 }
33}
34
35impl<C: ShortWeierstrass> Default for Projective<C> {
36 fn default() -> Self {
37 Self::IDENTITY
38 }
39}
40impl<C: ShortWeierstrass> DefaultIsZeroes for Projective<C> {}
41
42impl<C: ShortWeierstrass> ConstantTimeEq for Projective<C> {
43 fn ct_eq(&self, other: &Self) -> Choice {
44 let c1 = (self.x * other.z).ct_eq(&(other.x * self.z));
45 let c2 = (self.y * other.z).ct_eq(&(other.y * self.z));
46 c1 & c2
47 }
48}
49impl<C: ShortWeierstrass> PartialEq for Projective<C> {
50 fn eq(&self, other: &Self) -> bool {
51 self.ct_eq(other).into()
52 }
53}
54impl<C: ShortWeierstrass> Eq for Projective<C> {}
55
56impl<C: ShortWeierstrass> ConditionallySelectable for Projective<C> {
57 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
58 let x = C::FieldElement::conditional_select(&a.x, &b.x, choice);
59 let y = C::FieldElement::conditional_select(&a.y, &b.y, choice);
60 let z = C::FieldElement::conditional_select(&a.z, &b.z, choice);
61 Projective { x, y, z }
62 }
63}
64
65impl<C: ShortWeierstrass> Neg for Projective<C> {
66 type Output = Self;
67 fn neg(mut self) -> Self::Output {
68 self.y = -self.y;
69 self
70 }
71}
72
73impl<C: ShortWeierstrass> ConditionallyNegatable for Projective<C> {
74 fn conditional_negate(&mut self, negate: Choice) {
75 self.y = <_>::conditional_select(&self.y, &-self.y, negate);
76 }
77}
78
79impl<C: ShortWeierstrass> Add for Projective<C> {
80 type Output = Self;
81 fn add(self, p2: Self) -> Self {
87 let Self { x: X1, y: Y1, z: Z1 } = self;
88 let Self { x: X2, y: Y2, z: Z2 } = p2;
89
90 let Y1Z2 = Y1 * Z2;
91 let X1Z2 = X1 * Z2;
92 let Z1Z2 = Z1 * Z2;
93 let u = (Y2 * Z1) - Y1Z2;
94 let uu = u.square();
95 let v = (X2 * Z1) - X1Z2;
96 let vv = v.square();
97 let vvv = v * vv;
98 let R = vv * X1Z2;
99 let A = (uu * Z1Z2) - vvv - R.double();
100 let X3 = v * A;
101 let Y3 = (u * (R - A)) - (vvv * Y1Z2);
102 let Z3 = vvv * Z1Z2;
103
104 let res = Self { x: X3, y: Y3, z: Z3 };
105
106 let same_x_coordinate = (self.x * p2.z).ct_eq(&(p2.x * self.z));
107 let same_y_coordinate = (self.y * p2.z).ct_eq(&(p2.y * self.z));
108 let res = <_>::conditional_select(
109 &res,
110 &Self::IDENTITY,
111 (self.is_identity_internal() & p2.is_identity_internal()) |
112 (same_x_coordinate & (!same_y_coordinate)),
113 );
114 let res =
115 <_>::conditional_select(&res, &self.double_internal(), same_x_coordinate & same_y_coordinate);
116 let res = <_>::conditional_select(&res, &p2, self.is_identity_internal());
117 <_>::conditional_select(&res, &self, p2.is_identity_internal())
118 }
119}
120impl<C: ShortWeierstrass> Sub for Projective<C> {
121 type Output = Self;
122 fn sub(self, p2: Self) -> Self {
123 self + -p2
124 }
125}
126impl<C: ShortWeierstrass> AddAssign for Projective<C> {
127 fn add_assign(&mut self, p2: Self) {
128 *self = *self + p2;
129 }
130}
131impl<C: ShortWeierstrass> SubAssign for Projective<C> {
132 fn sub_assign(&mut self, p2: Self) {
133 *self = *self - p2;
134 }
135}
136impl<C: ShortWeierstrass> Add<&Self> for Projective<C> {
137 type Output = Self;
138 fn add(self, p2: &Self) -> Self {
139 self + *p2
140 }
141}
142impl<C: ShortWeierstrass> Sub<&Self> for Projective<C> {
143 type Output = Self;
144 fn sub(self, p2: &Self) -> Self {
145 self - *p2
146 }
147}
148impl<C: ShortWeierstrass> AddAssign<&Self> for Projective<C> {
149 fn add_assign(&mut self, p2: &Self) {
150 *self = *self + p2;
151 }
152}
153impl<C: ShortWeierstrass> SubAssign<&Self> for Projective<C> {
154 fn sub_assign(&mut self, p2: &Self) {
155 *self = *self - p2;
156 }
157}
158
159impl<C: ShortWeierstrass> Projective<C> {
160 pub const IDENTITY: Self =
162 Projective { x: C::FieldElement::ZERO, y: C::FieldElement::ONE, z: C::FieldElement::ZERO };
163 pub const GENERATOR: Self =
165 Projective { x: C::GENERATOR.x, y: C::GENERATOR.y, z: C::FieldElement::ONE };
166
167 fn is_identity_internal(&self) -> Choice {
168 self.z.ct_eq(&C::FieldElement::ZERO)
169 }
170
171 fn double_internal(&self) -> Self {
173 let Self { x: X1, y: Y1, z: Z1 } = *self;
174
175 let X1X1 = X1.square();
176 let w = (C::A * Z1.square()) + X1X1.double() + X1X1;
177 let s = Y1 * Z1;
178 let ss = s.square();
179 let sss = s * ss;
180 let R = Y1 * s;
181 let B = X1 * R;
182 let B4 = B.double().double();
183 let h = w.square() - B4.double();
184 let X3 = (h * s).double();
185 let Y3 = w * (B4 - h) - R.square().double().double().double();
186 let Z3 = sss.double().double().double();
187
188 let res = Self { x: X3, y: Y3, z: Z3 };
189 <_>::conditional_select(&res, &Self::IDENTITY, self.is_identity_internal())
190 }
191}
192
193impl<C: ShortWeierstrass> Sum for Projective<C> {
194 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
195 let mut res = Self::IDENTITY;
196 for item in iter {
197 res += item;
198 }
199 res
200 }
201}
202
203impl<'a, C: ShortWeierstrass> Sum<&'a Self> for Projective<C> {
204 fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
205 let mut res = Self::IDENTITY;
206 for item in iter {
207 res += item;
208 }
209 res
210 }
211}
212
213impl<C: ShortWeierstrass<Scalar = ()>> Projective<C> {
214 pub fn random(rng: impl RngCore) -> Self {
216 Self::from(Affine::random(rng))
217 }
218 pub fn is_identity(&self) -> Choice {
220 self.is_identity_internal()
221 }
222 pub fn double(&self) -> Self {
224 self.double_internal()
225 }
226}
227
228impl<C: ShortWeierstrass<Scalar: PrimeFieldBits>, S: Borrow<C::Scalar>> Mul<S> for Projective<C> {
229 type Output = Self;
230 fn mul(self, scalar: S) -> Self {
231 let mut table = [Self::IDENTITY; 16];
232 table[1] = self;
233 for i in 2 .. 16 {
234 table[i] = table[i - 1] + self;
235 }
236
237 let mut res = Self::identity();
238 let mut bits = 0;
239 for (i, mut bit) in scalar.borrow().to_le_bits().iter_mut().rev().enumerate() {
240 fn u8_from_bool(bit_ref: &mut bool) -> u8 {
241 let bit_ref = black_box(bit_ref);
242
243 let mut bit = black_box(*bit_ref);
244 let res = black_box(u8::from(bit));
245 bit.zeroize();
246 debug_assert!((res | 1) == 1);
247
248 bit_ref.zeroize();
249 res
250 }
251
252 bits <<= 1;
253 let mut bit = u8_from_bool(bit.deref_mut());
254 bits |= bit;
255 bit.zeroize();
256
257 if ((i + 1) % 4) == 0 {
258 if i != 3 {
259 for _ in 0 .. 4 {
260 res = res.double();
261 }
262 }
263
264 let mut term = table[0];
265 for (j, candidate) in table[1 ..].iter().enumerate() {
266 let j = j + 1;
267 term = Self::conditional_select(&term, candidate, usize::from(bits).ct_eq(&j));
268 }
269 res += term;
270 bits = 0;
271 }
272 }
273 res
274 }
275}
276impl<C: ShortWeierstrass<Scalar: PrimeFieldBits>, S: Borrow<C::Scalar>> MulAssign<S>
277 for Projective<C>
278{
279 fn mul_assign(&mut self, scalar: S) {
280 *self = *self * scalar.borrow();
281 }
282}
283impl<C: ShortWeierstrass<Scalar: PrimeFieldBits>> Group for Projective<C> {
297 type Scalar = C::Scalar;
298 fn random(rng: impl RngCore) -> Self {
299 Self::from(Affine::<C>::random(rng))
300 }
301 fn identity() -> Self {
302 Self::IDENTITY
303 }
304 fn generator() -> Self {
305 C::GENERATOR.into()
306 }
307 fn is_identity(&self) -> Choice {
308 self.is_identity_internal()
309 }
310 fn double(&self) -> Self {
311 self.double_internal()
312 }
313}