Skip to content

Commit 3ce1d90

Browse files
Rexicon226drubin-fd
authored andcommitted
secp256r1: check for point equality before using incomplete formula
1 parent 71c18bf commit 3ce1d90

File tree

2 files changed

+75
-7
lines changed

2 files changed

+75
-7
lines changed

src/ballet/secp256r1/fd_secp256r1_s2n.c

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ fd_secp256r1_scalar_from_digest( fd_secp256r1_scalar_t * r,
4141
}
4242

4343
static inline fd_secp256r1_scalar_t *
44-
fd_secp256r1_scalar_mul( fd_secp256r1_scalar_t * r,
44+
fd_secp256r1_scalar_mul( fd_secp256r1_scalar_t * r,
4545
fd_secp256r1_scalar_t const * a,
4646
fd_secp256r1_scalar_t const * b ) {
4747
ulong t[ 8 ];
@@ -51,7 +51,7 @@ fd_secp256r1_scalar_mul( fd_secp256r1_scalar_t * r,
5151
}
5252

5353
static inline fd_secp256r1_scalar_t *
54-
fd_secp256r1_scalar_inv( fd_secp256r1_scalar_t * r,
54+
fd_secp256r1_scalar_inv( fd_secp256r1_scalar_t * r,
5555
fd_secp256r1_scalar_t const * a ) {
5656
ulong t[ 12 ];
5757
bignum_modinv( 4, r->limbs, (ulong *)a->limbs, (ulong *)fd_secp256r1_const_n[0].limbs, t );
@@ -131,7 +131,7 @@ fd_secp256r1_point_frombytes( fd_secp256r1_point_t * r,
131131
}
132132

133133
bignum_tomont_p256( r->x->limbs, r->x->limbs );
134-
134+
135135
/* y^2 = x^3 + ax + b */
136136
bignum_montsqr_p256( y2->limbs, r->x->limbs );
137137
bignum_add_p256 ( y2->limbs, y2->limbs, (ulong *)fd_secp256r1_const_a_mont[0].limbs );
@@ -176,6 +176,41 @@ fd_secp256r1_point_eq_x( fd_secp256r1_point_t const * p,
176176
return FD_SECP256R1_FAILURE;
177177
}
178178

179+
/* Given the projective point `r` and the affine point `p`,
180+
returns 1 if they are equal and 0 otherwise.
181+
Assumes that `p` X and Y coordinates are in Montgomery domain. */
182+
static inline int
183+
fd_secp256r1_point_eq_mixed( fd_secp256r1_point_t const * a,
184+
ulong const b[ 8 ] ) {
185+
fd_secp256r1_fp_t x[1], y[1];
186+
fd_memcpy( x->limbs, b+0, sizeof(fd_secp256r1_fp_t) );
187+
fd_memcpy( y->limbs, b+4, sizeof(fd_secp256r1_fp_t) );
188+
/* Indicates if the affine point is zero. */
189+
int is_zero = fd_uint256_eq( x, fd_secp256r1_const_zero ) & fd_uint256_eq( y, fd_secp256r1_const_zero );
190+
191+
/* Easy cases */
192+
if( FD_UNLIKELY( fd_uint256_eq( a->z, fd_secp256r1_const_zero ) ) ) {
193+
return is_zero;
194+
}
195+
if( FD_UNLIKELY( is_zero ) ) {
196+
return 0;
197+
}
198+
199+
fd_secp256r1_fp_t z1z1[1];
200+
bignum_montsqr_p256( z1z1->limbs, (ulong *)a->z->limbs );
201+
202+
fd_secp256r1_fp_t temp[1];
203+
bignum_montmul_p256( temp->limbs, (ulong *)x->limbs, z1z1->limbs );
204+
205+
if( FD_UNLIKELY( fd_uint256_eq( a->x, temp ) ) ) {
206+
bignum_montmul_p256( temp->limbs, z1z1->limbs, (ulong *)a->z->limbs );
207+
bignum_montmul_p256( temp->limbs, temp->limbs, (ulong *)y->limbs );
208+
return fd_uint256_eq( a->y, temp );
209+
} else {
210+
return 0;
211+
}
212+
}
213+
179214
static inline void
180215
fd_secp256r1_double_scalar_mul_base( fd_secp256r1_point_t * r,
181216
fd_secp256r1_scalar_t const * u1,
@@ -189,5 +224,9 @@ fd_secp256r1_double_scalar_mul_base( fd_secp256r1_point_t * r,
189224

190225
p256_montjscalarmul( (ulong *)r, (ulong *)u2->limbs, (ulong *)a );
191226

192-
p256_montjmixadd( (ulong *)r, (ulong *)r, rtmp );
227+
if( FD_UNLIKELY( fd_secp256r1_point_eq_mixed( r, rtmp ) ) ) {
228+
p256_montjdouble( (ulong *)r, (ulong *)r );
229+
} else {
230+
p256_montjmixadd( (ulong *)r, (ulong *)r, rtmp );
231+
}
193232
}

src/ballet/secp256r1/test_secp256r1.c

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ test_secp256r1_scalar_frombytes( FD_FN_UNUSED fd_rng_t * rng ) {
1616
uchar _sig[ 64 ] = { 0 }; uchar * sig = _sig;
1717
fd_hex_decode( sig, "a940d67c9560a47c5dafb45ab1f39eb68c8fac9b51fc8c4e30b1f0e63e4967d3586569a56364c3b03eefd421aa7fc750f6fa187210c3206c55602f96e0ecaa4d", 64 );
1818
fd_secp256r1_scalar_t _r[1]; fd_secp256r1_scalar_t * r = _r;
19-
19+
2020
FD_TEST( fd_secp256r1_scalar_frombytes( r, sig )==r );
2121
FD_TEST( fd_secp256r1_scalar_frombytes_positive( r, sig+32 )==r );
2222
FD_TEST( fd_secp256r1_scalar_frombytes_positive( r, sig )==NULL );
@@ -105,7 +105,7 @@ test_secp256r1_fp_frombytes( FD_FN_UNUSED fd_rng_t * rng ) {
105105
uchar _buf[ 32 ] = { 0 }; uchar * buf = _buf;
106106
fd_hex_decode( buf, "d8c82b3791c8b51cfe44aa50226217159596ca26e6075aaf8bf8be2d351b96ae", 32 );
107107
fd_secp256r1_fp_t _r[1]; fd_secp256r1_fp_t * r = _r;
108-
108+
109109
FD_TEST( fd_secp256r1_fp_frombytes( r, buf )==r );
110110

111111
// bench
@@ -129,7 +129,7 @@ test_secp256r1_fp_sqrt( FD_FN_UNUSED fd_rng_t * rng ) {
129129
fd_hex_decode( sqrt1, "f942f2008adaab3a98ad4af432f97b2cc45170a9051574304e12c6b461c012e8", 32 );
130130
fd_secp256r1_fp_t _r[1]; fd_secp256r1_fp_t * r = _r;
131131
fd_secp256r1_fp_t a[1];
132-
132+
133133
FD_TEST( fd_secp256r1_fp_frombytes( a, sqrt1 )==a );
134134
FD_TEST( fd_secp256r1_fp_sqrt( r, a )==NULL );
135135

@@ -222,6 +222,33 @@ test_secp256r1_point_eq_x( FD_FN_UNUSED fd_rng_t * rng ) {
222222
}
223223
}
224224

225+
static void
226+
test_secp256r1_double_scalar_mul_base_equal_points( FD_FN_UNUSED fd_rng_t * rng ) {
227+
/* edge case in fd_secp256r1_double_scalar_mul_base where the point
228+
addition at the end receives equal points. without special handling,
229+
performing a point addition in incomplete jacobian coordinates results
230+
in an invalid result. */
231+
uchar _buf[ 33 ] = { 0 }; uchar * buf = _buf;
232+
fd_secp256r1_scalar_t u1[1], u2[1], expected_x[1];
233+
fd_secp256r1_point_t pub[1], result[1];
234+
235+
fd_hex_decode( buf, "cdfa20ffc3bcdc92cdf4f96552b30a2f775d4353d857fab82729f140b16fbb07", 32 );
236+
fd_secp256r1_scalar_frombytes( u1, buf );
237+
238+
fd_hex_decode( buf, "5f811cb929645f8b6facaa5090e5e945452ec40a3193ca54ee8971105e503a69", 32 );
239+
fd_secp256r1_scalar_frombytes( u2, buf );
240+
241+
fd_hex_decode( buf, "03578af9bfb68e75c0f38fa2b4af3815164ec0acfb1e111fe9bc425b373735d62e", 33 );
242+
FD_TEST( fd_secp256r1_point_frombytes( pub, buf )==pub );
243+
244+
/* x-coordinate of 2*(u1*G) = u1*G + u2*A */
245+
fd_hex_decode( buf, "aa30744d8384e6c20a67418b687ab2a0f049368917e15ef9832fe61d3bf2b622", 32 );
246+
fd_secp256r1_scalar_frombytes( expected_x, buf );
247+
248+
fd_secp256r1_double_scalar_mul_base( result, u1, pub, u2 );
249+
FD_TEST( fd_secp256r1_point_eq_x( result, expected_x )==FD_SECP256R1_SUCCESS );
250+
}
251+
225252
static void
226253
test_secp256r1_verify( FD_FN_UNUSED fd_rng_t * rng ) {
227254

@@ -297,6 +324,8 @@ main( int argc,
297324
test_secp256r1_point_frombytes ( rng );
298325
test_secp256r1_point_eq_x ( rng );
299326

327+
test_secp256r1_double_scalar_mul_base_equal_points( rng );
328+
300329
test_secp256r1_verify ( rng );
301330

302331
FD_LOG_NOTICE(( "pass" ));

0 commit comments

Comments
 (0)