Skip to content

Commit cc604e9

Browse files
peterdettmansipa
authored andcommitted
Avoid division when decomposing scalars
- In secp256k1_gej_split_exp, there are two divisions used. Since the denominator is a constant known at compile-time, each can be replaced by a multiplication followed by a right-shift (and rounding). - Add the constants g1, g2 for this purpose and rewrite secp256k1_scalar_split_lambda_var accordingly. - Remove secp256k1_num_div since no longer used Rebased-by: Pieter Wuille
1 parent ff8746d commit cc604e9

File tree

4 files changed

+54
-44
lines changed

4 files changed

+54
-44
lines changed

src/ecmult_impl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const
170170
/* build wnaf representation for na_1 and na_lam. */
171171
int wnaf_na_1[129]; int bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A);
172172
int wnaf_na_lam[129]; int bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A);
173+
VERIFY_CHECK(bits_na_1 <= 129);
174+
VERIFY_CHECK(bits_na_lam <= 129);
173175
int bits = bits_na_1;
174176
if (bits_na_lam > bits) bits = bits_na_lam;
175177
#else

src/num.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,6 @@ static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, cons
4747
/** Multiply two (signed) numbers. */
4848
static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
4949

50-
/** Divide two (signed) numbers. */
51-
static void secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
52-
5350
/** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1,
5451
even if r was negative. */
5552
static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m);

src/num_gmp_impl.h

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -206,25 +206,6 @@ static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, cons
206206
memset(tmp, 0, sizeof(tmp));
207207
}
208208

209-
static void secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
210-
secp256k1_num_sanity(a);
211-
secp256k1_num_sanity(b);
212-
if (b->limbs > a->limbs) {
213-
r->limbs = 1;
214-
r->data[0] = 0;
215-
r->neg = 0;
216-
return;
217-
}
218-
219-
mp_limb_t quo[2*NUM_LIMBS+1];
220-
mp_limb_t rem[2*NUM_LIMBS+1];
221-
mpn_tdiv_qr(quo, rem, 0, a->data, a->limbs, b->data, b->limbs);
222-
mpn_copyi(r->data, quo, a->limbs - b->limbs + 1);
223-
r->limbs = a->limbs - b->limbs + 1;
224-
while (r->limbs > 1 && r->data[r->limbs - 1]==0) r->limbs--;
225-
r->neg = a->neg ^ b->neg;
226-
}
227-
228209
static void secp256k1_num_shift(secp256k1_num_t *r, int bits) {
229210
if (bits % GMP_NUMB_BITS) {
230211
// Shift within limbs.

src/scalar_impl.h

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ typedef struct {
2929
secp256k1_num_t order;
3030
#endif
3131
#ifdef USE_ENDOMORPHISM
32-
secp256k1_num_t a1b2, b1, a2;
32+
secp256k1_num_t a1b2, b1, a2, g1, g2;
3333
#endif
3434
} secp256k1_scalar_consts_t;
3535

@@ -65,10 +65,38 @@ static void secp256k1_scalar_start(void) {
6565
0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,
6666
0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8
6767
};
68-
68+
/**
69+
* g1, g2 are precomputed constants used to replace division with a rounded multiplication
70+
* when decomposing the scalar for an endomorphism-based point multiplication.
71+
*
72+
* The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve
73+
* Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5.
74+
*
75+
* The derivation is described in the paper "Efficient Software Implementation of Public-Key
76+
* Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez),
77+
* Section 4.3 (here we use a somewhat higher-precision estimate):
78+
* d = a1*b2 - b1*a2
79+
* g1 = round((2^272)*b2/d)
80+
* g2 = round((2^272)*b1/d)
81+
*
82+
* (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found
83+
* as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda').
84+
*/
85+
static const unsigned char secp256k1_scalar_consts_g1[] = {
86+
0x30,0x86,
87+
0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,
88+
0x90,0xe4,0x92,0x84,0xeb,0x15,0x3d,0xab
89+
};
90+
static const unsigned char secp256k1_scalar_consts_g2[] = {
91+
0xe4,0x43,
92+
0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,
93+
0x7f,0xa9,0x0a,0xbf,0xe4,0xc4,0x22,0x12
94+
};
6995
secp256k1_num_set_bin(&ret->a1b2, secp256k1_scalar_consts_a1b2, sizeof(secp256k1_scalar_consts_a1b2));
7096
secp256k1_num_set_bin(&ret->a2, secp256k1_scalar_consts_a2, sizeof(secp256k1_scalar_consts_a2));
7197
secp256k1_num_set_bin(&ret->b1, secp256k1_scalar_consts_b1, sizeof(secp256k1_scalar_consts_b1));
98+
secp256k1_num_set_bin(&ret->g1, secp256k1_scalar_consts_g1, sizeof(secp256k1_scalar_consts_g1));
99+
secp256k1_num_set_bin(&ret->g2, secp256k1_scalar_consts_g2, sizeof(secp256k1_scalar_consts_g2));
72100
#endif
73101

74102
/* Set the global pointer. */
@@ -273,26 +301,28 @@ static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_
273301
secp256k1_num_t rn1, rn2;
274302

275303
const secp256k1_scalar_consts_t *c = secp256k1_scalar_consts;
276-
secp256k1_num_t bnc1, bnc2, bnt1, bnt2, bnn2;
277-
278-
secp256k1_num_copy(&bnn2, &c->order);
279-
secp256k1_num_shift(&bnn2, 1);
280-
281-
secp256k1_num_mul(&bnc1, &na, &c->a1b2);
282-
secp256k1_num_add(&bnc1, &bnc1, &bnn2);
283-
secp256k1_num_div(&bnc1, &bnc1, &c->order);
284-
285-
secp256k1_num_mul(&bnc2, &na, &c->b1);
286-
secp256k1_num_add(&bnc2, &bnc2, &bnn2);
287-
secp256k1_num_div(&bnc2, &bnc2, &c->order);
288-
289-
secp256k1_num_mul(&bnt1, &bnc1, &c->a1b2);
290-
secp256k1_num_mul(&bnt2, &bnc2, &c->a2);
291-
secp256k1_num_add(&bnt1, &bnt1, &bnt2);
292-
secp256k1_num_sub(&rn1, &na, &bnt1);
293-
secp256k1_num_mul(&bnt1, &bnc1, &c->b1);
294-
secp256k1_num_mul(&bnt2, &bnc2, &c->a1b2);
295-
secp256k1_num_sub(&rn2, &bnt1, &bnt2);
304+
secp256k1_num_t d1, d2, t, one;
305+
unsigned char cone[1] = {0x01};
306+
secp256k1_num_set_bin(&one, cone, 1);
307+
308+
secp256k1_num_mul(&d1, &na, &c->g1);
309+
secp256k1_num_shift(&d1, 271);
310+
secp256k1_num_add(&d1, &d1, &one);
311+
secp256k1_num_shift(&d1, 1);
312+
313+
secp256k1_num_mul(&d2, &na, &c->g2);
314+
secp256k1_num_shift(&d2, 271);
315+
secp256k1_num_add(&d2, &d2, &one);
316+
secp256k1_num_shift(&d2, 1);
317+
318+
secp256k1_num_mul(&t, &d1, &c->a1b2);
319+
secp256k1_num_sub(&rn1, &na, &t);
320+
secp256k1_num_mul(&t, &d2, &c->a2);
321+
secp256k1_num_sub(&rn1, &rn1, &t);
322+
323+
secp256k1_num_mul(&rn2, &d1, &c->b1);
324+
secp256k1_num_mul(&t, &d2, &c->a1b2);
325+
secp256k1_num_sub(&rn2, &rn2, &t);
296326

297327
secp256k1_num_get_bin(b, 32, &rn1);
298328
secp256k1_scalar_set_b32(r1, b, NULL);

0 commit comments

Comments
 (0)