@@ -190,6 +190,27 @@ 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+ * we 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+ * So `zi` is equal to the inverse-z-coordinate of our first point. All
205+ * subsequent inverse-z-coordinates can be obtained by multiplying this
206+ * factor by successive z-ratios, which is much more efficient than
207+ * directly computing each one.
208+ *
209+ * Importantly, these inverse-zs will be coordinates of points on secp256k1,
210+ * while our other stored values come from computations on the isomorphic
211+ * curve. So in the below loop, we will take care not to actually use `zi`
212+ * or any derived values until we're back on secp256k1.
213+ */
193214 i = n - 1 ;
194215 while (i > 0 ) {
195216 secp256k1_fe zi2 , zi3 ;
@@ -198,7 +219,7 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp25
198219
199220 secp256k1_ge_from_storage (& p_ge , & pre [i ]);
200221
201- /* For the remaining points , we extract the z-ratio from the stored
222+ /* For each remaining point , we extract the z-ratio from the stored
202223 * x-coordinate, compute its z^-1 from that, and compute the full
203224 * point from that. */
204225 rzr = & p_ge .x ;
@@ -212,19 +233,31 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp25
212233 * computed iteratively starting from the overall Z inverse then
213234 * multiplying by each z-ratio in turn.
214235 *
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
236+ * Denoting the z-ratio as `rzr`, we observe that it equal to `h`
237+ * from the inside of the above `gej_add_ge_var` call. This satisfies
238+ *
239+ * rzr = d_x * z^2 - x * d_z^2
240+ *
241+ * where (`d_x`, `d_z`) are Jacobian coordinates of `D` and `(x, z)`
242+ * are Jacobian coordinates of our desired point -- except both are on
243+ * the isomorphic curve that we were using when we called `gej_add_ge_var`.
244+ * To get back to secp256k1, we must multiply both `z`s by `d_z`, or
245+ * equivalently divide both `x`s by `d_z^2`. Our equation then becomes
246+ *
247+ * rzr = d_x * z^2 / d_z^2 - x
248+ *
249+ * (The left-hand-side, being a ratio of z-coordinates, is unaffected
250+ * by the isomorphism.)
218251 *
219- * rzr = d_x * z^2 - x
252+ * Rearranging to solve for `x`, we have
220253 *
221- * where `d_x` is the x coordinate of `D` and `(x, z)` are Jacobian
222- * coordinates of our desired point.
254+ * x = d_x * z^2 / d_z^2 - rzr
223255 *
224- * Rearranging and dividing by `z^2` to convert to affine, we get
256+ * But what we actually want is the affine coordinate `X = x/z^2`,
257+ * which will satisfy
225258 *
226- * x = d_x - rzr / z^2
227- * = d_x - rzr * zi2
259+ * X = d_x / d_z^2 - rzr / z^2
260+ * = dx_over_dz_squared - rzr * zi2
228261 */
229262 secp256k1_fe_mul (& p_ge .x , rzr , & zi2 );
230263 secp256k1_fe_negate (& p_ge .x , & p_ge .x , 1 );
0 commit comments