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