@@ -190,6 +190,26 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp25
190
190
secp256k1_fe_sqr (& dx_over_dz_squared , & d .z );
191
191
secp256k1_fe_mul (& dx_over_dz_squared , & dx_over_dz_squared , & d .x );
192
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
+ */
193
213
i = n - 1 ;
194
214
while (i > 0 ) {
195
215
secp256k1_fe zi2 , zi3 ;
@@ -198,7 +218,7 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp25
198
218
199
219
secp256k1_ge_from_storage (& p_ge , & pre [i ]);
200
220
201
- /* For the remaining points , we extract the z-ratio from the stored
221
+ /* For each remaining point , we extract the z-ratio from the stored
202
222
* x-coordinate, compute its z^-1 from that, and compute the full
203
223
* point from that. */
204
224
rzr = & p_ge .x ;
@@ -212,19 +232,31 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp25
212
232
* computed iteratively starting from the overall Z inverse then
213
233
* multiplying by each z-ratio in turn.
214
234
*
215
- * Denoting the z-ratio as `rzr` (though the actual variable binding
216
- * is `p_ge.x`), we observe that it equal to `h` from the inside
217
- * of the above `gej_add_ge_var` call. This satisfies
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.)
218
250
*
219
- * rzr = d_x * z^2 - x
251
+ * Rearranging to solve for `x`, we have
220
252
*
221
- * where `d_x` is the x coordinate of `D` and `(x, z)` are Jacobian
222
- * coordinates of our desired point.
253
+ * x = d_x * z^2 / d_z^2 - rzr
223
254
*
224
- * Rearranging and dividing by `z^2` to convert to affine, we get
255
+ * But what we actually want is the affine coordinate `X = x/z^2`,
256
+ * which will satisfy
225
257
*
226
- * x = d_x - rzr / z^2
227
- * = d_x - rzr * zi2
258
+ * X = d_x / d_z^2 - rzr / z^2
259
+ * = dx_over_dz_squared - rzr * zi2
228
260
*/
229
261
secp256k1_fe_mul (& p_ge .x , rzr , & zi2 );
230
262
secp256k1_fe_negate (& p_ge .x , & p_ge .x , 1 );
0 commit comments