Skip to content

Commit 78cb860

Browse files
committed
Merge pull request #1 from sipa/slice
Slice bytes of G multiples to avoid cache timings.
2 parents 55372af + 65a79b3 commit 78cb860

File tree

1 file changed

+28
-7
lines changed

1 file changed

+28
-7
lines changed

src/impl/ecmult.h

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,20 @@ void static secp256k1_ecmult_table_precomp_ge(secp256k1_ge_t *pre, const secp256
6464
#define ECMULT_TABLE_GET_GE(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_ge_neg)
6565

6666
typedef struct {
67+
// For accelerating the computation of a*P + b*G:
6768
secp256k1_ge_t pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; // odd multiples of the generator
6869
secp256k1_ge_t pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; // odd multiples of 2^128*generator
69-
secp256k1_ge_t prec[64][16]; // prec[j][i] = 16^j * (i+1) * G
70+
71+
// For accelerating the computation of a*G:
72+
// To harden against timing attacks, use the following mechanism:
73+
// * Break up the multiplicand into groups of 4 bits, called n_0, n_1, n_2, ..., n_63.
74+
// * Compute sum((n_i + 1) * 16^i * G, i=0..63).
75+
// * Subtract sum(1 * 16^i * G, i=0..63).
76+
// For each i, and each of the 16 possible values of n_i, ((n_i + 1) * 16^i * G) is
77+
// precomputed (call it prec(i,n_i), as well as -sum(1 * 16^i * G) (called fin).
78+
// The formula now becomes sum(prec(i, n_i), i=0..63) + fin.
79+
// To make memory access uniform, the bytes of prec(i,n_i) are sliced per value of n_i.
80+
unsigned char prec[64][sizeof(secp256k1_ge_t)][16]; // prec[j][k][i] = k'th byte of (16^j * (i+1) * G)
7081
secp256k1_ge_t fin; // -(sum(prec[j][0], j=0..63))
7182
} secp256k1_ecmult_consts_t;
7283

@@ -94,16 +105,21 @@ static void secp256k1_ecmult_start(void) {
94105

95106
// compute prec and fin
96107
secp256k1_gej_t gg; secp256k1_gej_set_ge(&gg, g);
108+
secp256k1_ge_t ggn; ggn = *g;
97109
secp256k1_ge_t ad = *g;
98110
secp256k1_gej_t fn; secp256k1_gej_set_infinity(&fn);
99111
for (int j=0; j<64; j++) {
100-
secp256k1_ge_set_gej(&ret->prec[j][0], &gg);
112+
for (int k=0; k<sizeof(secp256k1_ge_t); k++)
113+
ret->prec[j][k][0] = ((unsigned char*)(&ggn))[k];
101114
secp256k1_gej_add(&fn, &fn, &gg);
102115
for (int i=1; i<16; i++) {
103116
secp256k1_gej_add_ge(&gg, &gg, &ad);
104-
secp256k1_ge_set_gej(&ret->prec[j][i], &gg);
117+
secp256k1_ge_set_gej(&ggn, &gg);
118+
if (i == 15)
119+
ad = ggn;
120+
for (int k=0; k<sizeof(secp256k1_ge_t); k++)
121+
ret->prec[j][k][i] = ((unsigned char*)(&ggn))[k];
105122
}
106-
ad = ret->prec[j][15];
107123
}
108124
secp256k1_ge_set_gej(&ret->fin, &fn);
109125
secp256k1_ge_neg(&ret->fin, &ret->fin);
@@ -163,9 +179,14 @@ void static secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_num_t *gn)
163179
secp256k1_num_init(&n);
164180
secp256k1_num_copy(&n, gn);
165181
const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts;
166-
secp256k1_gej_set_ge(r, &c->prec[0][secp256k1_num_shift(&n, 4)]);
167-
for (int j=1; j<64; j++)
168-
secp256k1_gej_add_ge(r, r, &c->prec[j][secp256k1_num_shift(&n, 4)]);
182+
secp256k1_gej_set_infinity(r);
183+
for (int j=0; j<64; j++) {
184+
secp256k1_ge_t add;
185+
int bits = secp256k1_num_shift(&n, 4);
186+
for (int k=0; k<sizeof(secp256k1_ge_t); k++)
187+
((unsigned char*)(&add))[k] = c->prec[j][k][bits];
188+
secp256k1_gej_add_ge(r, r, &add);
189+
}
169190
secp256k1_num_free(&n);
170191
secp256k1_gej_add_ge(r, r, &c->fin);
171192
}

0 commit comments

Comments
 (0)