Skip to content

Commit be8ff3a

Browse files
field: Static-assert that int args affecting magnitude are constant
See bitcoin#1001.
1 parent 67214f5 commit be8ff3a

File tree

6 files changed

+43
-18
lines changed

6 files changed

+43
-18
lines changed

src/field.h

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST(
8888
# define secp256k1_fe_set_b32_mod secp256k1_fe_impl_set_b32_mod
8989
# define secp256k1_fe_set_b32_limit secp256k1_fe_impl_set_b32_limit
9090
# define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32
91-
# define secp256k1_fe_negate secp256k1_fe_impl_negate
92-
# define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int
91+
# define secp256k1_fe_negate_unchecked secp256k1_fe_impl_negate_unchecked
92+
# define secp256k1_fe_mul_int_unchecked secp256k1_fe_impl_mul_int_unchecked
9393
# define secp256k1_fe_add secp256k1_fe_impl_add
9494
# define secp256k1_fe_mul secp256k1_fe_impl_mul
9595
# define secp256k1_fe_sqr secp256k1_fe_impl_sqr
@@ -214,11 +214,17 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a);
214214
/** Negate a field element.
215215
*
216216
* On input, r does not need to be initialized. a must be a valid field element with
217-
* magnitude not exceeding m. m must be an integer in [0,31].
217+
* magnitude not exceeding m. m must be an integer constant expression in [0,31].
218218
* Performs {r = -a}.
219219
* On output, r will not be normalized, and will have magnitude m+1.
220220
*/
221-
static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
221+
#define secp256k1_fe_negate(r, a, m) ASSERT_INT_CONST_AND_DO(m, secp256k1_fe_negate_unchecked(r, a, m))
222+
223+
/** Like secp256k1_fe_negate_unchecked but m is not checked to be an integer constant expression.
224+
*
225+
* Should not be called directly outside of tests.
226+
*/
227+
static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m);
222228

223229
/** Add a small integer to a field element.
224230
*
@@ -229,12 +235,18 @@ static void secp256k1_fe_add_int(secp256k1_fe *r, int a);
229235

230236
/** Multiply a field element with a small integer.
231237
*
232-
* On input, r must be a valid field element. a must be an integer in [0,32].
238+
* On input, r must be a valid field element. a must be an integer constant expression in [0,32].
233239
* The magnitude of r times a must not exceed 32.
234240
* Performs {r *= a}.
235241
* On output, r's magnitude is multiplied by a, and r will not be normalized.
236242
*/
237-
static void secp256k1_fe_mul_int(secp256k1_fe *r, int a);
243+
#define secp256k1_fe_mul_int(r, a) ASSERT_INT_CONST_AND_DO(a, secp256k1_fe_mul_int_unchecked(r, a))
244+
245+
/** Like secp256k1_fe_mul_int but a is not checked to be an integer constant expression.
246+
*
247+
* Should not be called directly outside of tests.
248+
*/
249+
static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a);
238250

239251
/** Increment a field element by another.
240252
*

src/field_10x26_impl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
344344
r[31] = a->n[0] & 0xff;
345345
}
346346

347-
SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
347+
SECP256K1_INLINE static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) {
348348
/* For all legal values of m (0..31), the following properties hold: */
349349
VERIFY_CHECK(0x3FFFC2FUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
350350
VERIFY_CHECK(0x3FFFFBFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
@@ -365,7 +365,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const sec
365365
r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9];
366366
}
367367

368-
SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) {
368+
SECP256K1_INLINE static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a) {
369369
r->n[0] *= a;
370370
r->n[1] *= a;
371371
r->n[2] *= a;

src/field_5x52_impl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
314314
r[31] = a->n[0] & 0xFF;
315315
}
316316

317-
SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
317+
SECP256K1_INLINE static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) {
318318
/* For all legal values of m (0..31), the following properties hold: */
319319
VERIFY_CHECK(0xFFFFEFFFFFC2FULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
320320
VERIFY_CHECK(0xFFFFFFFFFFFFFULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
@@ -329,7 +329,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const sec
329329
r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4];
330330
}
331331

332-
SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) {
332+
SECP256K1_INLINE static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a) {
333333
r->n[0] *= a;
334334
r->n[1] *= a;
335335
r->n[2] *= a;

src/field_impl.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -289,23 +289,23 @@ SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp25
289289
secp256k1_fe_impl_get_b32(r, a);
290290
}
291291

292-
static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
293-
SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
292+
static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m);
293+
SECP256K1_INLINE static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) {
294294
secp256k1_fe_verify(a);
295295
VERIFY_CHECK(m >= 0 && m <= 31);
296296
VERIFY_CHECK(a->magnitude <= m);
297-
secp256k1_fe_impl_negate(r, a, m);
297+
secp256k1_fe_impl_negate_unchecked(r, a, m);
298298
r->magnitude = m + 1;
299299
r->normalized = 0;
300300
secp256k1_fe_verify(r);
301301
}
302302

303-
static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a);
304-
SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
303+
static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a);
304+
SECP256K1_INLINE static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a) {
305305
secp256k1_fe_verify(r);
306306
VERIFY_CHECK(a >= 0 && a <= 32);
307307
VERIFY_CHECK(a*r->magnitude <= 32);
308-
secp256k1_fe_impl_mul_int(r, a);
308+
secp256k1_fe_impl_mul_int_unchecked(r, a);
309309
r->magnitude *= a;
310310
r->normalized = 0;
311311
secp256k1_fe_verify(r);

src/tests.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ static void random_field_element_magnitude(secp256k1_fe *fe) {
108108
}
109109
secp256k1_fe_clear(&zero);
110110
secp256k1_fe_negate(&zero, &zero, 0);
111-
secp256k1_fe_mul_int(&zero, n - 1);
111+
secp256k1_fe_mul_int_unchecked(&zero, n - 1);
112112
secp256k1_fe_add(fe, &zero);
113113
#ifdef VERIFY
114114
CHECK(fe->magnitude == n);
@@ -3223,7 +3223,7 @@ static void run_field_misc(void) {
32233223
CHECK(q.normalized && q.magnitude == 1);
32243224
#endif
32253225
for (j = 0; j < 6; j++) {
3226-
secp256k1_fe_negate(&z, &z, j+1);
3226+
secp256k1_fe_negate_unchecked(&z, &z, j+1);
32273227
secp256k1_fe_normalize_var(&q);
32283228
secp256k1_fe_cmov(&q, &z, (j&1));
32293229
#ifdef VERIFY

src/util.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,19 @@ static void print_buf_plain(const unsigned char *buf, size_t len) {
5151
# define SECP256K1_INLINE inline
5252
# endif
5353

54+
/** Assert statically that expr is an integer constant expression, and run stmt.
55+
*
56+
* Useful for example to enforce that magnitude arguments are constant.
57+
*/
58+
#define ASSERT_INT_CONST_AND_DO(expr, stmt) do { \
59+
switch(42) { \
60+
case /* ERROR: integer argument is not constant */ expr: \
61+
break; \
62+
default: ; \
63+
} \
64+
stmt; \
65+
} while(0)
66+
5467
typedef struct {
5568
void (*fn)(const char *text, void* data);
5669
const void* data;

0 commit comments

Comments
 (0)