@@ -137,24 +137,107 @@ static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *p
137137 secp256k1_ge_globalz_set_table_gej (ECMULT_TABLE_SIZE (WINDOW_A ), pre , globalz , prej , zr );
138138}
139139
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 a_ge , d_ge , p_ge ;
143+ secp256k1_ge last_ge ;
144+ secp256k1_gej pj ;
145+ secp256k1_fe zi ;
146+ secp256k1_fe zr ;
147+ secp256k1_fe dx_over_dz_squared ;
144148 int i ;
145149
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 ]);
150+ VERIFY_CHECK (!a -> infinity );
151+
152+ secp256k1_gej_double_var (& d , a , NULL );
153+
154+ /* First, we perform all the additions in an isomorphic curve obtained by multiplying
155+ * all `z` coordinates by 1/`d.z`. In these coordinates `d` is affine so we can use
156+ * `secp256k1_gej_add_ge_var` to perform the additions. For each addition, we store
157+ * the resulting y-coordinate and the z-ratio, since we only have enough memory to
158+ * store two field elements. These are sufficient to efficiently undo the isomorphism
159+ * and recompute all the `x`s.
160+ */
161+ d_ge .x = d .x ;
162+ d_ge .y = d .y ;
163+ d_ge .infinity = 0 ;
164+
165+ secp256k1_ge_set_gej_zinv (& a_ge , a , & d .z );
166+ pj .x = a_ge .x ;
167+ pj .y = a_ge .y ;
168+ pj .z = a -> z ;
169+ pj .infinity = 0 ;
170+
171+ zr = d .z ;
172+ secp256k1_fe_normalize_var (& zr );
173+ secp256k1_fe_to_storage (& pre [0 ].x , & zr );
174+ secp256k1_fe_normalize_var (& pj .y );
175+ secp256k1_fe_to_storage (& pre [0 ].y , & pj .y );
176+
177+ for (i = 1 ; i < n ; i ++ ) {
178+ secp256k1_gej_add_ge_var (& pj , & pj , & d_ge , & zr );
179+ secp256k1_fe_normalize_var (& zr );
180+ secp256k1_fe_to_storage (& pre [i ].x , & zr );
181+ secp256k1_fe_normalize_var (& pj .y );
182+ secp256k1_fe_to_storage (& pre [i ].y , & pj .y );
153183 }
154184
155- free (prea );
156- free (prej );
157- free (zr );
185+ /* Map `pj` back to our curve by multiplying its z-coordinate by `d.z`. */
186+ secp256k1_fe_mul (& pj .z , & pj .z , & d .z );
187+ /* Directly set `pre[n - 1]` to `pj`, saving the inverted z-coordinate so
188+ * that we can combine it with the saved z-ratios to compute the other zs
189+ * without any more inversions. */
190+ secp256k1_fe_inv_var (& zi , & pj .z );
191+ secp256k1_ge_set_gej_zinv (& p_ge , & pj , & zi );
192+ secp256k1_ge_from_storage (& last_ge , & pre [n - 1 ]);
193+ secp256k1_ge_to_storage (& pre [n - 1 ], & p_ge );
194+
195+ /* Compute the actual x-coordinate of D, which will be needed below. */
196+ secp256k1_fe_inv_var (& d .z , & d .z );
197+ secp256k1_fe_sqr (& dx_over_dz_squared , & d .z );
198+ secp256k1_fe_mul (& dx_over_dz_squared , & dx_over_dz_squared , & d .x );
199+
200+ i = n - 1 ;
201+ while (i > 0 ) {
202+ secp256k1_fe zi2 , zi3 ;
203+ i -- ;
204+ /* For the remaining points, we extract the z-ratio from the stored
205+ * x-coordinate, compute its z^-1 from that, and compute the full
206+ * point from that. The z-ratio for the next iteration is stored in
207+ * the x-coordinate at the end of the loop. */
208+ secp256k1_fe_mul (& zi , & zi , & last_ge .x );
209+ secp256k1_fe_sqr (& zi2 , & zi );
210+ secp256k1_fe_mul (& zi3 , & zi2 , & zi );
211+ /* To compute the actual x-coordinate, we use the stored z ratio and
212+ * y-coordinate, which we obtained from `secp256k1_gej_add_ge_var`
213+ * in the loop above, as well as the inverse of the square of its
214+ * z-coordinate. We store the latter in the `zi2` variable, which is
215+ * computed iteratively starting from the overall Z inverse then
216+ * multiplying by each z-ratio in turn.
217+ *
218+ * Denoting the z-ratio as `rzr` (though the actual variable binding
219+ * is `last_ge.x`), we observe that it equal to `h` from the inside
220+ * of the above `gej_add_ge_var` call. This satisfies
221+ *
222+ * rzr = d_x * z^2 - x
223+ *
224+ * where `d_x` is the x coordinate of `D` and `(x, z)` are Jacobian
225+ * coordinates of our desired point.
226+ *
227+ * Rearranging and dividing by `z^2` to convert to affine, we get
228+ *
229+ * x = d_x - rzr / z^2
230+ * = d_x - rzr * zi2
231+ */
232+ secp256k1_fe_mul (& p_ge .x , & last_ge .x , & zi2 );
233+ secp256k1_fe_negate (& p_ge .x , & p_ge .x , 1 );
234+ secp256k1_fe_add (& p_ge .x , & dx_over_dz_squared );
235+ /* y is stored_y/z^3, as we expect */
236+ secp256k1_ge_from_storage (& last_ge , & pre [i ]);
237+ secp256k1_fe_mul (& p_ge .y , & last_ge .y , & zi3 );
238+ /* Store */
239+ secp256k1_ge_to_storage (& pre [i ], & p_ge );
240+ }
158241}
159242
160243/** The following two macro retrieves a particular odd multiple from a table
@@ -202,7 +285,7 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
202285 ctx -> pre_g = (secp256k1_ge_storage (* )[])checked_malloc (cb , sizeof ((* ctx -> pre_g )[0 ]) * ECMULT_TABLE_SIZE (WINDOW_G ));
203286
204287 /* precompute the tables with odd multiples */
205- secp256k1_ecmult_odd_multiples_table_storage_var (ECMULT_TABLE_SIZE (WINDOW_G ), * ctx -> pre_g , & gj , cb );
288+ secp256k1_ecmult_odd_multiples_table_storage_var (ECMULT_TABLE_SIZE (WINDOW_G ), * ctx -> pre_g , & gj );
206289
207290#ifdef USE_ENDOMORPHISM
208291 {
@@ -216,7 +299,7 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
216299 for (i = 0 ; i < 128 ; i ++ ) {
217300 secp256k1_gej_double_var (& g_128j , & g_128j , NULL );
218301 }
219- secp256k1_ecmult_odd_multiples_table_storage_var (ECMULT_TABLE_SIZE (WINDOW_G ), * ctx -> pre_g_128 , & g_128j , cb );
302+ secp256k1_ecmult_odd_multiples_table_storage_var (ECMULT_TABLE_SIZE (WINDOW_G ), * ctx -> pre_g_128 , & g_128j );
220303 }
221304#endif
222305}
0 commit comments