Skip to content

Commit b3bf5f9

Browse files
committed
ecmult_impl: expand comment to explain how effective affine interacts with everything
1 parent efa783f commit b3bf5f9

File tree

1 file changed

+42
-10
lines changed

1 file changed

+42
-10
lines changed

src/ecmult_impl.h

+42-10
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)