Skip to content

Commit a0992eb

Browse files
committed
Implement endomorphism optimization for secp256k1_ecdh_point_multiply
1 parent a022656 commit a0992eb

File tree

1 file changed

+43
-1
lines changed

1 file changed

+43
-1
lines changed

src/ecdh_impl.h

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,43 @@ static void secp256k1_ecdh_point_multiply(secp256k1_gej_t *r, const secp256k1_ge
6161
secp256k1_ge_t tmpa;
6262
secp256k1_fe_t Z;
6363

64+
#ifdef USE_ENDOMORPHISM
65+
secp256k1_ge_t pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
66+
int wnaf_1[256];
67+
int wnaf_lam[256];
68+
int n_words_lam;
69+
secp256k1_scalar_t q_1, q_lam;
70+
#else
6471
int wnaf[256];
72+
#endif
6573
int n_words;
6674

6775
int i;
6876
int is_zero = secp256k1_scalar_is_zero(scalar);
6977
secp256k1_scalar_t sc = *scalar;
78+
79+
/* build wnaf representation for q. */
80+
#ifdef USE_ENDOMORPHISM
81+
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
82+
secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc);
83+
/* the wNAF ladder cannot handle zero, so bump this to one .. we will
84+
* correct the result after the fact */
85+
q_1.d[0] += is_zero;
86+
q_lam.d[0] += is_zero;
87+
VERIFY_CHECK(!secp256k1_scalar_is_zero(&q_1));
88+
VERIFY_CHECK(!secp256k1_scalar_is_zero(&q_lam));
89+
90+
n_words = secp256k1_ecdh_wnaf(wnaf_1, &q_1, WINDOW_A - 1);
91+
n_words_lam = secp256k1_ecdh_wnaf(wnaf_lam, &q_lam, WINDOW_A - 1);
92+
VERIFY_CHECK(n_words == n_words_lam);
93+
#else
7094
/* the wNAF ladder cannot handle zero, so bump this to one .. we will
7195
* correct the result after the fact */
7296
sc.d[0] += is_zero;
97+
VERIFY_CHECK(!secp256k1_scalar_is_zero(&sc));
7398

74-
/* build wnaf representation for q. */
7599
n_words = secp256k1_ecdh_wnaf(wnaf, &sc, WINDOW_A - 1);
100+
#endif
76101

77102
/* Calculate odd multiples of a.
78103
* All multiples are brought to the same Z 'denominator', which is stored
@@ -82,6 +107,11 @@ static void secp256k1_ecdh_point_multiply(secp256k1_gej_t *r, const secp256k1_ge
82107
*/
83108
secp256k1_gej_set_ge(r, a);
84109
secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r);
110+
#ifdef USE_ENDOMORPHISM
111+
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
112+
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
113+
}
114+
#endif
85115
secp256k1_gej_set_infinity(r);
86116

87117
for (i = n_words; i >= 0; i--) {
@@ -90,10 +120,22 @@ static void secp256k1_ecdh_point_multiply(secp256k1_gej_t *r, const secp256k1_ge
90120
for (j = 0; j < WINDOW_A - 1; ++j) {
91121
secp256k1_gej_double_var(r, r, NULL);
92122
}
123+
#ifdef USE_ENDOMORPHISM
124+
n = wnaf_1[i];
125+
ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
126+
VERIFY_CHECK(n != 0);
127+
secp256k1_gej_add_ge(r, r, &tmpa);
128+
129+
n = wnaf_lam[i];
130+
ECMULT_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
131+
VERIFY_CHECK(n != 0);
132+
secp256k1_gej_add_ge(r, r, &tmpa);
133+
#else
93134
n = wnaf[i];
94135
VERIFY_CHECK(n != 0);
95136
ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
96137
secp256k1_gej_add_ge(r, r, &tmpa);
138+
#endif
97139
}
98140

99141
if (!r->infinity) {

0 commit comments

Comments
 (0)