@@ -4,6 +4,7 @@ use lambdaworks_math::{
4
4
elliptic_curve:: {
5
5
short_weierstrass:: {
6
6
curves:: stark_curve:: StarkCurve , point:: ShortWeierstrassProjectivePoint ,
7
+ traits:: IsShortWeierstrass ,
7
8
} ,
8
9
traits:: { FromAffine , IsEllipticCurve } ,
9
10
} ,
@@ -33,6 +34,28 @@ impl AffinePoint {
33
34
] ) )
34
35
}
35
36
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
+
36
59
/// The point at infinity.
37
60
pub fn identity ( ) -> AffinePoint {
38
61
Self ( ShortWeierstrassProjectivePoint :: neutral_element ( ) )
@@ -86,6 +109,7 @@ impl core::ops::Mul<Felt> for &AffinePoint {
86
109
#[ cfg( test) ]
87
110
mod test {
88
111
use super :: * ;
112
+ use std:: ops:: Neg ;
89
113
90
114
#[ test]
91
115
fn affine_point_new_unchecked ( ) {
@@ -191,4 +215,30 @@ mod test {
191
215
. unwrap( )
192
216
) ;
193
217
}
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
+ }
194
244
}
0 commit comments