Skip to content

Commit c914fcc

Browse files
committed
Reduce side-channels from single-bit reads
Also make secp256k1_scalar_get_bits work with count=32.
1 parent 3d3e5be commit c914fcc

4 files changed

+17
-10
lines changed

src/ecmult_gen_impl.h

+12-5
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,11 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
152152
#if COMB_BITS > 256
153153
} else if (EXPECT(bit_pos >= 256, 0)) {
154154
/* Some bit(s) of (mask(block) << comb_off) are outside of [0,256). This means
155-
* we are also done constructing bits, but know its top bit is zero, and no
155+
* we are also done constructing bits, but know its top bit should be zero, and no
156156
* flipping/negating is needed. The table lookup can also be done over a
157157
* smaller number of entries. */
158-
VERIFY_CHECK(bits < (1U << tooth));
158+
/* Mask out junk in bits variable. */
159+
bits &= ((1U << tooth) - 1);
159160
VERIFY_CHECK(bits < COMB_POINTS);
160161
for (index = 0; (index >> tooth) == 0; ++index) {
161162
secp256k1_ge_storage_cmov(&adds, &secp256k1_ecmult_gen_prec_table[block][index], index == bits);
@@ -164,10 +165,16 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
164165
break;
165166
#endif
166167
} else {
167-
/* Gather another bit. */
168-
uint32_t bit = secp256k1_scalar_get_bits(&recoded, bit_pos, 1);
168+
/* Gather another bit. To reduce side-channels from single-bit reads, don't
169+
* actually fetch a single bit, but read higher bits too, which are XOR'ed
170+
* into the upper bits of bits. On every iteration, an addition bits is
171+
* made correct, starting at the bottom. The bits above that contain junk.
172+
* See https://www.usenix.org/system/files/conference/usenixsecurity18/sec18-alam.pdf
173+
*/
174+
uint32_t bitdata = secp256k1_scalar_get_bits(&recoded, bit_pos & ~0x1f, 32) >> (bit_pos & 0x1f);
169175
VERIFY_CHECK(bit_pos < COMB_BITS && bit_pos < 256);
170-
bits |= bit << tooth;
176+
bits &= ~(1 << tooth);
177+
bits ^= bitdata << tooth;
171178
bit_pos += COMB_SPACING;
172179
++tooth;
173180
}

src/scalar_4x64_impl.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig
4242

4343
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
4444
VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6);
45-
return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1);
45+
return (a->d[offset >> 6] >> (offset & 0x3F)) & (0xFFFFFFFFU >> (32 - count));
4646
}
4747

4848
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
@@ -52,7 +52,7 @@ SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256
5252
return secp256k1_scalar_get_bits(a, offset, count);
5353
} else {
5454
VERIFY_CHECK((offset >> 6) + 1 < 4);
55-
return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & ((((uint64_t)1) << count) - 1);
55+
return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & (0xFFFFFFFFU >> (32 - count));
5656
}
5757
}
5858

src/scalar_8x32_impl.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig
6060

6161
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
6262
VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5);
63-
return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1);
63+
return (a->d[offset >> 5] >> (offset & 0x1F)) & (0xFFFFFFFFU >> (32 - count));
6464
}
6565

6666
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
@@ -70,7 +70,7 @@ SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256
7070
return secp256k1_scalar_get_bits(a, offset, count);
7171
} else {
7272
VERIFY_CHECK((offset >> 5) + 1 < 8);
73-
return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & ((((uint32_t)1) << count) - 1);
73+
return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & (0xFFFFFFFFU >> (32 - count));
7474
}
7575
}
7676

src/scalar_low_impl.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig
2020

2121
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
2222
if (offset < 32)
23-
return ((*a >> offset) & ((((uint32_t)1) << count) - 1));
23+
return (*a >> offset) & (0xFFFFFFFFU >> (32 - count));
2424
else
2525
return 0;
2626
}

0 commit comments

Comments
 (0)