@@ -53,33 +53,15 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) {
53
53
uint32_t t0 = r -> n [0 ], t1 = r -> n [1 ], t2 = r -> n [2 ], t3 = r -> n [3 ], t4 = r -> n [4 ],
54
54
t5 = r -> n [5 ], t6 = r -> n [6 ], t7 = r -> n [7 ], t8 = r -> n [8 ], t9 = r -> n [9 ];
55
55
56
- /* Reduce t9 at the start so there will be at most a single carry from the first pass */
57
- uint32_t m ;
58
- uint32_t x = t9 >> 22 ; t9 &= 0x03FFFFFUL ;
56
+ /* Reduce t9 at the start so there will be at most a single carry from the first pass.
57
+ * x is incremented before the first pass and then decremented before the second pass
58
+ * to ensure that the result doesn't fall into the range [P, 2^256). */
59
+ uint32_t x = (t9 >> 22 ) + 1 ; t9 &= 0x03FFFFFUL ;
59
60
60
61
/* The first pass ensures the magnitude is 1, ... */
61
62
t0 += x * 0x3D1UL ; t1 += (x << 6 );
62
63
t1 += (t0 >> 26 ); t0 &= 0x3FFFFFFUL ;
63
64
t2 += (t1 >> 26 ); t1 &= 0x3FFFFFFUL ;
64
- t3 += (t2 >> 26 ); t2 &= 0x3FFFFFFUL ; m = t2 ;
65
- t4 += (t3 >> 26 ); t3 &= 0x3FFFFFFUL ; m &= t3 ;
66
- t5 += (t4 >> 26 ); t4 &= 0x3FFFFFFUL ; m &= t4 ;
67
- t6 += (t5 >> 26 ); t5 &= 0x3FFFFFFUL ; m &= t5 ;
68
- t7 += (t6 >> 26 ); t6 &= 0x3FFFFFFUL ; m &= t6 ;
69
- t8 += (t7 >> 26 ); t7 &= 0x3FFFFFFUL ; m &= t7 ;
70
- t9 += (t8 >> 26 ); t8 &= 0x3FFFFFFUL ; m &= t8 ;
71
-
72
- /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */
73
- VERIFY_CHECK (t9 >> 23 == 0 );
74
-
75
- /* At most a single final reduction is needed; check if the value is >= the field characteristic */
76
- x = (t9 >> 22 ) | ((t9 == 0x03FFFFFUL ) & (m == 0x3FFFFFFUL )
77
- & ((t1 + 0x40UL + ((t0 + 0x3D1UL ) >> 26 )) > 0x3FFFFFFUL ));
78
-
79
- /* Apply the final reduction (for constant-time behaviour, we do it always) */
80
- t0 += x * 0x3D1UL ; t1 += (x << 6 );
81
- t1 += (t0 >> 26 ); t0 &= 0x3FFFFFFUL ;
82
- t2 += (t1 >> 26 ); t1 &= 0x3FFFFFFUL ;
83
65
t3 += (t2 >> 26 ); t2 &= 0x3FFFFFFUL ;
84
66
t4 += (t3 >> 26 ); t3 &= 0x3FFFFFFUL ;
85
67
t5 += (t4 >> 26 ); t4 &= 0x3FFFFFFUL ;
@@ -88,11 +70,24 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) {
88
70
t8 += (t7 >> 26 ); t7 &= 0x3FFFFFFUL ;
89
71
t9 += (t8 >> 26 ); t8 &= 0x3FFFFFFUL ;
90
72
91
- /* If t9 didn't carry to bit 22 already, then it should have after any final reduction */
92
- VERIFY_CHECK (t9 >> 22 == x );
73
+ /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */
74
+ VERIFY_CHECK (t9 >> 23 == 0 );
93
75
94
- /* Mask off the possible multiple of 2^256 from the final reduction */
95
- t9 &= 0x03FFFFFUL ;
76
+ /* The second pass subtracts (2^256 - P) from (t0..t9) iff there was no carry.
77
+ * No underflow is possible as we just added at least that amount in the first pass. */
78
+ x = (t9 >> 22 ) - 1 ; t9 &= 0x03FFFFFUL ;
79
+ VERIFY_CHECK (x == 0 || x == - (uint32_t )1 );
80
+
81
+ t0 -= x & 0x3D1UL ; t1 -= x & 0x40UL ;
82
+ t1 -= (t0 >> 31 ); t0 &= 0x3FFFFFFUL ;
83
+ t2 -= (t1 >> 31 ); t1 &= 0x3FFFFFFUL ;
84
+ t3 -= (t2 >> 31 ); t2 &= 0x3FFFFFFUL ;
85
+ t4 -= (t3 >> 31 ); t3 &= 0x3FFFFFFUL ;
86
+ t5 -= (t4 >> 31 ); t4 &= 0x3FFFFFFUL ;
87
+ t6 -= (t5 >> 31 ); t5 &= 0x3FFFFFFUL ;
88
+ t7 -= (t6 >> 31 ); t6 &= 0x3FFFFFFUL ;
89
+ t8 -= (t7 >> 31 ); t7 &= 0x3FFFFFFUL ;
90
+ t9 -= (t8 >> 31 ); t8 &= 0x3FFFFFFUL ;
96
91
97
92
r -> n [0 ] = t0 ; r -> n [1 ] = t1 ; r -> n [2 ] = t2 ; r -> n [3 ] = t3 ; r -> n [4 ] = t4 ;
98
93
r -> n [5 ] = t5 ; r -> n [6 ] = t6 ; r -> n [7 ] = t7 ; r -> n [8 ] = t8 ; r -> n [9 ] = t9 ;
@@ -195,29 +190,32 @@ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
195
190
uint32_t t0 = r -> n [0 ], t1 = r -> n [1 ], t2 = r -> n [2 ], t3 = r -> n [3 ], t4 = r -> n [4 ],
196
191
t5 = r -> n [5 ], t6 = r -> n [6 ], t7 = r -> n [7 ], t8 = r -> n [8 ], t9 = r -> n [9 ];
197
192
198
- /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */
199
- uint32_t z0 , z1 ;
193
+ /* z1 tracks a possible raw value of 0, z2 tracks a possible raw value of P */
194
+ uint32_t z0 , z1 , z2 ;
200
195
201
- /* Reduce t9 at the start so there will be at most a single carry from the first pass */
202
- uint32_t x = t9 >> 22 ; t9 &= 0x03FFFFFUL ;
196
+ /* Reduce t9 at the start so there will be at most a single carry from the first pass
197
+ * x is incremented before the first pass so both match values have internal zeros */
198
+ uint32_t x = (t9 >> 22 ) + 1 ; t9 &= 0x03FFFFFUL ;
203
199
204
200
/* The first pass ensures the magnitude is 1, ... */
205
201
t0 += x * 0x3D1UL ; t1 += (x << 6 );
206
- t1 += (t0 >> 26 ); t0 &= 0x3FFFFFFUL ; z0 = t0 ; z1 = t0 ^ 0x3D0UL ;
207
- t2 += (t1 >> 26 ); t1 &= 0x3FFFFFFUL ; z0 |= t1 ; z1 &= t1 ^ 0x40UL ;
208
- t3 += (t2 >> 26 ); t2 &= 0x3FFFFFFUL ; z0 |= t2 ; z1 &= t2 ;
209
- t4 += (t3 >> 26 ); t3 &= 0x3FFFFFFUL ; z0 |= t3 ; z1 &= t3 ;
210
- t5 += (t4 >> 26 ); t4 &= 0x3FFFFFFUL ; z0 |= t4 ; z1 &= t4 ;
211
- t6 += (t5 >> 26 ); t5 &= 0x3FFFFFFUL ; z0 |= t5 ; z1 &= t5 ;
212
- t7 += (t6 >> 26 ); t6 &= 0x3FFFFFFUL ; z0 |= t6 ; z1 &= t6 ;
213
- t8 += (t7 >> 26 ); t7 &= 0x3FFFFFFUL ; z0 |= t7 ; z1 &= t7 ;
214
- t9 += (t8 >> 26 ); t8 &= 0x3FFFFFFUL ; z0 |= t8 ; z1 &= t8 ;
215
- z0 |= t9 ; z1 &= t9 ^ 0x3C00000UL ;
202
+ t1 += (t0 >> 26 ); t0 &= 0x3FFFFFFUL ;
203
+ t2 += (t1 >> 26 ); t1 &= 0x3FFFFFFUL ;
204
+ t3 += (t2 >> 26 ); t2 &= 0x3FFFFFFUL ; z0 = t2 ;
205
+ t4 += (t3 >> 26 ); t3 &= 0x3FFFFFFUL ; z0 |= t3 ;
206
+ t5 += (t4 >> 26 ); t4 &= 0x3FFFFFFUL ; z0 |= t4 ;
207
+ t6 += (t5 >> 26 ); t5 &= 0x3FFFFFFUL ; z0 |= t5 ;
208
+ t7 += (t6 >> 26 ); t6 &= 0x3FFFFFFUL ; z0 |= t6 ;
209
+ t8 += (t7 >> 26 ); t7 &= 0x3FFFFFFUL ; z0 |= t7 ;
210
+ t9 += (t8 >> 26 ); t8 &= 0x3FFFFFFUL ; z0 |= t8 ;
211
+
212
+ z1 = z0 | (t0 ^ 0x3D1UL ) | (t1 ^ 0x40UL ) | t9 ;
213
+ z2 = z0 | t0 | t1 | (t9 ^ 0x400000UL );
216
214
217
215
/* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */
218
216
VERIFY_CHECK (t9 >> 23 == 0 );
219
217
220
- return (z0 == 0 ) | (z1 == 0x3FFFFFFUL );
218
+ return (z1 == 0 ) | (z2 == 0 );
221
219
}
222
220
223
221
static int secp256k1_fe_normalizes_to_zero_var (const secp256k1_fe * r ) {
0 commit comments