Skip to content

Commit f984fb0

Browse files
feat: create new AffinePoint from the compressed point representation (#127)
Co-authored-by: Gabriel Bosio <[email protected]>
1 parent 6e5b6be commit f984fb0

File tree

1 file changed

+50
-0
lines changed

1 file changed

+50
-0
lines changed

crates/starknet-types-core/src/curve/affine_point.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use lambdaworks_math::{
44
elliptic_curve::{
55
short_weierstrass::{
66
curves::stark_curve::StarkCurve, point::ShortWeierstrassProjectivePoint,
7+
traits::IsShortWeierstrass,
78
},
89
traits::{FromAffine, IsEllipticCurve},
910
},
@@ -33,6 +34,28 @@ impl AffinePoint {
3334
]))
3435
}
3536

37+
/// Construct new affine point from the `x` coordinate and the parity bit `y_parity`.
38+
/// If `y_parity` is false, choose the y-coordinate with even parity.
39+
/// If `y_parity` is true, choose the y-coordinate with odd parity.
40+
pub fn new_from_x(x: &Felt, y_parity: bool) -> Option<Self> {
41+
// right hand side of the stark curve equation `y^2 = x^3 + α*x + β (mod p)`.
42+
let rhs = x * x * x + Felt(StarkCurve::a()) * x + Felt(StarkCurve::b());
43+
44+
let (root_1, root_2) = rhs.0.sqrt()?;
45+
46+
let root_1_le_bits = root_1.to_bits_le();
47+
let first_bit = root_1_le_bits.first()?;
48+
49+
let y = if *first_bit == y_parity {
50+
root_1
51+
} else {
52+
root_2
53+
};
54+
55+
// the curve equation is already satisfied above and is safe to create a new unchecked point
56+
Some(Self::new_unchecked(*x, Felt(y)))
57+
}
58+
3659
/// The point at infinity.
3760
pub fn identity() -> AffinePoint {
3861
Self(ShortWeierstrassProjectivePoint::neutral_element())
@@ -86,6 +109,7 @@ impl core::ops::Mul<Felt> for &AffinePoint {
86109
#[cfg(test)]
87110
mod test {
88111
use super::*;
112+
use std::ops::Neg;
89113

90114
#[test]
91115
fn affine_point_new_unchecked() {
@@ -191,4 +215,30 @@ mod test {
191215
.unwrap()
192216
);
193217
}
218+
219+
#[test]
220+
fn affine_new_from_x_odd() {
221+
let p = AffinePoint::new(
222+
Felt::from_hex_unchecked("0x2d39148a92f479fb077389d"),
223+
Felt::from_hex_unchecked(
224+
"0x6e5d97edf7283fe7a7fe9deef2619224f42cb1bd531dd23380ad066c61ee20b",
225+
),
226+
)
227+
.unwrap();
228+
229+
assert_eq!(p, AffinePoint::new_from_x(&p.x(), true).unwrap());
230+
}
231+
232+
#[test]
233+
fn affine_new_from_x_even() {
234+
let p = AffinePoint::new(
235+
Felt::from_hex_unchecked("0x2d39148a92f479fb077389d"),
236+
Felt::from_hex_unchecked(
237+
"0x6e5d97edf7283fe7a7fe9deef2619224f42cb1bd531dd23380ad066c61ee20b",
238+
),
239+
)
240+
.unwrap();
241+
242+
assert_eq!(p.neg(), AffinePoint::new_from_x(&p.x(), false).unwrap());
243+
}
194244
}

0 commit comments

Comments
 (0)