Skip to content

Commit e5c1889

Browse files
Eliminate the prej array from ecmult_strauss_wnaf.
1 parent c9da1ba commit e5c1889

File tree

4 files changed

+80
-49
lines changed

4 files changed

+80
-49
lines changed

src/ecmult_const_impl.h

+2-5
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,10 @@
1919
* It only operates on tables sized for WINDOW_A wnaf multiples.
2020
*/
2121
static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) {
22-
secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)];
2322
secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];
2423

25-
/* Compute the odd multiples in Jacobian form. */
26-
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a);
27-
/* Bring them to the same Z denominator. */
28-
secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr);
24+
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr, globalz, a);
25+
secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr);
2926
}
3027

3128
/* This is like `ECMULT_TABLE_GET_GE` but is constant time */

src/ecmult_impl.h

+46-28
Original file line numberDiff line numberDiff line change
@@ -56,44 +56,62 @@
5656

5757
#define ECMULT_MAX_POINTS_PER_BATCH 5000000
5858

59-
/** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain
60-
* the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will
61-
* contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z.
62-
* Prej's Z values are undefined, except for the last value.
59+
/** Fill a table 'pre_a' with precomputed odd multiples of a.
60+
* pre_a will contain [1*a,3*a,...,(2*n-1)*a], so it needs space for n group elements.
61+
* zr needs space for n field elements.
62+
*
63+
* Although pre_a is an array of _ge rather than _gej, it actually represents elements
64+
* in Jacobian coordinates with their z coordinates omitted. The omitted z-coordinates
65+
* can be recovered using z and zr. Using the notation z(b) to represent the omitted
66+
* z coordinate of b:
67+
* - z(pre_a[n-1]) = 'z'
68+
* - z(pre_a[i-1]) = z(pre_a[i]) / zr[i] for n > i > 0
69+
*
70+
* Lastly the zr[0] value, which isn't used above, is set so that:
71+
* - a.z = z(pre_a[0]) / zr[0]
6372
*/
64-
static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, secp256k1_fe *zr, const secp256k1_gej *a) {
65-
secp256k1_gej d;
66-
secp256k1_ge a_ge, d_ge;
73+
static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_ge *pre_a, secp256k1_fe *zr, secp256k1_fe *z, const secp256k1_gej *a) {
74+
secp256k1_gej d, ai;
75+
secp256k1_ge d_ge;
6776
int i;
6877

6978
VERIFY_CHECK(!a->infinity);
7079

7180
secp256k1_gej_double_var(&d, a, NULL);
7281

7382
/*
74-
* Perform the additions on an isomorphism where 'd' is affine: drop the z coordinate
75-
* of 'd', and scale the 1P starting value's x/y coordinates without changing its z.
83+
* Perform the additions using an isomorphic curve Y^2 = X^3 + 7*C^6 where C := d.z.
84+
* The isomorphism, phi, maps a secp256k1 point (x, y) to the point (x*C^2, y*C^3) on the other curve.
85+
* In Jacobian coordinates phi maps (x, y, z) to (x*C^2, y*C^3, z) or, equivalently to (x, y, z/C).
86+
*
87+
* phi(x, y, z) = (x*C^2, y*C^3, z) = (x, y, z/C)
88+
* d_ge := phi(d) = (d.x, d.y, 1)
89+
* ai := phi(a) = (a.x*C^2, a.y*C^3, a.z)
90+
*
91+
* The group addition functions work correctly on these isomorphic curves.
92+
* In particular phi(d) is easy to represent in affine coordinates under this isomorphism.
93+
* This lets us use the faster secp256k1_gej_add_ge_var group addition function that we wouldn't be able to use otherwise.
7694
*/
77-
d_ge.x = d.x;
78-
d_ge.y = d.y;
79-
d_ge.infinity = 0;
80-
81-
secp256k1_ge_set_gej_zinv(&a_ge, a, &d.z);
82-
prej[0].x = a_ge.x;
83-
prej[0].y = a_ge.y;
84-
prej[0].z = a->z;
85-
prej[0].infinity = 0;
95+
secp256k1_ge_set_xy(&d_ge, &d.x, &d.y);
96+
secp256k1_ge_set_gej_zinv(&pre_a[0], a, &d.z);
97+
secp256k1_gej_set_ge(&ai, &pre_a[0]);
98+
ai.z = a->z;
8699

100+
/* pre_a[0] is the point (a.x*C^2, a.y*C^3, a.z*C) which is equvalent to a.
101+
* Set zr[0] to C, which is the ratio between the omitted z(pre_a[0]) value and a.z.
102+
*/
87103
zr[0] = d.z;
104+
88105
for (i = 1; i < n; i++) {
89-
secp256k1_gej_add_ge_var(&prej[i], &prej[i-1], &d_ge, &zr[i]);
106+
secp256k1_gej_add_ge_var(&ai, &ai, &d_ge, &zr[i]);
107+
secp256k1_ge_set_xy(&pre_a[i], &ai.x, &ai.y);
90108
}
91109

92-
/*
93-
* Each point in 'prej' has a z coordinate too small by a factor of 'd.z'. Only
94-
* the final point's z coordinate is actually used though, so just update that.
110+
/* Multiply the last z-coordinate by C to undo the isomorphism.
111+
* Since the z-coordinates of the pre_a values are implied by the zr array of z-coordinate ratios,
112+
* undoing the isomorphism here undoes the isomorphism for all pre_a values.
95113
*/
96-
secp256k1_fe_mul(&prej[n-1].z, &prej[n-1].z, &d.z);
114+
secp256k1_fe_mul(z, &ai.z, &d.z);
97115
}
98116

99117
/** The following two macro retrieves a particular odd multiple from a table
@@ -246,18 +264,18 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
246264
*/
247265
if (no > 0) {
248266
/* Compute the odd multiples in Jacobian form. */
249-
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej, state->zr, &a[state->ps[0].input_pos]);
267+
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->pre_a, state->zr, &Z, &a[state->ps[0].input_pos]);
250268
for (np = 1; np < no; ++np) {
251269
secp256k1_gej tmp = a[state->ps[np].input_pos];
252270
#ifdef VERIFY
253-
secp256k1_fe_normalize_var(&(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z));
271+
secp256k1_fe_normalize_var(&Z);
254272
#endif
255-
secp256k1_gej_rescale(&tmp, &(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z));
256-
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &tmp);
273+
secp256k1_gej_rescale(&tmp, &Z);
274+
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &Z, &tmp);
257275
secp256k1_fe_mul(state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &(a[state->ps[np].input_pos].z));
258276
}
259277
/* Bring them to the same Z denominator. */
260-
secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, &Z, state->prej, state->zr);
278+
secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->zr);
261279
} else {
262280
secp256k1_fe_set_int(&Z, 1);
263281
}

src/group.h

+25-8
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99

1010
#include "field.h"
1111

12-
/** A group element of the secp256k1 curve, in affine coordinates. */
12+
/** A group element in affine coordinates on the secp256k1 curve,
13+
* or occasionally on an isomorphic curve of the form y^2 = x^3 + 7*t^6.
14+
* Note: For exhaustive test mode, secp256k1 is replaced by a small subgroup of a different curve.
15+
*/
1316
typedef struct {
1417
secp256k1_fe x;
1518
secp256k1_fe y;
@@ -19,7 +22,9 @@ typedef struct {
1922
#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0}
2023
#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1}
2124

22-
/** A group element of the secp256k1 curve, in jacobian coordinates. */
25+
/** A group element of the secp256k1 curve, in jacobian coordinates.
26+
* Note: For exhastive test mode, sepc256k1 is replaced by a small subgroup of a different curve.
27+
*/
2328
typedef struct {
2429
secp256k1_fe x; /* actual X: x/z^2 */
2530
secp256k1_fe y; /* actual Y: y/z^3 */
@@ -64,12 +69,24 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a);
6469
/** Set a batch of group elements equal to the inputs given in jacobian coordinates */
6570
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len);
6671

67-
/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to
68-
* the same global z "denominator". zr must contain the known z-ratios such
69-
* that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. The x and y
70-
* coordinates of the result are stored in r, the common z coordinate is
71-
* stored in globalz. */
72-
static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr);
72+
/** Bring a batch of inputs to the same global z "denominator", based on ratios between
73+
* (omitted) z coordinates of adjacent elements.
74+
*
75+
* Although the elements a[i] are _ge rather than _gej, they actually represent elements
76+
* in Jacobian coordinates with their z coordinates omitted.
77+
*
78+
* Using the notation z(b) to represent the omitted z coordinate of b, the array zr of
79+
* z coordinate ratios must satisfy zr[i] == z(a[i]) / z(a[i-1]) for 0 < 'i' < len.
80+
* The zr[0] value is unused.
81+
*
82+
* This function adjusts the coordinates of 'a' in place so that for all 'i', z(a[i]) == z(a[len-1]).
83+
* In other words, the initial value of z(a[len-1]) becomes the global z "denominator". Only the
84+
* a[i].x and a[i].y coordinates are explicitly modified; the adjustment of the omitted z coordinate is
85+
* implicit.
86+
*
87+
* The coordinates of the final element a[len-1] are not changed.
88+
*/
89+
static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr);
7390

7491
/** Set a group element (affine) equal to the point at infinity. */
7592
static void secp256k1_ge_set_infinity(secp256k1_ge *r);

src/group_impl.h

+7-8
Original file line numberDiff line numberDiff line change
@@ -161,27 +161,26 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
161161
}
162162
}
163163

164-
static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr) {
164+
static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr) {
165165
size_t i = len - 1;
166166
secp256k1_fe zs;
167167

168168
if (len > 0) {
169-
/* The z of the final point gives us the "global Z" for the table. */
170-
r[i].x = a[i].x;
171-
r[i].y = a[i].y;
172169
/* Ensure all y values are in weak normal form for fast negation of points */
173-
secp256k1_fe_normalize_weak(&r[i].y);
174-
*globalz = a[i].z;
175-
r[i].infinity = 0;
170+
secp256k1_fe_normalize_weak(&a[i].y);
176171
zs = zr[i];
177172

178173
/* Work our way backwards, using the z-ratios to scale the x/y values. */
179174
while (i > 0) {
175+
secp256k1_gej tmpa;
180176
if (i != len - 1) {
181177
secp256k1_fe_mul(&zs, &zs, &zr[i]);
182178
}
183179
i--;
184-
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zs);
180+
tmpa.x = a[i].x;
181+
tmpa.y = a[i].y;
182+
tmpa.infinity = 0;
183+
secp256k1_ge_set_gej_zinv(&a[i], &tmpa, &zs);
185184
}
186185
}
187186
}

0 commit comments

Comments
 (0)