lambdaworks_math/elliptic_curve/
point.rs1use crate::elliptic_curve::traits::IsEllipticCurve;
2use crate::field::element::FieldElement;
3use core::fmt::Debug;
4#[derive(Debug, Clone)]
8pub struct ProjectivePoint<E: IsEllipticCurve> {
9 pub value: [FieldElement<E::BaseField>; 3],
10}
11
12impl<E: IsEllipticCurve> ProjectivePoint<E> {
13 pub const fn new(value: [FieldElement<E::BaseField>; 3]) -> Self {
15 Self { value }
16 }
17
18 pub fn x(&self) -> &FieldElement<E::BaseField> {
20 &self.value[0]
21 }
22
23 pub fn y(&self) -> &FieldElement<E::BaseField> {
25 &self.value[1]
26 }
27
28 pub fn z(&self) -> &FieldElement<E::BaseField> {
30 &self.value[2]
31 }
32
33 pub fn coordinates(&self) -> &[FieldElement<E::BaseField>; 3] {
35 &self.value
36 }
37
38 pub fn to_affine(&self) -> Self {
42 let [x, y, z] = self.coordinates();
43 if z == &FieldElement::zero() {
45 return Self::new([
47 FieldElement::zero(),
48 FieldElement::one(),
49 FieldElement::zero(),
50 ]);
51 };
52 let inv_z = z.inv().unwrap();
53 ProjectivePoint::new([x * &inv_z, y * inv_z, FieldElement::one()])
54 }
55}
56
57impl<E: IsEllipticCurve> PartialEq for ProjectivePoint<E> {
58 fn eq(&self, other: &Self) -> bool {
59 let [px, py, pz] = self.coordinates();
60 let [qx, qy, qz] = other.coordinates();
61 (px * qz == pz * qx) && (py * qz == qy * pz)
62 }
63}
64
65impl<E: IsEllipticCurve> Eq for ProjectivePoint<E> {}
66#[derive(Debug, Clone)]
67
68pub struct JacobianPoint<E: IsEllipticCurve> {
69 pub value: [FieldElement<E::BaseField>; 3],
70}
71
72impl<E: IsEllipticCurve> JacobianPoint<E> {
73 pub const fn new(value: [FieldElement<E::BaseField>; 3]) -> Self {
75 Self { value }
76 }
77
78 pub fn x(&self) -> &FieldElement<E::BaseField> {
80 &self.value[0]
81 }
82
83 pub fn y(&self) -> &FieldElement<E::BaseField> {
85 &self.value[1]
86 }
87
88 pub fn z(&self) -> &FieldElement<E::BaseField> {
90 &self.value[2]
91 }
92
93 pub fn coordinates(&self) -> &[FieldElement<E::BaseField>; 3] {
95 &self.value
96 }
97
98 pub fn to_affine(&self) -> Self {
99 let [x, y, z] = self.coordinates();
100 if z == &FieldElement::zero() {
102 return Self::new([
104 FieldElement::one(),
105 FieldElement::one(),
106 FieldElement::zero(),
107 ]);
108 };
109 let inv_z = z.inv().unwrap();
110 let inv_z_square = inv_z.square();
111 let inv_z_cube = &inv_z_square * &inv_z;
112 JacobianPoint::new([x * inv_z_square, y * inv_z_cube, FieldElement::one()])
113 }
114}
115
116impl<E: IsEllipticCurve> PartialEq for JacobianPoint<E> {
117 fn eq(&self, other: &Self) -> bool {
118 let [px, py, pz] = self.coordinates();
122 let [qx, qy, qz] = other.coordinates();
123
124 let zp_sq = pz.square();
125 let zq_sq = qz.square();
126
127 let zp_cu = &zp_sq * pz;
128 let zq_cu = &zq_sq * qz;
129
130 let xp_zq_sq = px * zq_sq;
131 let xq_zp_sq = qx * zp_sq;
132
133 let yp_zq_cu = py * zq_cu;
134 let yq_zp_cu = qy * zp_cu;
135
136 (xp_zq_sq == xq_zp_sq) && (yp_zq_cu == yq_zp_cu)
137 }
138}
139impl<E: IsEllipticCurve> Eq for JacobianPoint<E> {}
140#[cfg(test)]
141mod tests {
142 use crate::cyclic_group::IsGroup;
143 use crate::elliptic_curve::short_weierstrass::curves::test_curve_1::{
144 TestCurve1, TestCurvePrimeField, TestCurveQuadraticNonResidue,
145 TEST_CURVE_1_MAIN_SUBGROUP_ORDER,
146 };
147 use crate::elliptic_curve::short_weierstrass::curves::test_curve_2::TestCurve2;
148 use crate::field::element::FieldElement;
149 use crate::unsigned_integer::element::U384;
150 use crate::elliptic_curve::traits::{EllipticCurveError, IsEllipticCurve};
152 use crate::field::extensions::quadratic::QuadraticExtensionFieldElement;
153
154 #[allow(clippy::upper_case_acronyms)]
155 type FEE = QuadraticExtensionFieldElement<TestCurvePrimeField, TestCurveQuadraticNonResidue>;
156
157 #[test]
159 fn create_valid_point_works() {
160 let point = TestCurve1::create_point_from_affine(FEE::from(35), FEE::from(31)).unwrap();
161 assert_eq!(*point.x(), FEE::from(35));
162 assert_eq!(*point.y(), FEE::from(31));
163 assert_eq!(*point.z(), FEE::from(1));
164 }
165
166 #[test]
167 fn create_invalid_points_panics() {
168 let a = TestCurve1::create_point_from_affine(FEE::from(0), FEE::from(1));
169 assert_eq!(EllipticCurveError::InvalidPoint, a.unwrap_err());
170 }
171
172 #[test]
173 fn equality_works() {
174 let g = TestCurve1::generator();
175 let g2 = g.operate_with(&g);
176 assert_ne!(&g2, &g);
177 assert_eq!(&g, &g);
178 }
179
180 #[test]
181 fn operate_with_self_works_1() {
182 let g = TestCurve1::generator();
183 assert_eq!(
184 g.operate_with(&g).operate_with(&g),
185 g.operate_with_self(3_u16)
186 );
187 }
188
189 #[test]
190 fn operate_with_self_works_2() {
191 let mut point_1 = TestCurve1::generator();
192 point_1 = point_1.operate_with_self(TEST_CURVE_1_MAIN_SUBGROUP_ORDER as u128);
193 assert!(point_1.is_neutral_element());
194 }
195
196 #[test]
197 fn doubling_a_point_works() {
198 let point = TestCurve1::create_point_from_affine(FEE::from(35), FEE::from(31)).unwrap();
199 let expected_result =
200 TestCurve1::create_point_from_affine(FEE::from(25), FEE::from(29)).unwrap();
201 assert_eq!(point.operate_with_self(2_u16).to_affine(), expected_result);
202 }
203
204 #[test]
205 fn operate_with_self_works_with_test_curve_2() {
206 let mut point_1 = TestCurve2::generator();
207 point_1 = point_1.operate_with_self(15_u16);
208
209 let expected_result = TestCurve2::create_point_from_affine(
210 FieldElement::new([
211 FieldElement::new(U384::from_hex_unchecked(
212 "7b8ee59e422e702458174c18eb3302e17",
213 )),
214 FieldElement::new(U384::from_hex_unchecked(
215 "1395065adef5a6a5457f1ea600b5a3e4fb",
216 )),
217 ]),
218 FieldElement::new([
219 FieldElement::new(U384::from_hex_unchecked(
220 "e29d5b15c42124cd8f05d3c8500451c33",
221 )),
222 FieldElement::new(U384::from_hex_unchecked(
223 "e836ef62db0a47a63304b67c0de69b140",
224 )),
225 ]),
226 )
227 .unwrap();
228
229 assert_eq!(point_1, expected_result);
230 }
231
232 #[test]
233 fn coordinate_getters_work() {
234 let x = FEE::from(35);
235 let y = FEE::from(31);
236 let z = FEE::from(1);
237 let point = TestCurve1::create_point_from_affine(x.clone(), y.clone()).unwrap();
238 let coordinates = point.coordinates();
239 assert_eq!(&x, point.x());
240 assert_eq!(&y, point.y());
241 assert_eq!(&z, point.z());
242 assert_eq!(x, coordinates[0]);
243 assert_eq!(y, coordinates[1]);
244 assert_eq!(z, coordinates[2]);
245 }
246}