@@ -200,15 +200,31 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
200
200
* together: bit (tooth) of bits = bit
201
201
* ((block*COMB_TEETH + tooth)*COMB_SPACING + comb_off) of d. */
202
202
uint32_t bits = 0 , sign , abs , index , tooth ;
203
+ /* Instead of reading individual bits here to construct the bits variable,
204
+ * build up the result by xoring rotated reads together. In every iteration,
205
+ * one additional bit is made correct, starting at the bottom. The bits
206
+ * above that contain junk. This reduces leakage by avoiding computations
207
+ * on variables that can have only a low number of possible values (e.g.,
208
+ * just two values when reading a single bit into a variable.) See:
209
+ * https://www.usenix.org/system/files/conference/usenixsecurity18/sec18-alam.pdf
210
+ */
203
211
for (tooth = 0 ; tooth < COMB_TEETH ; ++ tooth ) {
204
- /* Instead of reading individual bits here to construct bits, build up
205
- * the result by xoring shifted reads together. In every iteration, one
206
- * additional bit is made correct, starting at the bottom. The bits
207
- * above that contain junk. This reduces leakage from single bits. See
208
- * https://www.usenix.org/system/files/conference/usenixsecurity18/sec18-alam.pdf
209
- */
210
- uint32_t bitdata = recoded [bit_pos >> 5 ] >> (bit_pos & 0x1f );
211
- bits &= ~(1 << tooth );
212
+ /* Construct bitdata s.t. the bottom bit is the bit we'd like to read.
213
+ *
214
+ * We could just set bitdata = recoded[bit_pos >> 5] >> (bit_pos & 0x1f)
215
+ * but this would simply discard the bits that fall off at the bottom,
216
+ * and thus, for example, bitdata could still have only two values if we
217
+ * happen to shift by exactly 31 positions. We use a rotation instead,
218
+ * which ensures that bitdata doesn't loose entropy. This relies on the
219
+ * rotation being atomic, i.e., the compiler emitting an actual rot
220
+ * instruction. */
221
+ uint32_t bitdata = secp256k1_rotr32 (recoded [bit_pos >> 5 ], bit_pos & 0x1f );
222
+
223
+ /* Clear the bit at position tooth, but sssh, don't tell clang. */
224
+ uint32_t volatile vmask = ~(1 << tooth );
225
+ bits &= vmask ;
226
+
227
+ /* Write the bit into position tooth (and junk into higher bits). */
212
228
bits ^= bitdata << tooth ;
213
229
bit_pos += COMB_SPACING ;
214
230
}
0 commit comments