From b29566c51b2a47139d610bf686e09ae9f9d24001 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 17:39:30 -0500 Subject: [PATCH 01/29] Merge magnitude/normalized fields, move/improve comments Also split secp256k1_fe_verify into a generic and an implementation specific part. --- src/field.h | 45 +++++++++++++++++++++++++++++++----------- src/field_10x26.h | 27 ++++++++++++++++++------- src/field_10x26_impl.h | 17 ++-------------- src/field_5x52.h | 27 ++++++++++++++++++------- src/field_5x52_impl.h | 23 ++------------------- src/field_impl.h | 18 +++++++++++++++++ 6 files changed, 96 insertions(+), 61 deletions(-) diff --git a/src/field.h b/src/field.h index dca75aac10..28ebe85ac1 100644 --- a/src/field.h +++ b/src/field.h @@ -7,19 +7,36 @@ #ifndef SECP256K1_FIELD_H #define SECP256K1_FIELD_H -/** Field element module. - * - * Field elements can be represented in several ways, but code accessing - * it (and implementations) need to take certain properties into account: - * - Each field element can be normalized or not. - * - Each field element has a magnitude, which represents how far away - * its representation is away from normalization. Normalized elements - * always have a magnitude of 0 or 1, but a magnitude of 1 doesn't - * imply normality. - */ - #include "util.h" +/* This file defines the generic interface for working with secp256k1_fe + * objects, which represent field elements (integers modulo 2^256 - 2^32 - 977). + * + * The actual definition of the secp256k1_fe type depends on the chosen field + * implementation; see the field_5x52.h and field_10x26.h files for details. + * + * All secp256k1_fe objects have implicit properties that determine what + * operations are permitted on it. These are purely a function of what + * secp256k1_fe_ operations are applied on it, generally (implicitly) fixed at + * compile time, and do not depend on the chosen field implementation. Despite + * that, what these properties actually entail for the field representation + * values depends on the chosen field implementation. These properties are: + * - magnitude: an integer in [0,32] + * - normalized: 0 or 1; normalized=1 implies magnitude <= 1. + * + * In VERIFY mode, they are materialized explicitly as fields in the struct, + * allowing run-time verification of these properties. In that case, the field + * implementation also provides a secp256k1_fe_verify routine to verify that + * these fields match the run-time value and perform internal consistency + * checks. */ +#ifdef VERIFY +# define SECP256K1_FE_VERIFY_FIELDS \ + int magnitude; \ + int normalized; +#else +# define SECP256K1_FE_VERIFY_FIELDS +#endif + #if defined(SECP256K1_WIDEMUL_INT128) #include "field_5x52.h" #elif defined(SECP256K1_WIDEMUL_INT64) @@ -34,6 +51,12 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul ); +#ifndef VERIFY +/* In non-VERIFY mode, we #define the fe operations to be identical to their + * internal field implementation, to avoid the potential overhead of a + * function call (even though presumably inlinable). */ +#endif /* !defined(VERIFY) */ + /** Normalize a field element. This brings the field element to a canonical representation, reduces * its magnitude to 1, and reduces it modulo field size `p`. */ diff --git a/src/field_10x26.h b/src/field_10x26.h index 9eb65607f1..4fe36d08e2 100644 --- a/src/field_10x26.h +++ b/src/field_10x26.h @@ -9,15 +9,28 @@ #include +/** This field implementation represents the value as 10 uint32_t limbs in base + * 2^26. */ typedef struct { - /* X = sum(i=0..9, n[i]*2^(i*26)) mod p - * where p = 2^256 - 0x1000003D1 - */ + /* A field element f represents the sum(i=0..9, f.n[i] << (i*26)) mod p, + * where p is the field modulus, 2^256 - 2^32 - 977. + * + * The individual limbs f.n[i] can exceed 2^26; the field's magnitude roughly + * corresponds to how much excess is allowed. The value + * sum(i=0..9, f.n[i] << (i*26)) may exceed p, unless the field element is + * normalized. */ uint32_t n[10]; -#ifdef VERIFY - int magnitude; - int normalized; -#endif + /* + * Magnitude m requires: + * n[i] <= 2 * m * (2^26 - 1) for i=0..8 + * n[9] <= 2 * m * (2^22 - 1) + * + * Normalized requires: + * n[i] <= (2^26 - 1) for i=0..8 + * sum(i=0..9, n[i] << (i*26)) < p + * (together these imply n[9] <= 2^22 - 1) + */ + SECP256K1_FE_VERIFY_FIELDS } secp256k1_fe; /* Unpacks a constant into a overlapping multi-limbed FE element. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index c164711757..8115f534ad 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -12,17 +12,8 @@ #include "field.h" #include "modinv32_impl.h" -/** See the comment at the top of field_5x52_impl.h for more details. - * - * Here, we represent field elements as 10 uint32_t's in base 2^26, least significant first, - * where limbs can contain >26 bits. - * A magnitude M means: - * - 2*M*(2^22-1) is the max (inclusive) of the most significant limb - * - 2*M*(2^26-1) is the max (inclusive) of the remaining limbs - */ - -static void secp256k1_fe_verify(const secp256k1_fe *a) { #ifdef VERIFY +static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { const uint32_t *d = a->n; int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; r &= (d[0] <= 0x3FFFFFFUL * m); @@ -35,10 +26,7 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) { r &= (d[7] <= 0x3FFFFFFUL * m); r &= (d[8] <= 0x3FFFFFFUL * m); r &= (d[9] <= 0x03FFFFFUL * m); - r &= (a->magnitude >= 0); - r &= (a->magnitude <= 32); if (a->normalized) { - r &= (a->magnitude <= 1); if (r && (d[9] == 0x03FFFFFUL)) { uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2]; if (mid == 0x3FFFFFFUL) { @@ -47,9 +35,8 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) { } } VERIFY_CHECK(r == 1); -#endif - (void)a; } +#endif static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { VERIFY_CHECK(m >= 0); diff --git a/src/field_5x52.h b/src/field_5x52.h index 50ee3f9ec9..e4646a56be 100644 --- a/src/field_5x52.h +++ b/src/field_5x52.h @@ -9,15 +9,28 @@ #include +/** This field implementation represents the value as 5 uint64_t limbs in base + * 2^52. */ typedef struct { - /* X = sum(i=0..4, n[i]*2^(i*52)) mod p - * where p = 2^256 - 0x1000003D1 - */ + /* A field element f represents the sum(i=0..4, f.n[i] << (i*52)) mod p, + * where p is the field modulus, 2^256 - 2^32 - 977. + * + * The individual limbs f.n[i] can exceed 2^52; the field's magnitude roughly + * corresponds to how much excess is allowed. The value + * sum(i=0..4, f.n[i] << (i*52)) may exceed p, unless the field element is + * normalized. */ uint64_t n[5]; -#ifdef VERIFY - int magnitude; - int normalized; -#endif + /* + * Magnitude m requires: + * n[i] <= 2 * m * (2^52 - 1) for i=0..3 + * n[4] <= 2 * m * (2^48 - 1) + * + * Normalized requires: + * n[i] <= (2^52 - 1) for i=0..3 + * sum(i=0..4, n[i] << (i*52)) < p + * (together these imply n[4] <= 2^48 - 1) + */ + SECP256K1_FE_VERIFY_FIELDS } secp256k1_fe; /* Unpacks a constant into a overlapping multi-limbed FE element. */ diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 9b9794c099..cd240577f7 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -18,23 +18,8 @@ #include "field_5x52_int128_impl.h" #endif -/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F, - * represented as 5 uint64_t's in base 2^52, least significant first. Note that the limbs are allowed to - * contain >52 bits each. - * - * Each field element has a 'magnitude' associated with it. Internally, a magnitude M means: - * - 2*M*(2^48-1) is the max (inclusive) of the most significant limb - * - 2*M*(2^52-1) is the max (inclusive) of the remaining limbs - * - * Operations have different rules for propagating magnitude to their outputs. If an operation takes a - * magnitude M as a parameter, that means the magnitude of input field elements can be at most M (inclusive). - * - * Each field element also has a 'normalized' flag. A field element is normalized if its magnitude is either - * 0 or 1, and its value is already reduced modulo the order of the field. - */ - -static void secp256k1_fe_verify(const secp256k1_fe *a) { #ifdef VERIFY +static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { const uint64_t *d = a->n; int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ @@ -43,18 +28,14 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) { r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m); r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m); r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m); - r &= (a->magnitude >= 0); - r &= (a->magnitude <= 2048); if (a->normalized) { - r &= (a->magnitude <= 1); if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { r &= (d[0] < 0xFFFFEFFFFFC2FULL); } } VERIFY_CHECK(r == 1); -#endif - (void)a; } +#endif static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { VERIFY_CHECK(m >= 0); diff --git a/src/field_impl.h b/src/field_impl.h index 0a03076bbc..9920dfdb78 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -7,6 +7,7 @@ #ifndef SECP256K1_FIELD_IMPL_H #define SECP256K1_FIELD_IMPL_H +#include "field.h" #include "util.h" #if defined(SECP256K1_WIDEMUL_INT128) @@ -131,4 +132,21 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) { return secp256k1_fe_equal(&t1, a); } +#ifndef VERIFY +static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; } +#else +static void secp256k1_fe_impl_verify(const secp256k1_fe *a); +static void secp256k1_fe_verify(const secp256k1_fe *a) { + /* Magnitude between 0 and 32. */ + int r = (a->magnitude >= 0) & (a->magnitude <= 32); + /* Normalized is 0 or 1. */ + r &= (a->normalized == 0) | (a->normalized == 1); + /* If normalized, magnitude must be 0 or 1. */ + if (a->normalized) r &= (a->magnitude <= 1); + VERIFY_CHECK(r == 1); + /* Invoke implementation-specific checks. */ + secp256k1_fe_impl_verify(a); +} +#endif /* defined(VERIFY) */ + #endif /* SECP256K1_FIELD_IMPL_H */ From 7fa51955592ccf4fb424a7a538372ad159e77293 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 1 Feb 2022 11:15:09 -0500 Subject: [PATCH 02/29] Bugfix: correct SECP256K1_FE_CONST mag/norm fields --- src/field.h | 20 ++++++++++++++++++++ src/field_10x26.h | 6 ------ src/field_5x52.h | 6 ------ 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/field.h b/src/field.h index 28ebe85ac1..3914f6b47a 100644 --- a/src/field.h +++ b/src/field.h @@ -45,6 +45,26 @@ #error "Please select wide multiplication implementation" #endif +#ifdef VERIFY +/* Magnitude and normalized value for constants. */ +#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) \ + /* Magnitude is 0 for constant 0; 1 otherwise. */ \ + , (((d7) | (d6) | (d5) | (d4) | (d3) | (d2) | (d1) | (d0)) != 0) \ + /* Normalized is 1 unless sum(d_i<<(32*i) for i=0..7) exceeds field modulus. */ \ + , (!(((d7) & (d6) & (d5) & (d4) & (d3) & (d2)) == 0xfffffffful && ((d1) == 0xfffffffful || ((d1) == 0xfffffffe && (d0 >= 0xfffffc2f))))) +#else +#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) +#endif + +/** This expands to an initializer for a secp256k1_fe valued sum((i*32) * d_i, i=0..7) mod p. + * + * It has magnitude 1, unless d_i are all 0, in which case the magnitude is 0. + * It is normalized, unless sum(2^(i*32) * d_i, i=0..7) >= p. + * + * SECP256K1_FE_CONST_INNER is provided by the implementation. + */ +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) SECP256K1_FE_VERIFY_CONST((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) } + static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, diff --git a/src/field_10x26.h b/src/field_10x26.h index 4fe36d08e2..203c10167c 100644 --- a/src/field_10x26.h +++ b/src/field_10x26.h @@ -47,12 +47,6 @@ typedef struct { (((uint32_t)d7) >> 10) \ } -#ifdef VERIFY -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} -#else -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} -#endif - typedef struct { uint32_t n[8]; } secp256k1_fe_storage; diff --git a/src/field_5x52.h b/src/field_5x52.h index e4646a56be..f20c246fdd 100644 --- a/src/field_5x52.h +++ b/src/field_5x52.h @@ -42,12 +42,6 @@ typedef struct { ((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \ } -#ifdef VERIFY -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} -#else -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} -#endif - typedef struct { uint64_t n[4]; } secp256k1_fe_storage; From b6b6f9cb97f6c9313871c278ec73f209ef537a44 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 17:51:12 -0500 Subject: [PATCH 03/29] Abstract out verify logic for fe_normalize --- src/field.h | 7 +++++-- src/field_10x26_impl.h | 8 +------- src/field_5x52_impl.h | 8 +------- src/field_impl.h | 9 +++++++++ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/field.h b/src/field.h index 3914f6b47a..161df2b3ed 100644 --- a/src/field.h +++ b/src/field.h @@ -75,10 +75,13 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( /* In non-VERIFY mode, we #define the fe operations to be identical to their * internal field implementation, to avoid the potential overhead of a * function call (even though presumably inlinable). */ +# define secp256k1_fe_normalize secp256k1_fe_impl_normalize #endif /* !defined(VERIFY) */ -/** Normalize a field element. This brings the field element to a canonical representation, reduces - * its magnitude to 1, and reduces it modulo field size `p`. +/** Normalize a field element. + * + * On input, r must be a valid field element. + * On output, r represents the same value but has normalized=1 and magnitude=1. */ static void secp256k1_fe_normalize(secp256k1_fe *r); diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 8115f534ad..537000a8d1 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -58,7 +58,7 @@ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { #endif } -static void secp256k1_fe_normalize(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -105,12 +105,6 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index cd240577f7..820bc3466f 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -52,7 +52,7 @@ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { #endif } -static void secp256k1_fe_normalize(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -87,12 +87,6 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) { t4 &= 0x0FFFFFFFFFFFFULL; r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { diff --git a/src/field_impl.h b/src/field_impl.h index 9920dfdb78..f3341db0e4 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -147,6 +147,15 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) { /* Invoke implementation-specific checks. */ secp256k1_fe_impl_verify(a); } + +static void secp256k1_fe_impl_normalize(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) { + secp256k1_fe_verify(r); + secp256k1_fe_impl_normalize(r); + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From e28b51f52254b93805350354567a944ca4d79ae2 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 17:54:22 -0500 Subject: [PATCH 04/29] Abstract out verify logic for fe_normalize_weak --- src/field.h | 7 ++++++- src/field_10x26_impl.h | 7 +------ src/field_5x52_impl.h | 7 +------ src/field_impl.h | 8 ++++++++ 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/field.h b/src/field.h index 161df2b3ed..ba2d57bba9 100644 --- a/src/field.h +++ b/src/field.h @@ -76,6 +76,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( * internal field implementation, to avoid the potential overhead of a * function call (even though presumably inlinable). */ # define secp256k1_fe_normalize secp256k1_fe_impl_normalize +# define secp256k1_fe_normalize_weak secp256k1_fe_impl_normalize_weak #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -85,7 +86,11 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( */ static void secp256k1_fe_normalize(secp256k1_fe *r); -/** Weakly normalize a field element: reduce its magnitude to 1, but don't fully normalize. */ +/** Give a field element magnitude 1. + * + * On input, r must be a valid field element. + * On output, r represents the same value but has magnitude=1. Normalized is unchanged. + */ static void secp256k1_fe_normalize_weak(secp256k1_fe *r); /** Normalize a field element, without constant-time guarantee. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 537000a8d1..b76111641c 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -107,7 +107,7 @@ static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; } -static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -131,11 +131,6 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_normalize_var(secp256k1_fe *r) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 820bc3466f..09f3d74900 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -89,7 +89,7 @@ static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; } -static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -106,11 +106,6 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { VERIFY_CHECK(t4 >> 49 == 0); r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - -#ifdef VERIFY - r->magnitude = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_normalize_var(secp256k1_fe *r) { diff --git a/src/field_impl.h b/src/field_impl.h index f3341db0e4..3928e417c6 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -156,6 +156,14 @@ SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) { r->normalized = 1; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { + secp256k1_fe_verify(r); + secp256k1_fe_impl_normalize_weak(r); + r->magnitude = 1; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 6c31371120bb85a397bf1caa73fd1c9b8405d35e Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 17:59:36 -0500 Subject: [PATCH 05/29] Abstract out verify logic for fe_normalize_var --- src/field.h | 6 +++++- src/field_10x26_impl.h | 8 +------- src/field_5x52_impl.h | 8 +------- src/field_impl.h | 9 +++++++++ 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/field.h b/src/field.h index ba2d57bba9..cae92b5866 100644 --- a/src/field.h +++ b/src/field.h @@ -77,6 +77,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( * function call (even though presumably inlinable). */ # define secp256k1_fe_normalize secp256k1_fe_impl_normalize # define secp256k1_fe_normalize_weak secp256k1_fe_impl_normalize_weak +# define secp256k1_fe_normalize_var secp256k1_fe_impl_normalize_var #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -93,7 +94,10 @@ static void secp256k1_fe_normalize(secp256k1_fe *r); */ static void secp256k1_fe_normalize_weak(secp256k1_fe *r); -/** Normalize a field element, without constant-time guarantee. */ +/** Normalize a field element, without constant-time guarantee. + * + * Identical in behavior to secp256k1_fe_normalize, but not constant time in r. + */ static void secp256k1_fe_normalize_var(secp256k1_fe *r); /** Verify whether a field element represents zero i.e. would normalize to a zero value. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index b76111641c..7043da3dea 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -133,7 +133,7 @@ static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) { r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; } -static void secp256k1_fe_normalize_var(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -181,12 +181,6 @@ static void secp256k1_fe_normalize_var(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 09f3d74900..6594972def 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -108,7 +108,7 @@ static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; } -static void secp256k1_fe_normalize_var(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -144,12 +144,6 @@ static void secp256k1_fe_normalize_var(secp256k1_fe *r) { } r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { diff --git a/src/field_impl.h b/src/field_impl.h index 3928e417c6..414e3e188c 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -164,6 +164,15 @@ SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { r->magnitude = 1; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) { + secp256k1_fe_verify(r); + secp256k1_fe_impl_normalize_var(r); + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 864f9db491b4e1204fda5168174b235f9eefb56e Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 31 Jan 2022 16:51:10 -0500 Subject: [PATCH 06/29] Abstract out verify logic for fe_normalizes_to_zero{,_var} --- src/field.h | 14 +++++++++++--- src/field_10x26_impl.h | 4 ++-- src/field_5x52_impl.h | 4 ++-- src/field_impl.h | 12 ++++++++++++ 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/field.h b/src/field.h index cae92b5866..8db62a92eb 100644 --- a/src/field.h +++ b/src/field.h @@ -78,6 +78,8 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_normalize secp256k1_fe_impl_normalize # define secp256k1_fe_normalize_weak secp256k1_fe_impl_normalize_weak # define secp256k1_fe_normalize_var secp256k1_fe_impl_normalize_var +# define secp256k1_fe_normalizes_to_zero secp256k1_fe_impl_normalizes_to_zero +# define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -100,11 +102,17 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r); */ static void secp256k1_fe_normalize_var(secp256k1_fe *r); -/** Verify whether a field element represents zero i.e. would normalize to a zero value. */ +/** Determine whether r represents field element 0. + * + * On input, r must be a valid field element. + * Returns whether r = 0 (mod p). + */ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r); -/** Verify whether a field element represents zero i.e. would normalize to a zero value, - * without constant-time guarantee. */ +/** Determine whether r represents field element 0, without constant-time guarantee. + * + * Identical in behavior to secp256k1_normalizes_to_zero, but not constant time in r. + */ static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r); /** Set a field element equal to a small (not greater than 0x7FFF), non-negative integer. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 7043da3dea..e107bee8a8 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -183,7 +183,7 @@ static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) { r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; } -static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { +static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -212,7 +212,7 @@ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) { +static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) { uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; uint32_t z0, z1; uint32_t x; diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 6594972def..1a8960ff1e 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -146,7 +146,7 @@ static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; } -static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { +static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ @@ -169,7 +169,7 @@ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); } -static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) { +static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) { uint64_t t0, t1, t2, t3, t4; uint64_t z0, z1; uint64_t x; diff --git a/src/field_impl.h b/src/field_impl.h index 414e3e188c..ae54693859 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -173,6 +173,18 @@ SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) { r->normalized = 1; secp256k1_fe_verify(r); } + +static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r); +SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { + secp256k1_fe_verify(r); + return secp256k1_fe_impl_normalizes_to_zero(r); +} + +static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r); +SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) { + secp256k1_fe_verify(r); + return secp256k1_fe_impl_normalizes_to_zero_var(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 19a2bfeeeac4274bbeca7f8757a2ee73bdf03895 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:04:15 -0500 Subject: [PATCH 07/29] Abstract out verify logic for fe_set_int --- src/field.h | 7 +++++-- src/field_10x26_impl.h | 8 +------- src/field_5x52_impl.h | 8 +------- src/field_impl.h | 9 +++++++++ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/field.h b/src/field.h index 8db62a92eb..e841f14ee0 100644 --- a/src/field.h +++ b/src/field.h @@ -80,6 +80,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_normalize_var secp256k1_fe_impl_normalize_var # define secp256k1_fe_normalizes_to_zero secp256k1_fe_impl_normalizes_to_zero # define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var +# define secp256k1_fe_set_int secp256k1_fe_impl_set_int #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -115,8 +116,10 @@ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r); */ static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r); -/** Set a field element equal to a small (not greater than 0x7FFF), non-negative integer. - * Resulting field element is normalized; it has magnitude 0 if a == 0, and magnitude 1 otherwise. +/** Set a field element to an integer in range [0,0x7FFF]. + * + * On input, r does not need to be initialized, a must be in [0,0x7FFF]. + * On output, r represents value a, is normalized and has magnitude (a!=0). */ static void secp256k1_fe_set_int(secp256k1_fe *r, int a); diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index e107bee8a8..70be960f8a 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -264,15 +264,9 @@ static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) { return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { - VERIFY_CHECK(0 <= a && a <= 0x7FFF); +SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; -#ifdef VERIFY - r->magnitude = (a != 0); - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 1a8960ff1e..c735257f53 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -210,15 +210,9 @@ static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) { return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); } -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { - VERIFY_CHECK(0 <= a && a <= 0x7FFF); +SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; -#ifdef VERIFY - r->magnitude = (a != 0); - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { diff --git a/src/field_impl.h b/src/field_impl.h index ae54693859..0083aabc8d 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -185,6 +185,15 @@ SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_ secp256k1_fe_verify(r); return secp256k1_fe_impl_normalizes_to_zero_var(r); } + +static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a); +SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { + VERIFY_CHECK(0 <= a && a <= 0x7FFF); + secp256k1_fe_impl_set_int(r, a); + r->magnitude = (a != 0); + r->normalized = 1; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From c701d9a4719adff20fa83511f946e4abbd4d8cda Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 31 Jan 2022 17:15:41 -0500 Subject: [PATCH 08/29] Abstract out verify logic for fe_clear --- src/field.h | 7 ++++++- src/field_10x26_impl.h | 6 +----- src/field_5x52_impl.h | 6 +----- src/field_impl.h | 8 ++++++++ 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/field.h b/src/field.h index e841f14ee0..f6f3fa9f17 100644 --- a/src/field.h +++ b/src/field.h @@ -81,6 +81,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_normalizes_to_zero secp256k1_fe_impl_normalizes_to_zero # define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var # define secp256k1_fe_set_int secp256k1_fe_impl_set_int +# define secp256k1_fe_clear secp256k1_fe_impl_clear #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -123,7 +124,11 @@ static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r); */ static void secp256k1_fe_set_int(secp256k1_fe *r, int a); -/** Sets a field element equal to zero, initializing all fields. */ +/** Set a field element to 0. + * + * On input, a does not need to be initialized. + * On output, a represents 0, is normalized and has magnitude 0. + */ static void secp256k1_fe_clear(secp256k1_fe *a); /** Verify whether a field element is zero. Requires the input to be normalized. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 70be960f8a..7fc9993e00 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -286,12 +286,8 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { return a->n[0] & 1; } -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { +SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) { int i; -#ifdef VERIFY - a->magnitude = 0; - a->normalized = 1; -#endif for (i=0; i<10; i++) { a->n[i] = 0; } diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index c735257f53..d2c4a6ba25 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -232,12 +232,8 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { return a->n[0] & 1; } -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { +SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) { int i; -#ifdef VERIFY - a->magnitude = 0; - a->normalized = 1; -#endif for (i=0; i<5; i++) { a->n[i] = 0; } diff --git a/src/field_impl.h b/src/field_impl.h index 0083aabc8d..0eccf75023 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -194,6 +194,14 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { r->normalized = 1; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_clear(secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { + a->magnitude = 0; + a->normalized = 1; + secp256k1_fe_impl_clear(a); + secp256k1_fe_verify(a); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From d3f3fe8616d02bd1c62376c1318be69c64eea982 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:07:55 -0500 Subject: [PATCH 09/29] Abstract out verify logic for fe_is_zero --- src/field.h | 10 +++++++++- src/field_10x26_impl.h | 6 +----- src/field_5x52_impl.h | 6 +----- src/field_impl.h | 7 +++++++ 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/field.h b/src/field.h index f6f3fa9f17..c057472c28 100644 --- a/src/field.h +++ b/src/field.h @@ -82,6 +82,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var # define secp256k1_fe_set_int secp256k1_fe_impl_set_int # define secp256k1_fe_clear secp256k1_fe_impl_clear +# define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -131,7 +132,14 @@ static void secp256k1_fe_set_int(secp256k1_fe *r, int a); */ static void secp256k1_fe_clear(secp256k1_fe *a); -/** Verify whether a field element is zero. Requires the input to be normalized. */ +/** Determine whether a represents field element 0. + * + * On input, a must be a valid normalized field element. + * Returns whether a = 0 (mod p). + * + * This behaves identical to secp256k1_normalizes_to_zero{,_var}, but requires + * normalized input (and is much faster). + */ static int secp256k1_fe_is_zero(const secp256k1_fe *a); /** Check the "oddness" of a field element. Requires the input to be normalized. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 7fc9993e00..5e934c438c 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -269,12 +269,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) { r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; } -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { +SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) { const uint32_t *t = a->n; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0; } diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index d2c4a6ba25..0572d77bec 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -215,12 +215,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) { r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; } -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { +SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) { const uint64_t *t = a->n; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0; } diff --git a/src/field_impl.h b/src/field_impl.h index 0eccf75023..8c85134057 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -202,6 +202,13 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { secp256k1_fe_impl_clear(a); secp256k1_fe_verify(a); } + +static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a); +SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { + secp256k1_fe_verify(a); + VERIFY_CHECK(a->normalized); + return secp256k1_fe_impl_is_zero(a); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From c5e788d672d78315e7269fd3743eadae6428468e Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:11:21 -0500 Subject: [PATCH 10/29] Abstract out verify logic for fe_is_odd --- src/field.h | 7 ++++++- src/field_10x26_impl.h | 6 +----- src/field_5x52_impl.h | 6 +----- src/field_impl.h | 7 +++++++ 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/field.h b/src/field.h index c057472c28..9e517dca80 100644 --- a/src/field.h +++ b/src/field.h @@ -83,6 +83,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_set_int secp256k1_fe_impl_set_int # define secp256k1_fe_clear secp256k1_fe_impl_clear # define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero +# define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -142,7 +143,11 @@ static void secp256k1_fe_clear(secp256k1_fe *a); */ static int secp256k1_fe_is_zero(const secp256k1_fe *a); -/** Check the "oddness" of a field element. Requires the input to be normalized. */ +/** Determine whether a (mod p) is odd. + * + * On input, a must be a valid normalized field element. + * Returns (int(a) mod p) & 1. + */ static int secp256k1_fe_is_odd(const secp256k1_fe *a); /** Compare two field elements. Requires magnitude-1 inputs. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 5e934c438c..e7305abb3e 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -274,11 +274,7 @@ SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) { return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0; } -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) { return a->n[0] & 1; } diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 0572d77bec..31c3bcb7a6 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -220,11 +220,7 @@ SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) { return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0; } -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) { return a->n[0] & 1; } diff --git a/src/field_impl.h b/src/field_impl.h index 8c85134057..bd6982033c 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -209,6 +209,13 @@ SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { VERIFY_CHECK(a->normalized); return secp256k1_fe_impl_is_zero(a); } + +static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a); +SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { + secp256k1_fe_verify(a); + VERIFY_CHECK(a->normalized); + return secp256k1_fe_impl_is_odd(a); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 7d7d43c6dd2741853de4631881d77ae38a14cd23 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 31 Jan 2022 17:34:36 -0500 Subject: [PATCH 11/29] Improve comments/check for fe_equal{,_var} --- src/field.h | 12 ++++++++++-- src/field_impl.h | 12 ++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/field.h b/src/field.h index 9e517dca80..e7b64e78eb 100644 --- a/src/field.h +++ b/src/field.h @@ -150,10 +150,18 @@ static int secp256k1_fe_is_zero(const secp256k1_fe *a); */ static int secp256k1_fe_is_odd(const secp256k1_fe *a); -/** Compare two field elements. Requires magnitude-1 inputs. */ +/** Determine whether two field elements are equal. + * + * On input, a and b must be valid field elements with magnitudes not exceeding + * 1 and 31, respectively. + * Returns a = b (mod p). + */ static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b); -/** Same as secp256k1_fe_equal, but may be variable time. */ +/** Determine whether two field elements are equal, without constant-time guarantee. + * + * Identical in behavior to secp256k1_fe_equal, but not constant time in either a or b. + */ static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); /** Compare two field elements. Requires both inputs to be normalized */ diff --git a/src/field_impl.h b/src/field_impl.h index bd6982033c..dae82aa67e 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -20,6 +20,12 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { secp256k1_fe na; +#ifdef VERIFY + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); + VERIFY_CHECK(a->magnitude <= 1); + VERIFY_CHECK(b->magnitude <= 31); +#endif secp256k1_fe_negate(&na, a, 1); secp256k1_fe_add(&na, b); return secp256k1_fe_normalizes_to_zero(&na); @@ -27,6 +33,12 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) { secp256k1_fe na; +#ifdef VERIFY + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); + VERIFY_CHECK(a->magnitude <= 1); + VERIFY_CHECK(b->magnitude <= 31); +#endif secp256k1_fe_negate(&na, a, 1); secp256k1_fe_add(&na, b); return secp256k1_fe_normalizes_to_zero_var(&na); From ce4d2093e86fedca676dbbe59b50bdcf8c599704 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:16:16 -0500 Subject: [PATCH 12/29] Abstract out verify logic for fe_cmp_var --- src/field.h | 8 +++++++- src/field_10x26_impl.h | 8 +------- src/field_5x52_impl.h | 8 +------- src/field_impl.h | 9 +++++++++ 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/field.h b/src/field.h index e7b64e78eb..4145d89c80 100644 --- a/src/field.h +++ b/src/field.h @@ -84,6 +84,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_clear secp256k1_fe_impl_clear # define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero # define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd +# define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -164,7 +165,12 @@ static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b); */ static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); -/** Compare two field elements. Requires both inputs to be normalized */ +/** Compare the values represented by 2 field elements, without constant-time guarantee. + * + * On input, a and b must be valid normalized field elements. + * Returns 1 if a > b, -1 if a < b, and 0 if a = b (comparisons are done as integers + * in range 0..p-1). + */ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); /** Set a field element equal to 32-byte big endian value. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index e7305abb3e..a7a0186b71 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -285,14 +285,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) { } } -static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { +static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { int i; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); -#endif for (i = 9; i >= 0; i--) { if (a->n[i] > b->n[i]) { return 1; diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 31c3bcb7a6..b4af5d69a0 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -231,14 +231,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) { } } -static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { +static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { int i; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); -#endif for (i = 4; i >= 0; i--) { if (a->n[i] > b->n[i]) { return 1; diff --git a/src/field_impl.h b/src/field_impl.h index dae82aa67e..4424ddb173 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -228,6 +228,15 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { VERIFY_CHECK(a->normalized); return secp256k1_fe_impl_is_odd(a); } + +static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); +SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); + VERIFY_CHECK(a->normalized); + VERIFY_CHECK(b->normalized); + return secp256k1_fe_impl_cmp_var(a, b); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From f7a7666aeb8db92b9171f4765f7d405b7b73d946 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:19:00 -0500 Subject: [PATCH 13/29] Abstract out verify logic for fe_set_b32 --- src/field.h | 13 ++++++++++--- src/field_10x26_impl.h | 11 ++--------- src/field_5x52_impl.h | 11 ++--------- src/field_impl.h | 9 +++++++++ 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/field.h b/src/field.h index 4145d89c80..b1c434eaf6 100644 --- a/src/field.h +++ b/src/field.h @@ -85,6 +85,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero # define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd # define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var +# define secp256k1_fe_set_b32 secp256k1_fe_impl_set_b32 #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -173,9 +174,15 @@ static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); */ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); -/** Set a field element equal to 32-byte big endian value. - * Returns 1 if no overflow occurred, and then the output is normalized. - * Returns 0 if overflow occurred, and then the output is only weakly normalized. */ +/** Set a field element equal to a provided 32-byte big endian value. + * + * On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array. + * On output, r = a (mod p). It will have magnitude 1, and if (a < p), it will be normalized. + * If not, it will only be weakly normalized. Returns whether (a < p). + * + * Note that this function is unusual in that the normalization of the output depends on the + * run-time value of a. + */ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a); /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index a7a0186b71..5e0b65d652 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -298,8 +298,7 @@ static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe * return 0; } -static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { - int ret; +static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) { r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24); 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); 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); @@ -311,13 +310,7 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24); r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14); - ret = !((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)); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = ret; - secp256k1_fe_verify(r); -#endif - return ret; + 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)); } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index b4af5d69a0..b06b485b7f 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -244,8 +244,7 @@ static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe * return 0; } -static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { - int ret; +static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) { r->n[0] = (uint64_t)a[31] | ((uint64_t)a[30] << 8) | ((uint64_t)a[29] << 16) @@ -280,13 +279,7 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { | ((uint64_t)a[2] << 24) | ((uint64_t)a[1] << 32) | ((uint64_t)a[0] << 40); - ret = !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL)); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = ret; - secp256k1_fe_verify(r); -#endif - return ret; + return !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL)); } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ diff --git a/src/field_impl.h b/src/field_impl.h index 4424ddb173..304c428cb7 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -237,6 +237,15 @@ SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const se VERIFY_CHECK(b->normalized); return secp256k1_fe_impl_cmp_var(a, b); } + +static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a); +SECP256K1_INLINE static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { + int ret = secp256k1_fe_impl_set_b32(r, a); + r->magnitude = 1; + r->normalized = ret; + secp256k1_fe_verify(r); + return ret; +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 144670893eccd84d638951f6c5bae43fc97e3c7b Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:23:54 -0500 Subject: [PATCH 14/29] Abstract out verify logic for fe_get_b32 --- src/field.h | 6 +++++- src/field_10x26_impl.h | 6 +----- src/field_5x52_impl.h | 6 +----- src/field_impl.h | 7 +++++++ 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/field.h b/src/field.h index b1c434eaf6..327e63fc96 100644 --- a/src/field.h +++ b/src/field.h @@ -86,6 +86,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd # define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var # define secp256k1_fe_set_b32 secp256k1_fe_impl_set_b32 +# define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32 #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -185,7 +186,10 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); */ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a); -/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ +/** Convert a field element to 32-byte big endian byte array. + * On input, a must be a valid normalized field element, and r a pointer to a 32-byte array. + * On output, r = a (mod p). + */ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a); /** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 5e0b65d652..c3f49c86eb 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -314,11 +314,7 @@ static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) { } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif +static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) { r[0] = (a->n[9] >> 14) & 0xff; r[1] = (a->n[9] >> 6) & 0xff; r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3); diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index b06b485b7f..0994087c56 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -283,11 +283,7 @@ static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) { } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif +static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) { r[0] = (a->n[4] >> 40) & 0xFF; r[1] = (a->n[4] >> 32) & 0xFF; r[2] = (a->n[4] >> 24) & 0xFF; diff --git a/src/field_impl.h b/src/field_impl.h index 304c428cb7..a09c7a6be1 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -246,6 +246,13 @@ SECP256K1_INLINE static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned secp256k1_fe_verify(r); return ret; } + +static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { + secp256k1_fe_verify(a); + VERIFY_CHECK(a->normalized); + secp256k1_fe_impl_get_b32(r, a); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 65d82a3445265767375383a5b68b5f61aeadefca Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:27:38 -0500 Subject: [PATCH 15/29] Abstract out verify logic for fe_negate --- src/field.h | 10 ++++++++-- src/field_10x26_impl.h | 15 +++++---------- src/field_5x52_impl.h | 15 +++++---------- src/field_impl.h | 11 +++++++++++ 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/field.h b/src/field.h index 327e63fc96..b1bc4b979e 100644 --- a/src/field.h +++ b/src/field.h @@ -87,6 +87,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var # define secp256k1_fe_set_b32 secp256k1_fe_impl_set_b32 # define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32 +# define secp256k1_fe_negate secp256k1_fe_impl_negate #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -192,8 +193,13 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a); */ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a); -/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input - * as an argument. The magnitude of the output is one higher. */ +/** Negate a field element. + * + * On input, r does not need to be initialized. a must be a valid field element with + * magnitude not exceeding m. m must be an integer in [0,31]. + * Performs {r = -a}. + * On output, r will not be normalized, and will have magnitude m+1. + */ static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m); /** Adds a small integer (up to 0x7FFF) to r. The resulting magnitude increases by one. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index c3f49c86eb..9e29f6adf9 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -349,15 +349,15 @@ static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) { r[31] = a->n[0] & 0xff; } -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= m); - secp256k1_fe_verify(a); +SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { + /* For all legal values of m (0..31), the following properties hold: */ VERIFY_CHECK(0x3FFFC2FUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); VERIFY_CHECK(0x3FFFFBFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); VERIFY_CHECK(0x3FFFFFFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); VERIFY_CHECK(0x03FFFFFUL * 2 * (m + 1) >= 0x03FFFFFUL * 2 * m); -#endif + + /* Due to the properties above, the left hand in the subtractions below is never less than + * the right hand. */ r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0]; r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1]; r->n[2] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[2]; @@ -368,11 +368,6 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k r->n[7] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[7]; r->n[8] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[8]; r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9]; -#ifdef VERIFY - r->magnitude = m + 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 0994087c56..4775ee0cee 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -318,24 +318,19 @@ static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) { r[31] = a->n[0] & 0xFF; } -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= m); - secp256k1_fe_verify(a); +SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { + /* For all legal values of m (0..31), the following properties hold: */ VERIFY_CHECK(0xFFFFEFFFFFC2FULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m); VERIFY_CHECK(0xFFFFFFFFFFFFFULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m); VERIFY_CHECK(0x0FFFFFFFFFFFFULL * 2 * (m + 1) >= 0x0FFFFFFFFFFFFULL * 2 * m); -#endif + + /* Due to the properties above, the left hand in the subtractions below is never less than + * the right hand. */ r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0]; r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1]; r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2]; r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3]; r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4]; -#ifdef VERIFY - r->magnitude = m + 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { diff --git a/src/field_impl.h b/src/field_impl.h index a09c7a6be1..1c70795169 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -253,6 +253,17 @@ SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp25 VERIFY_CHECK(a->normalized); secp256k1_fe_impl_get_b32(r, a); } + +static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m); +SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { + secp256k1_fe_verify(a); + VERIFY_CHECK(m >= 0 && m <= 31); + VERIFY_CHECK(a->magnitude <= m); + secp256k1_fe_impl_negate(r, a, m); + r->magnitude = m + 1; + r->normalized = 0; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 7e7ad7ff570645304459242104406d6e1f79857c Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:33:45 -0500 Subject: [PATCH 16/29] Abstract out verify logic for fe_mul_int --- src/field.h | 10 ++++++++-- src/field_10x26_impl.h | 7 +------ src/field_5x52_impl.h | 7 +------ src/field_impl.h | 11 +++++++++++ 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/field.h b/src/field.h index b1bc4b979e..2c1e9d2e1a 100644 --- a/src/field.h +++ b/src/field.h @@ -88,6 +88,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_set_b32 secp256k1_fe_impl_set_b32 # define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32 # define secp256k1_fe_negate secp256k1_fe_impl_negate +# define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -205,8 +206,13 @@ static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m); /** Adds a small integer (up to 0x7FFF) to r. The resulting magnitude increases by one. */ static void secp256k1_fe_add_int(secp256k1_fe *r, int a); -/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that - * small integer. */ +/** Multiply a field element with a small integer. + * + * On input, r must be a valid field element. a must be an integer in [0,32]. + * The magnitude of r times a must not exceed 32. + * Performs {r *= a}. + * On output, r's magnitude is multiplied by a, and r will not be normalized. + */ static void secp256k1_fe_mul_int(secp256k1_fe *r, int a); /** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 9e29f6adf9..f8c8ddb5b4 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -370,7 +370,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const sec r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9]; } -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) { r->n[0] *= a; r->n[1] *= a; r->n[2] *= a; @@ -381,11 +381,6 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { r->n[7] *= a; r->n[8] *= a; r->n[9] *= a; -#ifdef VERIFY - r->magnitude *= a; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 4775ee0cee..f509137340 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -333,17 +333,12 @@ SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const sec r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4]; } -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) { r->n[0] *= a; r->n[1] *= a; r->n[2] *= a; r->n[3] *= a; r->n[4] *= a; -#ifdef VERIFY - r->magnitude *= a; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { diff --git a/src/field_impl.h b/src/field_impl.h index 1c70795169..8bd18c61ab 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -264,6 +264,17 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k r->normalized = 0; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a); +SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { + secp256k1_fe_verify(r); + VERIFY_CHECK(a >= 0 && a <= 32); + VERIFY_CHECK(a*r->magnitude <= 32); + secp256k1_fe_impl_mul_int(r, a); + r->magnitude *= a; + r->normalized = 0; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From e179e651cbb20031905e01f37596e20ec2cb788a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:36:13 -0500 Subject: [PATCH 17/29] Abstract out verify logic for fe_add --- src/field.h | 9 ++++++++- src/field_10x26_impl.h | 8 +------- src/field_5x52_impl.h | 8 +------- src/field_impl.h | 11 +++++++++++ 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/field.h b/src/field.h index 2c1e9d2e1a..988bc6f390 100644 --- a/src/field.h +++ b/src/field.h @@ -89,6 +89,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32 # define secp256k1_fe_negate secp256k1_fe_impl_negate # define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int +# define secp256k1_fe_add secp256k1_fe_impl_add #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -215,7 +216,13 @@ static void secp256k1_fe_add_int(secp256k1_fe *r, int a); */ static void secp256k1_fe_mul_int(secp256k1_fe *r, int a); -/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */ +/** Increment a field element by another. + * + * On input, r and a must be valid field elements, not necessarily normalized. + * The sum of their magnitudes must not exceed 32. + * Performs {r += a}. + * On output, r will not be normalized, and will have magnitude incremented by a's. + */ static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a); /** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index f8c8ddb5b4..eefd4da697 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -383,8 +383,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) { r->n[9] *= a; } -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { - secp256k1_fe_verify(a); +SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) { r->n[0] += a->n[0]; r->n[1] += a->n[1]; r->n[2] += a->n[2]; @@ -395,11 +394,6 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f r->n[7] += a->n[7]; r->n[8] += a->n[8]; r->n[9] += a->n[9]; -#ifdef VERIFY - r->magnitude += a->magnitude; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index f509137340..8bd084ff27 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -353,18 +353,12 @@ SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { #endif } -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { - secp256k1_fe_verify(a); +SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) { r->n[0] += a->n[0]; r->n[1] += a->n[1]; r->n[2] += a->n[2]; r->n[3] += a->n[3]; r->n[4] += a->n[4]; -#ifdef VERIFY - r->magnitude += a->magnitude; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { diff --git a/src/field_impl.h b/src/field_impl.h index 8bd18c61ab..172b846d89 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -275,6 +275,17 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { r->normalized = 0; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { + secp256k1_fe_verify(r); + secp256k1_fe_verify(a); + VERIFY_CHECK(r->magnitude + a->magnitude <= 32); + secp256k1_fe_impl_add(r, a); + r->magnitude += a->magnitude; + r->normalized = 0; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 4c25f6efbd5f8b4738c1c16daf73906d45c5f579 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:40:33 -0500 Subject: [PATCH 18/29] Abstract out verify logic for fe_mul --- src/field.h | 11 +++++++++-- src/field_10x26_impl.h | 15 +-------------- src/field_5x52_impl.h | 15 +-------------- src/field_impl.h | 14 ++++++++++++++ 4 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/field.h b/src/field.h index 988bc6f390..c301841b29 100644 --- a/src/field.h +++ b/src/field.h @@ -90,6 +90,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_negate secp256k1_fe_impl_negate # define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int # define secp256k1_fe_add secp256k1_fe_impl_add +# define secp256k1_fe_mul secp256k1_fe_impl_mul #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -225,8 +226,14 @@ static void secp256k1_fe_mul_int(secp256k1_fe *r, int a); */ static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a); -/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8. - * The output magnitude is 1 (but not guaranteed to be normalized). */ +/** Multiply two field elements. + * + * On input, a and b must be valid field elements; r does not need to be initialized. + * r and a may point to the same object, but neither can be equal to b. The magnitudes + * of a and b must not exceed 8. + * Performs {r = a * b} + * On output, r will have magnitude 1, but won't be normalized. + */ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); /** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index eefd4da697..f2cc4ad1e3 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1027,21 +1027,8 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t } #endif -static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - VERIFY_CHECK(b->magnitude <= 8); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); - VERIFY_CHECK(r != b); - VERIFY_CHECK(a != b); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { secp256k1_fe_mul_inner(r->n, a->n, b->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 8bd084ff27..adfac57778 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -361,21 +361,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp25 r->n[4] += a->n[4]; } -static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - VERIFY_CHECK(b->magnitude <= 8); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); - VERIFY_CHECK(r != b); - VERIFY_CHECK(a != b); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { secp256k1_fe_mul_inner(r->n, a->n, b->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { diff --git a/src/field_impl.h b/src/field_impl.h index 172b846d89..0def1e57d5 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -286,6 +286,20 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f r->normalized = 0; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); +SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); + VERIFY_CHECK(a->magnitude <= 8); + VERIFY_CHECK(b->magnitude <= 8); + VERIFY_CHECK(r != b); + VERIFY_CHECK(a != b); + secp256k1_fe_impl_mul(r, a, b); + r->magnitude = 1; + r->normalized = 0; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 6ab35082efe904cbb7ca5225134a1d3647e35388 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:42:47 -0500 Subject: [PATCH 19/29] Abstract out verify logic for fe_sqr --- src/field.h | 10 ++++++++-- src/field_10x26_impl.h | 11 +---------- src/field_5x52_impl.h | 11 +---------- src/field_impl.h | 10 ++++++++++ 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/field.h b/src/field.h index c301841b29..597c9fe338 100644 --- a/src/field.h +++ b/src/field.h @@ -91,6 +91,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int # define secp256k1_fe_add secp256k1_fe_impl_add # define secp256k1_fe_mul secp256k1_fe_impl_mul +# define secp256k1_fe_sqr secp256k1_fe_impl_sqr #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -236,8 +237,13 @@ static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a); */ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); -/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8. - * The output magnitude is 1 (but not guaranteed to be normalized). */ +/** Square a field element. + * + * On input, a must be a valid field element; r does not need to be initialized. The magnitude + * of a must not exceed 8. + * Performs {r = a**2} + * On output, r will have magnitude 1, but won't be normalized. + */ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); /** If a has a square root, it is computed in r and 1 is returned. If a does not diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index f2cc4ad1e3..f34f27bb3d 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1031,17 +1031,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp25 secp256k1_fe_mul_inner(r->n, a->n, b->n); } -static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) { secp256k1_fe_sqr_inner(r->n, a->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index adfac57778..5e90218c94 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -365,17 +365,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp25 secp256k1_fe_mul_inner(r->n, a->n, b->n); } -static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) { secp256k1_fe_sqr_inner(r->n, a->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { diff --git a/src/field_impl.h b/src/field_impl.h index 0def1e57d5..ff4c8eca18 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -300,6 +300,16 @@ SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_f r->normalized = 0; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { + secp256k1_fe_verify(a); + VERIFY_CHECK(a->magnitude <= 8); + secp256k1_fe_impl_sqr(r, a); + r->magnitude = 1; + r->normalized = 0; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From be82bd8e0347e090037ff1d30a22a9d614db8c9f Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 31 Jan 2022 18:19:45 -0500 Subject: [PATCH 20/29] Improve comments/checks for fe_sqrt --- src/field.h | 14 ++++++++------ src/field_impl.h | 17 +++++++++++++++-- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/field.h b/src/field.h index 597c9fe338..eb6c586b48 100644 --- a/src/field.h +++ b/src/field.h @@ -246,12 +246,14 @@ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp2 */ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); -/** If a has a square root, it is computed in r and 1 is returned. If a does not - * have a square root, the root of its negation is computed and 0 is returned. - * The input's magnitude can be at most 8. The output magnitude is 1 (but not - * guaranteed to be normalized). The result in r will always be a square - * itself. */ -static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a); +/** Compute a square root of a field element. + * + * On input, a must be a valid field element with magnitude<=8; r need not be initialized. + * Performs {r = sqrt(a)} or {r = sqrt(-a)}, whichever exists. The resulting value + * represented by r will be a square itself. Variables r and a must not point to the same object. + * On output, r will have magnitude 1 but will not be normalized. + */ +static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a); /** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ diff --git a/src/field_impl.h b/src/field_impl.h index ff4c8eca18..89ffc76cc5 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -55,9 +55,13 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) { * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). */ secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; - int j; + int j, ret; +#ifdef VERIFY VERIFY_CHECK(r != a); + secp256k1_fe_verify(a); + VERIFY_CHECK(a->magnitude <= 8); +#endif /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in * { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: @@ -141,7 +145,16 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) { /* Check that a square root was actually calculated */ secp256k1_fe_sqr(&t1, r); - return secp256k1_fe_equal(&t1, a); + ret = secp256k1_fe_equal(&t1, a); + +#ifdef VERIFY + if (!ret) { + secp256k1_fe_negate(&t1, &t1, 1); + secp256k1_fe_normalize_var(&t1); + VERIFY_CHECK(secp256k1_fe_equal_var(&t1, a)); + } +#endif + return ret; } #ifndef VERIFY From 1e6894bdd74c0b94224f2891c9f5501ac7a3b87a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:45:42 -0500 Subject: [PATCH 21/29] Abstract out verify logic for fe_cmov --- src/field.h | 8 +++++++- src/field_10x26_impl.h | 8 +------- src/field_5x52_impl.h | 8 +------- src/field_impl.h | 13 +++++++++++++ 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/field.h b/src/field.h index eb6c586b48..daa2c54066 100644 --- a/src/field.h +++ b/src/field.h @@ -92,6 +92,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_add secp256k1_fe_impl_add # define secp256k1_fe_mul secp256k1_fe_impl_mul # define secp256k1_fe_sqr secp256k1_fe_impl_sqr +# define secp256k1_fe_cmov secp256k1_fe_impl_cmov #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -271,7 +272,12 @@ static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storag /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag); -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +/** Conditionally move a field element in constant time. + * + * On input, both r and a must be valid field elements. Flag must be 0 or 1. + * Performs {r = flag ? a : r}. + * On output, r's magnitude and normalized will equal a's in case of flag=1, unchanged otherwise. + */ static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); /** Halves the value of a field element modulo the field prime. Constant-time. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index f34f27bb3d..6219150170 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1035,7 +1035,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp25 secp256k1_fe_sqr_inner(r->n, a->n); } -static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { +SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { uint32_t mask0, mask1; volatile int vflag = flag; SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); @@ -1051,12 +1051,6 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_ r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); -#ifdef VERIFY - if (flag) { - r->magnitude = a->magnitude; - r->normalized = a->normalized; - } -#endif } static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 5e90218c94..6a90ef4c4d 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -369,7 +369,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp25 secp256k1_fe_sqr_inner(r->n, a->n); } -static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { +SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { uint64_t mask0, mask1; volatile int vflag = flag; SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); @@ -380,12 +380,6 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_ r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); -#ifdef VERIFY - if (flag) { - r->magnitude = a->magnitude; - r->normalized = a->normalized; - } -#endif } static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { diff --git a/src/field_impl.h b/src/field_impl.h index 89ffc76cc5..bb1608d25c 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -323,6 +323,19 @@ SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_f r->normalized = 0; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); +SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { + VERIFY_CHECK(flag == 0 || flag == 1); + secp256k1_fe_verify(a); + secp256k1_fe_verify(r); + secp256k1_fe_impl_cmov(r, a, flag); + if (flag) { + r->magnitude = a->magnitude; + r->normalized = a->normalized; + } + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 76d31e5047c1d8dfb83b277421f11460f5126a03 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:56:54 -0500 Subject: [PATCH 22/29] Abstract out verify logic for fe_to_storage --- src/field.h | 7 ++++++- src/field_10x26_impl.h | 5 +---- src/field_5x52_impl.h | 5 +---- src/field_impl.h | 7 +++++++ 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/field.h b/src/field.h index daa2c54066..4928e256af 100644 --- a/src/field.h +++ b/src/field.h @@ -93,6 +93,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_mul secp256k1_fe_impl_mul # define secp256k1_fe_sqr secp256k1_fe_impl_sqr # define secp256k1_fe_cmov secp256k1_fe_impl_cmov +# define secp256k1_fe_to_storage secp256k1_fe_impl_to_storage #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -263,7 +264,11 @@ static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a); /** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); -/** Convert a field element to the storage type. */ +/** Convert a field element to secp256k1_fe_storage. + * + * On input, a must be a valid normalized field element. + * Performs {r = a}. + */ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); /** Convert a field element back from the storage type. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 6219150170..b0676eb937 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1145,10 +1145,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); } -static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif +static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { r->n[0] = a->n[0] | a->n[1] << 26; r->n[1] = a->n[1] >> 6 | a->n[2] << 20; r->n[2] = a->n[2] >> 12 | a->n[3] << 14; diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 6a90ef4c4d..d183b0bf7f 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -459,10 +459,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); } -static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif +static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { r->n[0] = a->n[0] | a->n[1] << 52; r->n[1] = a->n[1] >> 12 | a->n[2] << 40; r->n[2] = a->n[2] >> 24 | a->n[3] << 28; diff --git a/src/field_impl.h b/src/field_impl.h index bb1608d25c..fd0d56da25 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -336,6 +336,13 @@ SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_ } secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { + secp256k1_fe_verify(a); + VERIFY_CHECK(a->normalized); + secp256k1_fe_impl_to_storage(r, a); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 316764607257084e714898e07234fdc53150b57a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 19:02:03 -0500 Subject: [PATCH 23/29] Abstract out verify logic for fe_from_storage --- src/field.h | 8 +++++++- src/field_10x26_impl.h | 7 +------ src/field_5x52_impl.h | 7 +------ src/field_impl.h | 8 ++++++++ 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/field.h b/src/field.h index 4928e256af..cb330635dc 100644 --- a/src/field.h +++ b/src/field.h @@ -94,6 +94,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_sqr secp256k1_fe_impl_sqr # define secp256k1_fe_cmov secp256k1_fe_impl_cmov # define secp256k1_fe_to_storage secp256k1_fe_impl_to_storage +# define secp256k1_fe_from_storage secp256k1_fe_impl_from_storage #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -271,7 +272,12 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); */ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); -/** Convert a field element back from the storage type. */ +/** Convert a field element back from secp256k1_fe_storage. + * + * On input, r need not be initialized. + * Performs {r = a}. + * On output, r will be normalized and will have magnitude 1. + */ static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index b0676eb937..55d152ec26 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1156,7 +1156,7 @@ static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k r->n[7] = a->n[8] >> 16 | a->n[9] << 10; } -static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { +static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { r->n[0] = a->n[0] & 0x3FFFFFFUL; r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL); r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL); @@ -1167,11 +1167,6 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL); r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL); r->n[9] = a->n[7] >> 10; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32_signed30 *a) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index d183b0bf7f..1946fbb88b 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -466,17 +466,12 @@ static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k r->n[3] = a->n[3] >> 36 | a->n[4] << 16; } -static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { +static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL; r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL); r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL); r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL); r->n[4] = a->n[3] >> 16; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64_signed62 *a) { diff --git a/src/field_impl.h b/src/field_impl.h index fd0d56da25..0e1c7630be 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -343,6 +343,14 @@ SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, co VERIFY_CHECK(a->normalized); secp256k1_fe_impl_to_storage(r, a); } + +static void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); +SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { + secp256k1_fe_impl_from_storage(r, a); + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From d5aa2f035802047c45605bfa69fb467000e9288f Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 19:20:51 -0500 Subject: [PATCH 24/29] Abstract out verify logic for fe_inv{,_var} --- src/field.h | 16 +++++++++++++--- src/field_10x26_impl.h | 28 ++++------------------------ src/field_5x52_impl.h | 28 ++++------------------------ src/field_impl.h | 22 ++++++++++++++++++++++ 4 files changed, 43 insertions(+), 51 deletions(-) diff --git a/src/field.h b/src/field.h index cb330635dc..953919d9a3 100644 --- a/src/field.h +++ b/src/field.h @@ -95,6 +95,8 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_cmov secp256k1_fe_impl_cmov # define secp256k1_fe_to_storage secp256k1_fe_impl_to_storage # define secp256k1_fe_from_storage secp256k1_fe_impl_from_storage +# define secp256k1_fe_inv secp256k1_fe_impl_inv +# define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -258,11 +260,19 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); */ static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a); -/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be - * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ +/** Compute the modular inverse of a field element. + * + * On input, a must be a valid field element; r need not be initialized. + * Performs {r = a**(p-2)} (which maps 0 to 0, and every other element to its + * inverse). + * On output, r will have magnitude (a.magnitude != 0) and be normalized. + */ static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a); -/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */ +/** Compute the modular inverse of a field element, without constant-time guarantee. + * + * Behaves identically to secp256k1_fe_inv, but is not constant-time in a. + */ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); /** Convert a field element to secp256k1_fe_storage. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 55d152ec26..d7b30cc87d 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1197,12 +1197,6 @@ static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32 r->n[7] = (a6 >> 2 ) & M26; r->n[8] = (a6 >> 28 | a7 << 2) & M26; r->n[9] = (a7 >> 24 | a8 << 6); - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_fe *a) { @@ -1210,10 +1204,6 @@ static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp2 const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4], a5 = a->n[5], a6 = a->n[6], a7 = a->n[7], a8 = a->n[8], a9 = a->n[9]; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif - r->v[0] = (a0 | a1 << 26) & M30; r->v[1] = (a1 >> 4 | a2 << 22) & M30; r->v[2] = (a2 >> 8 | a3 << 18) & M30; @@ -1231,34 +1221,24 @@ static const secp256k1_modinv32_modinfo secp256k1_const_modinfo_fe = { 0x2DDACACFL }; -static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) { - secp256k1_fe tmp; +static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; secp256k1_modinv32_signed30 s; - tmp = *x; secp256k1_fe_normalize(&tmp); secp256k1_fe_to_signed30(&s, &tmp); secp256k1_modinv32(&s, &secp256k1_const_modinfo_fe); secp256k1_fe_from_signed30(r, &s); - -#ifdef VERIFY - VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp)); -#endif } -static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { - secp256k1_fe tmp; +static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; secp256k1_modinv32_signed30 s; - tmp = *x; secp256k1_fe_normalize_var(&tmp); secp256k1_fe_to_signed30(&s, &tmp); secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_fe); secp256k1_fe_from_signed30(r, &s); - -#ifdef VERIFY - VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp)); -#endif } static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 1946fbb88b..e056cc2620 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -492,22 +492,12 @@ static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64 r->n[2] = (a1 >> 42 | a2 << 20) & M52; r->n[3] = (a2 >> 32 | a3 << 30) & M52; r->n[4] = (a3 >> 22 | a4 << 40); - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_fe *a) { const uint64_t M62 = UINT64_MAX >> 2; const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4]; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif - r->v[0] = (a0 | a1 << 52) & M62; r->v[1] = (a1 >> 10 | a2 << 42) & M62; r->v[2] = (a2 >> 20 | a3 << 32) & M62; @@ -520,34 +510,24 @@ static const secp256k1_modinv64_modinfo secp256k1_const_modinfo_fe = { 0x27C7F6E22DDACACFLL }; -static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) { - secp256k1_fe tmp; +static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; secp256k1_modinv64_signed62 s; - tmp = *x; secp256k1_fe_normalize(&tmp); secp256k1_fe_to_signed62(&s, &tmp); secp256k1_modinv64(&s, &secp256k1_const_modinfo_fe); secp256k1_fe_from_signed62(r, &s); - -#ifdef VERIFY - VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp)); -#endif } -static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { - secp256k1_fe tmp; +static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; secp256k1_modinv64_signed62 s; - tmp = *x; secp256k1_fe_normalize_var(&tmp); secp256k1_fe_to_signed62(&s, &tmp); secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_fe); secp256k1_fe_from_signed62(r, &s); - -#ifdef VERIFY - VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp)); -#endif } static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { diff --git a/src/field_impl.h b/src/field_impl.h index 0e1c7630be..3c03e26352 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -351,6 +351,28 @@ SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const se r->normalized = 1; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x); +SECP256K1_INLINE static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) { + int input_is_zero = secp256k1_fe_normalizes_to_zero(x); + secp256k1_fe_verify(x); + secp256k1_fe_impl_inv(r, x); + r->magnitude = x->magnitude > 0; + r->normalized = 1; + VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero); + secp256k1_fe_verify(r); +} + +static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x); +SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { + int input_is_zero = secp256k1_fe_normalizes_to_zero(x); + secp256k1_fe_verify(x); + secp256k1_fe_impl_inv_var(r, x); + r->magnitude = x->magnitude > 0; + r->normalized = 1; + VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero); + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 283cd80ab471bccb995925eb55865f04e38566f4 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 8 Jun 2022 15:04:49 -0400 Subject: [PATCH 25/29] Abstract out verify logic for fe_get_bounds --- src/field.h | 6 ++++-- src/field_10x26_impl.h | 9 +-------- src/field_5x52_impl.h | 9 +-------- src/field_impl.h | 11 +++++++++++ 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/field.h b/src/field.h index 953919d9a3..4b23333eb0 100644 --- a/src/field.h +++ b/src/field.h @@ -97,6 +97,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_from_storage secp256k1_fe_impl_from_storage # define secp256k1_fe_inv secp256k1_fe_impl_inv # define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var +# define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -306,8 +307,9 @@ static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); * The output is not guaranteed to be normalized, regardless of the input. */ static void secp256k1_fe_half(secp256k1_fe *r); -/** Sets each limb of 'r' to its upper bound at magnitude 'm'. The output will also have its - * magnitude set to 'm' and is normalized if (and only if) 'm' is zero. */ +/** Sets r to a field element with magnitude m, normalized if (and only if) m==0. + * The value is chosen so that it is likely to trigger edge cases related to + * internal overflows. */ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m); /** Determine whether a is a square (modulo p). */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index d7b30cc87d..39588c0bf9 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -38,9 +38,7 @@ static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { } #endif -static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { - VERIFY_CHECK(m >= 0); - VERIFY_CHECK(m <= 2048); +static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) { r->n[0] = 0x3FFFFFFUL * 2 * m; r->n[1] = 0x3FFFFFFUL * 2 * m; r->n[2] = 0x3FFFFFFUL * 2 * m; @@ -51,11 +49,6 @@ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { r->n[7] = 0x3FFFFFFUL * 2 * m; r->n[8] = 0x3FFFFFFUL * 2 * m; r->n[9] = 0x03FFFFFUL * 2 * m; -#ifdef VERIFY - r->magnitude = m; - r->normalized = (m == 0); - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index e056cc2620..d9d4e1a7bd 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -37,19 +37,12 @@ static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { } #endif -static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { - VERIFY_CHECK(m >= 0); - VERIFY_CHECK(m <= 2048); +static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) { r->n[0] = 0xFFFFFFFFFFFFFULL * 2 * m; r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * m; r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * m; r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * m; r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * m; -#ifdef VERIFY - r->magnitude = m; - r->normalized = (m == 0); - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { diff --git a/src/field_impl.h b/src/field_impl.h index 3c03e26352..0eac34d10f 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -373,6 +373,17 @@ SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256 VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero); secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m); +SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) { + VERIFY_CHECK(m >= 0); + VERIFY_CHECK(m <= 32); + secp256k1_fe_impl_get_bounds(r, m); + r->magnitude = m; + r->normalized = (m == 0); + secp256k1_fe_verify(r); +} + #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 89e324c6b9d1c74d3636b4ef5b1e5404e3e2053b Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 17 Nov 2022 11:28:49 -0500 Subject: [PATCH 26/29] Abstract out verify logic for fe_half --- src/field.h | 10 +++++++--- src/field_10x26_impl.h | 17 +++-------------- src/field_5x52_impl.h | 17 +++-------------- src/field_impl.h | 10 ++++++++++ 4 files changed, 23 insertions(+), 31 deletions(-) diff --git a/src/field.h b/src/field.h index 4b23333eb0..c20638e45e 100644 --- a/src/field.h +++ b/src/field.h @@ -98,6 +98,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_inv secp256k1_fe_impl_inv # define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var # define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds +# define secp256k1_fe_half secp256k1_fe_impl_half #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -302,9 +303,12 @@ static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_f */ static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); -/** Halves the value of a field element modulo the field prime. Constant-time. - * For an input magnitude 'm', the output magnitude is set to 'floor(m/2) + 1'. - * The output is not guaranteed to be normalized, regardless of the input. */ +/** Halve the value of a field element modulo the field prime in constant-time. + * + * On input, r must be a valid field element. + * On output, r will be normalized and have magnitude floor(m/2) + 1 where m is + * the magnitude of r on input. + */ static void secp256k1_fe_half(secp256k1_fe *r); /** Sets r to a field element with magnitude m, normalized if (and only if) m==0. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 39588c0bf9..ec53165e88 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1046,17 +1046,12 @@ SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp2 r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); } -static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { +static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; uint32_t one = (uint32_t)1; uint32_t mask = -(t0 & one) >> 6; -#ifdef VERIFY - secp256k1_fe_verify(r); - VERIFY_CHECK(r->magnitude < 32); -#endif - /* Bounds analysis (over the rationals). * * Let m = r->magnitude @@ -1103,10 +1098,8 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { * * Current bounds: t0..t8 <= C * (m/2 + 1/2) * t9 <= D * (m/2 + 1/4) - */ - -#ifdef VERIFY - /* Therefore the output magnitude (M) has to be set such that: + * + * Therefore the output magnitude (M) has to be set such that: * t0..t8: C * M >= C * (m/2 + 1/2) * t9: D * M >= D * (m/2 + 1/4) * @@ -1116,10 +1109,6 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { * and since we want the smallest such integer value for M: * M == floor(m/2) + 1 */ - r->magnitude = (r->magnitude >> 1) + 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index d9d4e1a7bd..06a2e379ab 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -375,16 +375,11 @@ SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp2 r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); } -static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { +static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; uint64_t one = (uint64_t)1; uint64_t mask = -(t0 & one) >> 12; -#ifdef VERIFY - secp256k1_fe_verify(r); - VERIFY_CHECK(r->magnitude < 32); -#endif - /* Bounds analysis (over the rationals). * * Let m = r->magnitude @@ -421,10 +416,8 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { * * Current bounds: t0..t3 <= C * (m/2 + 1/2) * t4 <= D * (m/2 + 1/4) - */ - -#ifdef VERIFY - /* Therefore the output magnitude (M) has to be set such that: + * + * Therefore the output magnitude (M) has to be set such that: * t0..t3: C * M >= C * (m/2 + 1/2) * t4: D * M >= D * (m/2 + 1/4) * @@ -434,10 +427,6 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { * and since we want the smallest such integer value for M: * M == floor(m/2) + 1 */ - r->magnitude = (r->magnitude >> 1) + 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { diff --git a/src/field_impl.h b/src/field_impl.h index 0eac34d10f..8dbc765f73 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -384,6 +384,16 @@ SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) { secp256k1_fe_verify(r); } +static void secp256k1_fe_impl_half(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_half(secp256k1_fe *r) { + secp256k1_fe_verify(r); + VERIFY_CHECK(r->magnitude < 32); + secp256k1_fe_impl_half(r); + r->magnitude = (r->magnitude >> 1) + 1; + r->normalized = 0; + secp256k1_fe_verify(r); +} + #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 4371f98346b0a50c0a77e93948fe5e21d9346d06 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 11 May 2023 03:05:35 -0400 Subject: [PATCH 27/29] Abstract out verify logic for fe_add_int --- src/field.h | 7 ++++++- src/field_10x26_impl.h | 10 +--------- src/field_5x52_impl.h | 10 +--------- src/field_impl.h | 10 ++++++++++ 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/field.h b/src/field.h index c20638e45e..a515f38095 100644 --- a/src/field.h +++ b/src/field.h @@ -99,6 +99,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var # define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds # define secp256k1_fe_half secp256k1_fe_impl_half +# define secp256k1_fe_add_int secp256k1_fe_impl_add_int #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -213,7 +214,11 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a); */ static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m); -/** Adds a small integer (up to 0x7FFF) to r. The resulting magnitude increases by one. */ +/** Add a small integer to a field element. + * + * Performs {r += a}. The magnitude of r increases by 1, and normalized is cleared. + * a must be in range [0,0xFFFF]. + */ static void secp256k1_fe_add_int(secp256k1_fe *r, int a); /** Multiply a field element with a small integer. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index ec53165e88..80f32aa460 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -389,16 +389,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp25 r->n[9] += a->n[9]; } -SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { - secp256k1_fe_verify(r); - VERIFY_CHECK(a >= 0); - VERIFY_CHECK(a <= 0x7FFF); +SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) { r->n[0] += a; -#ifdef VERIFY - r->magnitude += 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } #if defined(USE_EXTERNAL_ASM) diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 06a2e379ab..a9a436dec0 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -334,16 +334,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) { r->n[4] *= a; } -SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { - secp256k1_fe_verify(r); - VERIFY_CHECK(a >= 0); - VERIFY_CHECK(a <= 0x7FFF); +SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) { r->n[0] += a; -#ifdef VERIFY - r->magnitude += 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) { diff --git a/src/field_impl.h b/src/field_impl.h index 8dbc765f73..0d46b313d5 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -220,6 +220,16 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { secp256k1_fe_verify(r); } +static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a); +SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { + VERIFY_CHECK(0 <= a && a <= 0x7FFF); + secp256k1_fe_verify(r); + secp256k1_fe_impl_add_int(r, a); + r->magnitude += 1; + r->normalized = 0; + secp256k1_fe_verify(r); +} + static void secp256k1_fe_impl_clear(secp256k1_fe *a); SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { a->magnitude = 0; From 4e176ad5b94f989d5e2c6cdf9b2761a6f6a971e5 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 11 May 2023 03:16:00 -0400 Subject: [PATCH 28/29] Abstract out verify logic for fe_is_square_var --- src/field.h | 6 +++++- src/field_10x26_impl.h | 6 +----- src/field_5x52_impl.h | 6 +----- src/field_impl.h | 11 +++++++++++ 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/field.h b/src/field.h index a515f38095..2c8fbc28e3 100644 --- a/src/field.h +++ b/src/field.h @@ -100,6 +100,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds # define secp256k1_fe_half secp256k1_fe_impl_half # define secp256k1_fe_add_int secp256k1_fe_impl_add_int +# define secp256k1_fe_is_square_var secp256k1_fe_impl_is_square_var #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -321,7 +322,10 @@ static void secp256k1_fe_half(secp256k1_fe *r); * internal overflows. */ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m); -/** Determine whether a is a square (modulo p). */ +/** Determine whether a is a square (modulo p). + * + * On input, a must be a valid field element. + */ static int secp256k1_fe_is_square_var(const secp256k1_fe *a); /** Check invariants on a field element (no-op unless VERIFY is enabled). */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 80f32aa460..946c95fb2f 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1215,7 +1215,7 @@ static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { secp256k1_fe_from_signed30(r, &s); } -static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { +static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) { secp256k1_fe tmp; secp256k1_modinv32_signed30 s; int jac, ret; @@ -1233,10 +1233,6 @@ static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { secp256k1_fe dummy; ret = secp256k1_fe_sqrt(&dummy, &tmp); } else { -#ifdef VERIFY - secp256k1_fe dummy; - VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1); -#endif ret = jac >= 0; } return ret; diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index a9a436dec0..f947903675 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -504,7 +504,7 @@ static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { secp256k1_fe_from_signed62(r, &s); } -static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { +static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) { secp256k1_fe tmp; secp256k1_modinv64_signed62 s; int jac, ret; @@ -522,10 +522,6 @@ static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { secp256k1_fe dummy; ret = secp256k1_fe_sqrt(&dummy, &tmp); } else { -#ifdef VERIFY - secp256k1_fe dummy; - VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1); -#endif ret = jac >= 0; } return ret; diff --git a/src/field_impl.h b/src/field_impl.h index 0d46b313d5..187ffc8d8b 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -384,6 +384,17 @@ SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256 secp256k1_fe_verify(r); } +static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x); +SECP256K1_INLINE static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { + int ret; + secp256k1_fe tmp = *x, sqrt; + secp256k1_fe_verify(x); + ret = secp256k1_fe_impl_is_square_var(x); + secp256k1_fe_normalize_weak(&tmp); + VERIFY_CHECK(ret == secp256k1_fe_sqrt(&sqrt, &tmp)); + return ret; +} + static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m); SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) { VERIFY_CHECK(m >= 0); From 7fc642fa25ad03ebd95cfe237b625dfb6dfdfa94 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 11 May 2023 04:42:09 -0400 Subject: [PATCH 29/29] Simplify secp256k1_fe_{impl_,}verify --- src/field_10x26_impl.h | 27 +++++++++++++-------------- src/field_5x52_impl.h | 17 ++++++++--------- src/field_impl.h | 7 +++---- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 946c95fb2f..3f719c161f 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -15,26 +15,25 @@ #ifdef VERIFY static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { const uint32_t *d = a->n; - int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; - r &= (d[0] <= 0x3FFFFFFUL * m); - r &= (d[1] <= 0x3FFFFFFUL * m); - r &= (d[2] <= 0x3FFFFFFUL * m); - r &= (d[3] <= 0x3FFFFFFUL * m); - r &= (d[4] <= 0x3FFFFFFUL * m); - r &= (d[5] <= 0x3FFFFFFUL * m); - r &= (d[6] <= 0x3FFFFFFUL * m); - r &= (d[7] <= 0x3FFFFFFUL * m); - r &= (d[8] <= 0x3FFFFFFUL * m); - r &= (d[9] <= 0x03FFFFFUL * m); + int m = a->normalized ? 1 : 2 * a->magnitude; + VERIFY_CHECK(d[0] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[1] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[2] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[3] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[4] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[5] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[6] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[7] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[8] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[9] <= 0x03FFFFFUL * m); if (a->normalized) { - if (r && (d[9] == 0x03FFFFFUL)) { + if (d[9] == 0x03FFFFFUL) { uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2]; if (mid == 0x3FFFFFFUL) { - r &= ((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL); + VERIFY_CHECK((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL); } } } - VERIFY_CHECK(r == 1); } #endif diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index f947903675..a44a64b5a1 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -21,19 +21,18 @@ #ifdef VERIFY static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { const uint64_t *d = a->n; - int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; + int m = a->normalized ? 1 : 2 * a->magnitude; /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ - r &= (d[0] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[1] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[0] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[1] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[2] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[3] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[4] <= 0x0FFFFFFFFFFFFULL * m); if (a->normalized) { - if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { - r &= (d[0] < 0xFFFFEFFFFFC2FULL); + if ((d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { + VERIFY_CHECK(d[0] < 0xFFFFEFFFFFC2FULL); } } - VERIFY_CHECK(r == 1); } #endif diff --git a/src/field_impl.h b/src/field_impl.h index 187ffc8d8b..c082d8f553 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -163,12 +163,11 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; } static void secp256k1_fe_impl_verify(const secp256k1_fe *a); static void secp256k1_fe_verify(const secp256k1_fe *a) { /* Magnitude between 0 and 32. */ - int r = (a->magnitude >= 0) & (a->magnitude <= 32); + VERIFY_CHECK((a->magnitude >= 0) && (a->magnitude <= 32)); /* Normalized is 0 or 1. */ - r &= (a->normalized == 0) | (a->normalized == 1); + VERIFY_CHECK((a->normalized == 0) || (a->normalized == 1)); /* If normalized, magnitude must be 0 or 1. */ - if (a->normalized) r &= (a->magnitude <= 1); - VERIFY_CHECK(r == 1); + if (a->normalized) VERIFY_CHECK(a->magnitude <= 1); /* Invoke implementation-specific checks. */ secp256k1_fe_impl_verify(a); }