Skip to content

Commit 3353d3c

Browse files
committed
Merge #1207: Split fe_set_b32 into reducing and normalizing variants
5b32602 Split fe_set_b32 into reducing and normalizing variants (Pieter Wuille) Pull request description: Follow-up to #1205. This splits the `secp256k1_fe_set_b32` function into two variants: * `secp256k1_fe_set_b32_mod`, which returns `void`, reduces modulo the curve order, and only promises weakly normalized output. * `secp256k1_fe_set_b32_limit`, which returns `int` indicating success/failure, and only promises valid output in case the input is in range (but guarantees it's strongly normalized in this case). This removes one of the few cases in the codebase where normalization status depends on runtime values, making it fixed at compile-time instead. ACKs for top commit: real-or-random: ACK 5b32602 jonasnick: ACK 5b32602 Tree-SHA512: 4b93502272638c6ecdef4d74afa629e7ee540c0a20b377dccedbe567857b56c4684fad3af4b4293ed7ba35fed4aa5d0beaacdd77a903f44f24e8d87305919b61
2 parents 006ddc1 + 5b32602 commit 3353d3c

16 files changed

+68
-39
lines changed

src/bench_internal.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ static void bench_setup(void* arg) {
6565

6666
secp256k1_scalar_set_b32(&data->scalar[0], init[0], NULL);
6767
secp256k1_scalar_set_b32(&data->scalar[1], init[1], NULL);
68-
secp256k1_fe_set_b32(&data->fe[0], init[0]);
69-
secp256k1_fe_set_b32(&data->fe[1], init[1]);
70-
secp256k1_fe_set_b32(&data->fe[2], init[2]);
71-
secp256k1_fe_set_b32(&data->fe[3], init[3]);
68+
secp256k1_fe_set_b32_limit(&data->fe[0], init[0]);
69+
secp256k1_fe_set_b32_limit(&data->fe[1], init[1]);
70+
secp256k1_fe_set_b32_limit(&data->fe[2], init[2]);
71+
secp256k1_fe_set_b32_limit(&data->fe[3], init[3]);
7272
CHECK(secp256k1_ge_set_xo_var(&data->ge[0], &data->fe[0], 0));
7373
CHECK(secp256k1_ge_set_xo_var(&data->ge[1], &data->fe[1], 1));
7474
secp256k1_gej_set_ge(&data->gej[0], &data->ge[0]);

src/ecdsa_impl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp25
239239
}
240240
#else
241241
secp256k1_scalar_get_b32(c, sigr);
242-
secp256k1_fe_set_b32(&xr, c);
242+
/* we can ignore the fe_set_b32_limit return value, because we know the input is in range */
243+
(void)secp256k1_fe_set_b32_limit(&xr, c);
243244

244245
/** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n)
245246
* in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p),

src/eckey_impl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) {
1818
if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) {
1919
secp256k1_fe x;
20-
return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD);
20+
return secp256k1_fe_set_b32_limit(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD);
2121
} else if (size == 65 && (pub[0] == SECP256K1_TAG_PUBKEY_UNCOMPRESSED || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) {
2222
secp256k1_fe x, y;
23-
if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
23+
if (!secp256k1_fe_set_b32_limit(&x, pub+1) || !secp256k1_fe_set_b32_limit(&y, pub+33)) {
2424
return 0;
2525
}
2626
secp256k1_ge_set_xy(elem, &x, &y);

src/ecmult_gen_compute_table_impl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, cons
3131
secp256k1_fe nums_x;
3232
secp256k1_ge nums_ge;
3333
int r;
34-
r = secp256k1_fe_set_b32(&nums_x, nums_b32);
34+
r = secp256k1_fe_set_b32_limit(&nums_x, nums_b32);
3535
(void)r;
3636
VERIFY_CHECK(r);
3737
r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0);

src/ecmult_gen_impl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
108108
memset(keydata, 0, sizeof(keydata));
109109
/* Accept unobservably small non-uniformity. */
110110
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
111-
overflow = !secp256k1_fe_set_b32(&s, nonce32);
111+
overflow = !secp256k1_fe_set_b32_limit(&s, nonce32);
112112
overflow |= secp256k1_fe_is_zero(&s);
113113
secp256k1_fe_cmov(&s, &secp256k1_fe_one, overflow);
114114
/* Randomize the projection to defend against multiplier sidechannels.

src/field.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST(
8585
# define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero
8686
# define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd
8787
# define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var
88-
# define secp256k1_fe_set_b32 secp256k1_fe_impl_set_b32
88+
# define secp256k1_fe_set_b32_mod secp256k1_fe_impl_set_b32_mod
89+
# define secp256k1_fe_set_b32_limit secp256k1_fe_impl_set_b32_limit
8990
# define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32
9091
# define secp256k1_fe_negate secp256k1_fe_impl_negate
9192
# define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int
@@ -189,16 +190,20 @@ static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);
189190
*/
190191
static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
191192

192-
/** Set a field element equal to a provided 32-byte big endian value.
193+
/** Set a field element equal to a provided 32-byte big endian value, reducing it.
193194
*
194195
* On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array.
195-
* On output, r = a (mod p). It will have magnitude 1, and if (a < p), it will be normalized.
196-
* If not, it will only be weakly normalized. Returns whether (a < p).
196+
* On output, r = a (mod p). It will have magnitude 1, and not be normalized.
197+
*/
198+
static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a);
199+
200+
/** Set a field element equal to a provided 32-byte big endian value, checking for overflow.
197201
*
198-
* Note that this function is unusual in that the normalization of the output depends on the
199-
* run-time value of a.
202+
* On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array.
203+
* On output, r = a if (a < p), it will be normalized with magnitude 1, and 1 is returned.
204+
* If a >= p, 0 is returned, and r will be made invalid (and must not be used without overwriting).
200205
*/
201-
static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a);
206+
static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a);
202207

203208
/** Convert a field element to 32-byte big endian byte array.
204209
* On input, a must be a valid normalized field element, and r a pointer to a 32-byte array.

src/field_10x26_impl.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *
290290
return 0;
291291
}
292292

293-
static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) {
293+
static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
294294
r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24);
295295
r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22);
296296
r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20);
@@ -301,7 +301,10 @@ static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) {
301301
r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18);
302302
r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24);
303303
r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14);
304+
}
304305

306+
static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
307+
secp256k1_fe_impl_set_b32_mod(r, a);
305308
return !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL));
306309
}
307310

src/field_5x52_impl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *
236236
return 0;
237237
}
238238

239-
static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) {
239+
static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
240240
r->n[0] = (uint64_t)a[31]
241241
| ((uint64_t)a[30] << 8)
242242
| ((uint64_t)a[29] << 16)
@@ -271,6 +271,10 @@ static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) {
271271
| ((uint64_t)a[2] << 24)
272272
| ((uint64_t)a[1] << 32)
273273
| ((uint64_t)a[0] << 40);
274+
}
275+
276+
static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
277+
secp256k1_fe_impl_set_b32_mod(r, a);
274278
return !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL));
275279
}
276280

src/field_impl.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -260,13 +260,26 @@ SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const se
260260
return secp256k1_fe_impl_cmp_var(a, b);
261261
}
262262

263-
static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a);
264-
SECP256K1_INLINE static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
265-
int ret = secp256k1_fe_impl_set_b32(r, a);
263+
static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a);
264+
SECP256K1_INLINE static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
265+
secp256k1_fe_impl_set_b32_mod(r, a);
266266
r->magnitude = 1;
267-
r->normalized = ret;
267+
r->normalized = 0;
268268
secp256k1_fe_verify(r);
269-
return ret;
269+
}
270+
271+
static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a);
272+
SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
273+
if (secp256k1_fe_impl_set_b32_limit(r, a)) {
274+
r->magnitude = 1;
275+
r->normalized = 1;
276+
secp256k1_fe_verify(r);
277+
return 1;
278+
} else {
279+
/* Mark the output field element as invalid. */
280+
r->magnitude = -1;
281+
return 0;
282+
}
270283
}
271284

272285
static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a);

src/modules/extrakeys/main_impl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_p
2828
memset(pubkey, 0, sizeof(*pubkey));
2929
ARG_CHECK(input32 != NULL);
3030

31-
if (!secp256k1_fe_set_b32(&x, input32)) {
31+
if (!secp256k1_fe_set_b32_limit(&x, input32)) {
3232
return 0;
3333
}
3434
if (!secp256k1_ge_set_xo_var(&pk, &x, 0)) {

0 commit comments

Comments
 (0)