Skip to content

Commit a403074

Browse files
committed
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_gej_split_exp accordingly. - Remove secp256k1_num_div since no longer used
1 parent f79d80a commit a403074

File tree

4 files changed

+72
-43
lines changed

4 files changed

+72
-43
lines changed

src/group.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ typedef struct {
3232
#ifdef USE_ENDOMORPHISM
3333
// constants related to secp256k1's efficiently computable endomorphism
3434
secp256k1_fe_t beta;
35-
secp256k1_num_t lambda, a1b2, b1, a2;
35+
secp256k1_num_t lambda, a1b2, b1, a2, g1, g2;
3636
#endif
3737
} secp256k1_ge_consts_t;
3838

src/group_impl.h

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -412,26 +412,27 @@ void static secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *
412412

413413
void static secp256k1_gej_split_exp_var(secp256k1_num_t *r1, secp256k1_num_t *r2, const secp256k1_num_t *a) {
414414
const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
415-
secp256k1_num_t bnc1, bnc2, bnt1, bnt2, bnn2;
416-
417-
secp256k1_num_copy(&bnn2, &c->order);
418-
secp256k1_num_shift(&bnn2, 1);
419-
420-
secp256k1_num_mul(&bnc1, a, &c->a1b2);
421-
secp256k1_num_add(&bnc1, &bnc1, &bnn2);
422-
secp256k1_num_div(&bnc1, &bnc1, &c->order);
423-
424-
secp256k1_num_mul(&bnc2, a, &c->b1);
425-
secp256k1_num_add(&bnc2, &bnc2, &bnn2);
426-
secp256k1_num_div(&bnc2, &bnc2, &c->order);
427-
428-
secp256k1_num_mul(&bnt1, &bnc1, &c->a1b2);
429-
secp256k1_num_mul(&bnt2, &bnc2, &c->a2);
430-
secp256k1_num_add(&bnt1, &bnt1, &bnt2);
431-
secp256k1_num_sub(r1, a, &bnt1);
432-
secp256k1_num_mul(&bnt1, &bnc1, &c->b1);
433-
secp256k1_num_mul(&bnt2, &bnc2, &c->a1b2);
434-
secp256k1_num_sub(r2, &bnt1, &bnt2);
415+
416+
secp256k1_num_t d1, d2, t;
417+
418+
secp256k1_num_mul(&t, a, &c->g1);
419+
secp256k1_num_trunc(&d1, &t, 272);
420+
if (secp256k1_num_get_bit(&t, 271))
421+
secp256k1_num_inc(&d1);
422+
423+
secp256k1_num_mul(&t, a, &c->g2);
424+
secp256k1_num_trunc(&d2, &t, 272);
425+
if (secp256k1_num_get_bit(&t, 271))
426+
secp256k1_num_inc(&d2);
427+
428+
secp256k1_num_mul(&t, &d1, &c->a1b2);
429+
secp256k1_num_sub(r1, a, &t);
430+
secp256k1_num_mul(&t, &d2, &c->a2);
431+
secp256k1_num_sub(r1, r1, &t);
432+
433+
secp256k1_num_mul(r2, &d1, &c->b1);
434+
secp256k1_num_mul(&t, &d2, &c->a1b2);
435+
secp256k1_num_sub(r2, r2, &t);
435436
}
436437
#endif
437438

@@ -482,6 +483,33 @@ void static secp256k1_ge_start(void) {
482483
0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,
483484
0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8
484485
};
486+
/**
487+
* g1, g2 are precomputed constants used to replace division with a rounded multiplication
488+
* when decomposing the scalar for an endomorphism-based point multiplication.
489+
*
490+
* The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve
491+
* Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5.
492+
*
493+
* The derivation is described in the paper "Efficient Software Implementation of Public-Key
494+
* Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez),
495+
* Section 4.3 (here we use a somewhat higher-precision estimate):
496+
* d = a1*b2 - b1*a2
497+
* g1 = round((2^272)*b2/d)
498+
* g2 = round((2^272)*b1/d)
499+
*
500+
* (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found
501+
* as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda').
502+
*/
503+
static const unsigned char secp256k1_ge_consts_g1[] = {
504+
0x30,0x86,
505+
0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,
506+
0x90,0xe4,0x92,0x84,0xeb,0x15,0x3d,0xab
507+
};
508+
static const unsigned char secp256k1_ge_consts_g2[] = {
509+
0xe4,0x43,
510+
0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,
511+
0x7f,0xa9,0x0a,0xbf,0xe4,0xc4,0x22,0x12
512+
};
485513
#endif
486514
if (secp256k1_ge_consts == NULL) {
487515
secp256k1_ge_consts_t *ret = (secp256k1_ge_consts_t*)malloc(sizeof(secp256k1_ge_consts_t));
@@ -493,6 +521,8 @@ void static secp256k1_ge_start(void) {
493521
secp256k1_num_set_bin(&ret->a1b2, secp256k1_ge_consts_a1b2, sizeof(secp256k1_ge_consts_a1b2));
494522
secp256k1_num_set_bin(&ret->a2, secp256k1_ge_consts_a2, sizeof(secp256k1_ge_consts_a2));
495523
secp256k1_num_set_bin(&ret->b1, secp256k1_ge_consts_b1, sizeof(secp256k1_ge_consts_b1));
524+
secp256k1_num_set_bin(&ret->g1, secp256k1_ge_consts_g1, sizeof(secp256k1_ge_consts_g1));
525+
secp256k1_num_set_bin(&ret->g2, secp256k1_ge_consts_g2, sizeof(secp256k1_ge_consts_g2));
496526
secp256k1_fe_set_b32(&ret->beta, secp256k1_ge_consts_beta);
497527
#endif
498528
secp256k1_fe_t g_x, g_y;

src/num.h

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

55-
/** Divide two (signed) numbers. */
56-
void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
57-
5855
/** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1,
5956
even if r was negative. */
6057
void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m);
@@ -89,6 +86,9 @@ void static secp256k1_num_get_hex(char *r, int rlen, const secp256k1_num_t *a);
8986
/** Split a number into a low and high part. */
9087
void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits);
9188

89+
/** Truncate a number, returning the high part only. */
90+
void static secp256k1_num_trunc(secp256k1_num_t *r, const secp256k1_num_t *a, int bits);
91+
9292
/** Change a number's sign. */
9393
void static secp256k1_num_negate(secp256k1_num_t *r);
9494

src/num_gmp_impl.h

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -233,25 +233,6 @@ void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, cons
233233
memset(tmp, 0, sizeof(tmp));
234234
}
235235

236-
void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
237-
secp256k1_num_sanity(a);
238-
secp256k1_num_sanity(b);
239-
if (b->limbs > a->limbs) {
240-
r->limbs = 1;
241-
r->data[0] = 0;
242-
r->neg = 0;
243-
return;
244-
}
245-
246-
mp_limb_t quo[2*NUM_LIMBS+1];
247-
mp_limb_t rem[2*NUM_LIMBS+1];
248-
mpn_tdiv_qr(quo, rem, 0, a->data, a->limbs, b->data, b->limbs);
249-
mpn_copyi(r->data, quo, a->limbs - b->limbs + 1);
250-
r->limbs = a->limbs - b->limbs + 1;
251-
while (r->limbs > 1 && r->data[r->limbs - 1]==0) r->limbs--;
252-
r->neg = a->neg ^ b->neg;
253-
}
254-
255236
void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m) {
256237
secp256k1_num_mul(r, a, b);
257238
secp256k1_num_mod(r, m);
@@ -358,6 +339,24 @@ void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const
358339
while (rl->limbs>1 && rl->data[rl->limbs-1]==0) rl->limbs--;
359340
}
360341

342+
void static secp256k1_num_trunc(secp256k1_num_t *r, const secp256k1_num_t *a, int bits) {
343+
VERIFY_CHECK(bits > 0);
344+
r->neg = a->neg;
345+
if (bits >= a->limbs * GMP_NUMB_BITS) {
346+
r->limbs = 1;
347+
r->data[0] = 0;
348+
return;
349+
}
350+
int limbs = bits / GMP_NUMB_BITS, left = bits % GMP_NUMB_BITS;
351+
r->limbs = a->limbs - limbs;
352+
if (left == 0) {
353+
mpn_copyi(r->data, a->data + limbs, r->limbs);
354+
} else {
355+
mpn_rshift(r->data, a->data + limbs, r->limbs, left);
356+
while (r->limbs>1 && r->data[r->limbs-1]==0) r->limbs--;
357+
}
358+
}
359+
361360
void static secp256k1_num_negate(secp256k1_num_t *r) {
362361
r->neg ^= 1;
363362
}

0 commit comments

Comments
 (0)