@@ -73,33 +73,15 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) {
73
73
uint32_t t0 = r -> n [0 ], t1 = r -> n [1 ], t2 = r -> n [2 ], t3 = r -> n [3 ], t4 = r -> n [4 ],
74
74
t5 = r -> n [5 ], t6 = r -> n [6 ], t7 = r -> n [7 ], t8 = r -> n [8 ], t9 = r -> n [9 ];
75
75
76
- /* Reduce t9 at the start so there will be at most a single carry from the first pass */
77
- uint32_t m ;
78
- uint32_t x = t9 >> 22 ; t9 &= 0x03FFFFFUL ;
76
+ /* Reduce t9 at the start so there will be at most a single carry from the first pass.
77
+ * x is incremented before the first pass and then decremented before the second pass
78
+ * to ensure that the result doesn't fall into the range [P, 2^256). */
79
+ uint32_t x = (t9 >> 22 ) + 1 ; t9 &= 0x03FFFFFUL ;
79
80
80
81
/* The first pass ensures the magnitude is 1, ... */
81
82
t0 += x * 0x3D1UL ; t1 += (x << 6 );
82
83
t1 += (t0 >> 26 ); t0 &= 0x3FFFFFFUL ;
83
84
t2 += (t1 >> 26 ); t1 &= 0x3FFFFFFUL ;
84
- t3 += (t2 >> 26 ); t2 &= 0x3FFFFFFUL ; m = t2 ;
85
- t4 += (t3 >> 26 ); t3 &= 0x3FFFFFFUL ; m &= t3 ;
86
- t5 += (t4 >> 26 ); t4 &= 0x3FFFFFFUL ; m &= t4 ;
87
- t6 += (t5 >> 26 ); t5 &= 0x3FFFFFFUL ; m &= t5 ;
88
- t7 += (t6 >> 26 ); t6 &= 0x3FFFFFFUL ; m &= t6 ;
89
- t8 += (t7 >> 26 ); t7 &= 0x3FFFFFFUL ; m &= t7 ;
90
- t9 += (t8 >> 26 ); t8 &= 0x3FFFFFFUL ; m &= t8 ;
91
-
92
- /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */
93
- VERIFY_CHECK (t9 >> 23 == 0 );
94
-
95
- /* At most a single final reduction is needed; check if the value is >= the field characteristic */
96
- x = (t9 >> 22 ) | ((t9 == 0x03FFFFFUL ) & (m == 0x3FFFFFFUL )
97
- & ((t1 + 0x40UL + ((t0 + 0x3D1UL ) >> 26 )) > 0x3FFFFFFUL ));
98
-
99
- /* Apply the final reduction (for constant-time behaviour, we do it always) */
100
- t0 += x * 0x3D1UL ; t1 += (x << 6 );
101
- t1 += (t0 >> 26 ); t0 &= 0x3FFFFFFUL ;
102
- t2 += (t1 >> 26 ); t1 &= 0x3FFFFFFUL ;
103
85
t3 += (t2 >> 26 ); t2 &= 0x3FFFFFFUL ;
104
86
t4 += (t3 >> 26 ); t3 &= 0x3FFFFFFUL ;
105
87
t5 += (t4 >> 26 ); t4 &= 0x3FFFFFFUL ;
@@ -108,11 +90,24 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) {
108
90
t8 += (t7 >> 26 ); t7 &= 0x3FFFFFFUL ;
109
91
t9 += (t8 >> 26 ); t8 &= 0x3FFFFFFUL ;
110
92
111
- /* If t9 didn't carry to bit 22 already, then it should have after any final reduction */
112
- VERIFY_CHECK (t9 >> 22 == x );
93
+ /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */
94
+ VERIFY_CHECK (t9 >> 23 == 0 );
113
95
114
- /* Mask off the possible multiple of 2^256 from the final reduction */
115
- t9 &= 0x03FFFFFUL ;
96
+ /* The second pass subtracts (2^256 - P) from (t0..t9) iff there was no carry.
97
+ * No underflow is possible as we just added at least that amount in the first pass. */
98
+ x = (t9 >> 22 ) - 1 ; t9 &= 0x03FFFFFUL ;
99
+ VERIFY_CHECK (x == 0 || x == - (uint32_t )1 );
100
+
101
+ t0 -= x & 0x3D1UL ; t1 -= x & 0x40UL ;
102
+ t1 -= (t0 >> 31 ); t0 &= 0x3FFFFFFUL ;
103
+ t2 -= (t1 >> 31 ); t1 &= 0x3FFFFFFUL ;
104
+ t3 -= (t2 >> 31 ); t2 &= 0x3FFFFFFUL ;
105
+ t4 -= (t3 >> 31 ); t3 &= 0x3FFFFFFUL ;
106
+ t5 -= (t4 >> 31 ); t4 &= 0x3FFFFFFUL ;
107
+ t6 -= (t5 >> 31 ); t5 &= 0x3FFFFFFUL ;
108
+ t7 -= (t6 >> 31 ); t6 &= 0x3FFFFFFUL ;
109
+ t8 -= (t7 >> 31 ); t7 &= 0x3FFFFFFUL ;
110
+ t9 -= (t8 >> 31 ); t8 &= 0x3FFFFFFUL ;
116
111
117
112
r -> n [0 ] = t0 ; r -> n [1 ] = t1 ; r -> n [2 ] = t2 ; r -> n [3 ] = t3 ; r -> n [4 ] = t4 ;
118
113
r -> n [5 ] = t5 ; r -> n [6 ] = t6 ; r -> n [7 ] = t7 ; r -> n [8 ] = t8 ; r -> n [9 ] = t9 ;
@@ -215,29 +210,32 @@ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
215
210
uint32_t t0 = r -> n [0 ], t1 = r -> n [1 ], t2 = r -> n [2 ], t3 = r -> n [3 ], t4 = r -> n [4 ],
216
211
t5 = r -> n [5 ], t6 = r -> n [6 ], t7 = r -> n [7 ], t8 = r -> n [8 ], t9 = r -> n [9 ];
217
212
218
- /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */
219
- uint32_t z0 , z1 ;
213
+ /* z1 tracks a possible raw value of 0, z2 tracks a possible raw value of P */
214
+ uint32_t z0 , z1 , z2 ;
220
215
221
- /* Reduce t9 at the start so there will be at most a single carry from the first pass */
222
- uint32_t x = t9 >> 22 ; t9 &= 0x03FFFFFUL ;
216
+ /* Reduce t9 at the start so there will be at most a single carry from the first pass
217
+ * x is incremented before the first pass so both match values have internal zeros */
218
+ uint32_t x = (t9 >> 22 ) + 1 ; t9 &= 0x03FFFFFUL ;
223
219
224
220
/* The first pass ensures the magnitude is 1, ... */
225
221
t0 += x * 0x3D1UL ; t1 += (x << 6 );
226
- t1 += (t0 >> 26 ); t0 &= 0x3FFFFFFUL ; z0 = t0 ; z1 = t0 ^ 0x3D0UL ;
227
- t2 += (t1 >> 26 ); t1 &= 0x3FFFFFFUL ; z0 |= t1 ; z1 &= t1 ^ 0x40UL ;
228
- t3 += (t2 >> 26 ); t2 &= 0x3FFFFFFUL ; z0 |= t2 ; z1 &= t2 ;
229
- t4 += (t3 >> 26 ); t3 &= 0x3FFFFFFUL ; z0 |= t3 ; z1 &= t3 ;
230
- t5 += (t4 >> 26 ); t4 &= 0x3FFFFFFUL ; z0 |= t4 ; z1 &= t4 ;
231
- t6 += (t5 >> 26 ); t5 &= 0x3FFFFFFUL ; z0 |= t5 ; z1 &= t5 ;
232
- t7 += (t6 >> 26 ); t6 &= 0x3FFFFFFUL ; z0 |= t6 ; z1 &= t6 ;
233
- t8 += (t7 >> 26 ); t7 &= 0x3FFFFFFUL ; z0 |= t7 ; z1 &= t7 ;
234
- t9 += (t8 >> 26 ); t8 &= 0x3FFFFFFUL ; z0 |= t8 ; z1 &= t8 ;
235
- z0 |= t9 ; z1 &= t9 ^ 0x3C00000UL ;
222
+ t1 += (t0 >> 26 ); t0 &= 0x3FFFFFFUL ;
223
+ t2 += (t1 >> 26 ); t1 &= 0x3FFFFFFUL ;
224
+ t3 += (t2 >> 26 ); t2 &= 0x3FFFFFFUL ; z0 = t2 ;
225
+ t4 += (t3 >> 26 ); t3 &= 0x3FFFFFFUL ; z0 |= t3 ;
226
+ t5 += (t4 >> 26 ); t4 &= 0x3FFFFFFUL ; z0 |= t4 ;
227
+ t6 += (t5 >> 26 ); t5 &= 0x3FFFFFFUL ; z0 |= t5 ;
228
+ t7 += (t6 >> 26 ); t6 &= 0x3FFFFFFUL ; z0 |= t6 ;
229
+ t8 += (t7 >> 26 ); t7 &= 0x3FFFFFFUL ; z0 |= t7 ;
230
+ t9 += (t8 >> 26 ); t8 &= 0x3FFFFFFUL ; z0 |= t8 ;
231
+
232
+ z1 = z0 | (t0 ^ 0x3D1UL ) | (t1 ^ 0x40UL ) | t9 ;
233
+ z2 = z0 | t0 | t1 | (t9 ^ 0x400000UL );
236
234
237
235
/* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */
238
236
VERIFY_CHECK (t9 >> 23 == 0 );
239
237
240
- return (z0 == 0 ) | (z1 == 0x3FFFFFFUL );
238
+ return (z1 == 0 ) | (z2 == 0 );
241
239
}
242
240
243
241
static int secp256k1_fe_normalizes_to_zero_var (const secp256k1_fe * r ) {
0 commit comments