@@ -190,6 +190,26 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp25
190190 secp256k1_fe_sqr (& dx_over_dz_squared , & d .z );
191191 secp256k1_fe_mul (& dx_over_dz_squared , & dx_over_dz_squared , & d .x );
192192
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+ */
193213 i = n - 1 ;
194214 while (i > 0 ) {
195215 secp256k1_fe zi2 , zi3 ;
@@ -198,7 +218,7 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp25
198218
199219 secp256k1_ge_from_storage (& p_ge , & pre [i ]);
200220
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
202222 * x-coordinate, compute its z^-1 from that, and compute the full
203223 * point from that. */
204224 rzr = & p_ge .x ;
@@ -212,19 +232,31 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp25
212232 * computed iteratively starting from the overall Z inverse then
213233 * multiplying by each z-ratio in turn.
214234 *
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.)
218250 *
219- * rzr = d_x * z^2 - x
251+ * Rearranging to solve for `x`, we have
220252 *
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
223254 *
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
225257 *
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
228260 */
229261 secp256k1_fe_mul (& p_ge .x , rzr , & zi2 );
230262 secp256k1_fe_negate (& p_ge .x , & p_ge .x , 1 );
0 commit comments