@@ -248,21 +248,32 @@ static int wp_x25519_derive(wp_EcxCtx* ctx, unsigned char* secret,
248248 ok = 0 ;
249249 }
250250 if (ok ) {
251+ /* Constant-time: always subtract, then select based on
252+ * whether secret >= order. */
253+ unsigned char reduced [CURVE25519_KEYSIZE ];
254+ int16_t carry = 0 ;
255+ byte gt = 0 ;
256+ byte eq = 0xFF ;
257+
258+ for (i = CURVE25519_KEYSIZE - 1 ; i >= 0 ; i -- ) {
259+ carry += secret [i ];
260+ carry -= wp_curve25519_order [i ];
261+ reduced [i ] = (unsigned char )carry ;
262+ carry >>= 8 ;
263+ }
264+ /* Determine if secret >= order in constant time. */
251265 for (i = 0 ; i < CURVE25519_KEYSIZE ; i ++ ) {
252- if (secret [i ] != wp_curve25519_order [i ]) {
253- break ;
254- }
266+ gt |= eq & wp_ct_int_mask_gte (secret [i ],
267+ wp_curve25519_order [i ] + 1 );
268+ eq &= wp_ct_byte_mask_eq (secret [i ],
269+ wp_curve25519_order [i ]);
255270 }
256- if ((i < CURVE25519_KEYSIZE ) &&
257- (secret [i ] > wp_curve25519_order [i ])) {
258- int16_t carry = 0 ;
259- for (i = CURVE25519_KEYSIZE - 1 ; i >= 0 ; i -- ) {
260- carry += secret [i ];
261- carry -= wp_curve25519_order [i ];
262- secret [i ] = (unsigned char )carry ;
263- carry >>= 8 ;
264- }
271+ /* Select reduced if secret >= order. */
272+ for (i = 0 ; i < CURVE25519_KEYSIZE ; i ++ ) {
273+ secret [i ] = wp_ct_byte_mask_sel (gt | eq , reduced [i ],
274+ secret [i ]);
265275 }
276+ OPENSSL_cleanse (reduced , sizeof (reduced ));
266277 }
267278 if (ok ) {
268279 * secLen = len ;
0 commit comments