@@ -137,24 +137,135 @@ static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *p
137
137
secp256k1_ge_globalz_set_table_gej (ECMULT_TABLE_SIZE (WINDOW_A ), pre , globalz , prej , zr );
138
138
}
139
139
140
- static void secp256k1_ecmult_odd_multiples_table_storage_var (int n , secp256k1_ge_storage * pre , const secp256k1_gej * a , const secp256k1_callback * cb ) {
141
- secp256k1_gej * prej = (secp256k1_gej * )checked_malloc (cb , sizeof (secp256k1_gej ) * n );
142
- secp256k1_ge * prea = (secp256k1_ge * )checked_malloc (cb , sizeof (secp256k1_ge ) * n );
143
- secp256k1_fe * zr = (secp256k1_fe * )checked_malloc (cb , sizeof (secp256k1_fe ) * n );
140
+ static void secp256k1_ecmult_odd_multiples_table_storage_var (const int n , secp256k1_ge_storage * pre , const secp256k1_gej * a ) {
141
+ secp256k1_gej d ;
142
+ secp256k1_ge d_ge , p_ge ;
143
+ secp256k1_gej pj ;
144
+ secp256k1_fe zi ;
145
+ secp256k1_fe zr ;
146
+ secp256k1_fe dx_over_dz_squared ;
144
147
int i ;
145
148
146
- /* Compute the odd multiples in Jacobian form. */
147
- secp256k1_ecmult_odd_multiples_table (n , prej , zr , a );
148
- /* Convert them in batch to affine coordinates. */
149
- secp256k1_ge_set_table_gej_var (prea , prej , zr , n );
150
- /* Convert them to compact storage form. */
151
- for (i = 0 ; i < n ; i ++ ) {
152
- secp256k1_ge_to_storage (& pre [i ], & prea [i ]);
149
+ VERIFY_CHECK (!a -> infinity );
150
+
151
+ secp256k1_gej_double_var (& d , a , NULL );
152
+
153
+ /* First, we perform all the additions in an isomorphic curve obtained by multiplying
154
+ * all `z` coordinates by 1/`d.z`. In these coordinates `d` is affine so we can use
155
+ * `secp256k1_gej_add_ge_var` to perform the additions. For each addition, we store
156
+ * the resulting y-coordinate and the z-ratio, since we only have enough memory to
157
+ * store two field elements. These are sufficient to efficiently undo the isomorphism
158
+ * and recompute all the `x`s.
159
+ */
160
+ d_ge .x = d .x ;
161
+ d_ge .y = d .y ;
162
+ d_ge .infinity = 0 ;
163
+
164
+ secp256k1_ge_set_gej_zinv (& p_ge , a , & d .z );
165
+ pj .x = p_ge .x ;
166
+ pj .y = p_ge .y ;
167
+ pj .z = a -> z ;
168
+ pj .infinity = 0 ;
169
+
170
+ for (i = 0 ; i < (n - 1 ); i ++ ) {
171
+ secp256k1_fe_normalize_var (& pj .y );
172
+ secp256k1_fe_to_storage (& pre [i ].y , & pj .y );
173
+ secp256k1_gej_add_ge_var (& pj , & pj , & d_ge , & zr );
174
+ secp256k1_fe_normalize_var (& zr );
175
+ secp256k1_fe_to_storage (& pre [i ].x , & zr );
153
176
}
154
177
155
- free (prea );
156
- free (prej );
157
- free (zr );
178
+ /* Invert d.z in the same batch, preserving pj.z so we can extract 1/d.z */
179
+ secp256k1_fe_mul (& zi , & pj .z , & d .z );
180
+ secp256k1_fe_inv_var (& zi , & zi );
181
+
182
+ /* Directly set `pre[n - 1]` to `pj`, saving the inverted z-coordinate so
183
+ * that we can combine it with the saved z-ratios to compute the other zs
184
+ * without any more inversions. */
185
+ secp256k1_ge_set_gej_zinv (& p_ge , & pj , & zi );
186
+ secp256k1_ge_to_storage (& pre [n - 1 ], & p_ge );
187
+
188
+ /* Compute the actual x-coordinate of D, which will be needed below. */
189
+ secp256k1_fe_mul (& d .z , & zi , & pj .z ); /* d.z = 1/d.z */
190
+ secp256k1_fe_sqr (& dx_over_dz_squared , & d .z );
191
+ secp256k1_fe_mul (& dx_over_dz_squared , & dx_over_dz_squared , & d .x );
192
+
193
+ /* Going into the second loop, we have set `pre[n-1]` to its final affine
194
+ * form, but still need to set `pre[i]` for `i` in 0 through `n-2`. We
195
+ * have `zi = (p.z * d.z)^-1`, where
196
+ *
197
+ * `p.z` is the z-coordinate of the point on the isomorphic curve
198
+ * which was ultimately assigned to `pre[n-1]`.
199
+ * `d.z` is the multiplier that must be applied to all z-coordinates
200
+ * to move from our isomorphic curve back to secp256k1; so the
201
+ * product `p.z * d.z` is the z-coordinate of the secp256k1
202
+ * point assigned to `pre[n-1]`.
203
+ *
204
+ * All subsequent inverse-z-coordinates can be obtained by multiplying this
205
+ * factor by successive z-ratios, which is much more efficient than directly
206
+ * computing each one.
207
+ *
208
+ * Importantly, these inverse-zs will be coordinates of points on secp256k1,
209
+ * while our other stored values come from computations on the isomorphic
210
+ * curve. So in the below loop, we will take care not to actually use `zi`
211
+ * or any derived values until we're back on secp256k1.
212
+ */
213
+ i = n - 1 ;
214
+ while (i > 0 ) {
215
+ secp256k1_fe zi2 , zi3 ;
216
+ const secp256k1_fe * rzr ;
217
+ i -- ;
218
+
219
+ secp256k1_ge_from_storage (& p_ge , & pre [i ]);
220
+
221
+ /* For each remaining point, we extract the z-ratio from the stored
222
+ * x-coordinate, compute its z^-1 from that, and compute the full
223
+ * point from that. */
224
+ rzr = & p_ge .x ;
225
+ secp256k1_fe_mul (& zi , & zi , rzr );
226
+ secp256k1_fe_sqr (& zi2 , & zi );
227
+ secp256k1_fe_mul (& zi3 , & zi2 , & zi );
228
+ /* To compute the actual x-coordinate, we use the stored z ratio and
229
+ * y-coordinate, which we obtained from `secp256k1_gej_add_ge_var`
230
+ * in the loop above, as well as the inverse of the square of its
231
+ * z-coordinate. We store the latter in the `zi2` variable, which is
232
+ * computed iteratively starting from the overall Z inverse then
233
+ * multiplying by each z-ratio in turn.
234
+ *
235
+ * Denoting the z-ratio as `rzr`, we observe that it is equal to `h`
236
+ * from the inside of the above `gej_add_ge_var` call. This satisfies
237
+ *
238
+ * rzr = d_x * z^2 - x * d_z^2
239
+ *
240
+ * where (`d_x`, `d_z`) are Jacobian coordinates of `D` and `(x, z)`
241
+ * are Jacobian coordinates of our desired point -- except both are on
242
+ * the isomorphic curve that we were using when we called `gej_add_ge_var`.
243
+ * To get back to secp256k1, we must multiply both `z`s by `d_z`, or
244
+ * equivalently divide both `x`s by `d_z^2`. Our equation then becomes
245
+ *
246
+ * rzr = d_x * z^2 / d_z^2 - x
247
+ *
248
+ * (The left-hand-side, being a ratio of z-coordinates, is unaffected
249
+ * by the isomorphism.)
250
+ *
251
+ * Rearranging to solve for `x`, we have
252
+ *
253
+ * x = d_x * z^2 / d_z^2 - rzr
254
+ *
255
+ * But what we actually want is the affine coordinate `X = x/z^2`,
256
+ * which will satisfy
257
+ *
258
+ * X = d_x / d_z^2 - rzr / z^2
259
+ * = dx_over_dz_squared - rzr * zi2
260
+ */
261
+ secp256k1_fe_mul (& p_ge .x , rzr , & zi2 );
262
+ secp256k1_fe_negate (& p_ge .x , & p_ge .x , 1 );
263
+ secp256k1_fe_add (& p_ge .x , & dx_over_dz_squared );
264
+ /* y is stored_y/z^3, as we expect */
265
+ secp256k1_fe_mul (& p_ge .y , & p_ge .y , & zi3 );
266
+ /* Store */
267
+ secp256k1_ge_to_storage (& pre [i ], & p_ge );
268
+ }
158
269
}
159
270
160
271
/** The following two macro retrieves a particular odd multiple from a table
@@ -202,7 +313,7 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
202
313
ctx -> pre_g = (secp256k1_ge_storage (* )[])checked_malloc (cb , sizeof ((* ctx -> pre_g )[0 ]) * ECMULT_TABLE_SIZE (WINDOW_G ));
203
314
204
315
/* precompute the tables with odd multiples */
205
- secp256k1_ecmult_odd_multiples_table_storage_var (ECMULT_TABLE_SIZE (WINDOW_G ), * ctx -> pre_g , & gj , cb );
316
+ secp256k1_ecmult_odd_multiples_table_storage_var (ECMULT_TABLE_SIZE (WINDOW_G ), * ctx -> pre_g , & gj );
206
317
207
318
#ifdef USE_ENDOMORPHISM
208
319
{
@@ -216,7 +327,7 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
216
327
for (i = 0 ; i < 128 ; i ++ ) {
217
328
secp256k1_gej_double_var (& g_128j , & g_128j , NULL );
218
329
}
219
- secp256k1_ecmult_odd_multiples_table_storage_var (ECMULT_TABLE_SIZE (WINDOW_G ), * ctx -> pre_g_128 , & g_128j , cb );
330
+ secp256k1_ecmult_odd_multiples_table_storage_var (ECMULT_TABLE_SIZE (WINDOW_G ), * ctx -> pre_g_128 , & g_128j );
220
331
}
221
332
#endif
222
333
}
0 commit comments