@@ -228,4 +228,118 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
228
228
secp256k1_fe_mul (& r -> z , & r -> z , & Z );
229
229
}
230
230
231
+ static int secp256k1_ecmult_const_xonly (secp256k1_fe * r , const secp256k1_fe * n , const secp256k1_fe * d , const secp256k1_scalar * q , int bits , int known_on_curve ) {
232
+
233
+ /* This algorithm is a generalization of Peter Dettman's technique for
234
+ * avoiding the square root in a random-basepoint x-only multiplication
235
+ * on a Weierstrass curve:
236
+ * https://mailarchive.ietf.org/arch/msg/cfrg/7DyYY6gg32wDgHAhgSb6XxMDlJA/
237
+ *
238
+ *
239
+ * Background: the effective affine technique
240
+ *
241
+ * Let phi_u be the isomorphism that maps (x, y) on secp256k1 curve y^2 = x^3 + 7 to
242
+ * x' = u^2*x, y' = u^3*y on curve y'^2 = x'^3 + u^6*7. This new curve has the same order as
243
+ * the original (it is isomorphic), but moreover, has the same addition/doubling formulas, as
244
+ * the curve b=7 coefficient does not appear in those formulas.
245
+ *
246
+ * This means any computation on secp256k1 can be peformed by applying phi_u for any non-zero
247
+ * u on all the input points (including the generator, if used), performing the computation
248
+ * on the isomorphic curve (using the same group laws), and then applying phi_{1/u} to get back
249
+ * to secp256k1.
250
+ *
251
+ * Applying this to Jacobian coordinates, note that phi_u applied to (X, Y, Z) is simply
252
+ * (X, Y, Z/u). This means that if we want to compute (X1, Y1, Z) + (X2, Y2, Z), with
253
+ * identical Z coordinates, we can use phi_Z to transform it to (X1, Y1, 1) + (X2, Y2, 1) on
254
+ * an isomorphic curve where the affine addition formula can be used instead.
255
+ * If (X3, Y3, Z3) = (X1, Y1) + (X2, Y2) on that curve, then our answer on secp256k1 is
256
+ * (X3, Y3, Z3*Z).
257
+ *
258
+ * This is the effective affine technique: if we have a linear combination of group elements
259
+ * to compute, and all those group elements have the same Z coordinate, we can simply pretend
260
+ * that all those Z coordinates are 1, perform the computation that way, and then multiply the
261
+ * original Z coordinate back in.
262
+ *
263
+ *
264
+ * Avoiding the square root for x-only point multiplication.
265
+ *
266
+ * In this function, we want to compute the X coordinate of q*(n/d, y), for
267
+ * y = sqrt((n/d)^3 + 7).
268
+ *
269
+ * Let g = y^2*d^3 = n^3 + 7*d^3. This also means y = sqrt(g/d^3).
270
+ *
271
+ * The input point (n/d, y) also has Jacobian coordinates:
272
+ * (n/d, y, 1)
273
+ * = (n/d * sqrt^2(d*g), y * sqrt^3(d*g), sqrt(d*g))
274
+ * = (n/d * d*g, y * sqrt(d^3*g^3), sqrt(d*g))
275
+ * = (n*g, sqrt(g/d^3 * d^3*g^3), sqrt(d*g))
276
+ * = (n*g, sqrt(g^4), sqrt(d*g))
277
+ * = (n*g, g^2, sqrt(d*g))
278
+ *
279
+ * Note that sqrt(d*g) must exist if the input was valid, as d*g = y^2*d^4 = (y*d^2)^2.
280
+ *
281
+ * Now switch to the effective affine curve using phi_{sqrt(d*g)}, where the input point has
282
+ * coordinates (n*g, g^2).
283
+ *
284
+ * Let (X, Y, Z) = q*(n*g, g^2). Back on secp256k1, that means q*(n*g, g^2, sqrt(d*g)) =
285
+ * (X, Y, Z*sqrt(d*g)). This last point has affine X coordinate X/(d*g*Z^2). The affine Y
286
+ * coordinate would involve a square root, but if we only care about the resulting X
287
+ * coordinate, no square root was needed anywhere in this computation.
288
+ */
289
+
290
+ secp256k1_fe g , i ;
291
+ secp256k1_ge p ;
292
+ secp256k1_gej rj ;
293
+
294
+ /* Compute g = (n^3 + B*d^3). */
295
+ secp256k1_fe_sqr (& g , n );
296
+ secp256k1_fe_mul (& g , & g , n );
297
+ if (d ) {
298
+ secp256k1_fe b ;
299
+ secp256k1_fe_sqr (& b , d );
300
+ secp256k1_fe_mul_int (& b , SECP256K1_B );
301
+ secp256k1_fe_mul (& b , & b , d );
302
+ secp256k1_fe_add (& g , & b );
303
+ if (!known_on_curve ) {
304
+ /* We need to determine whether (n/d)^3 + 7 is square.
305
+ *
306
+ * is_square((n/d)^3 + 7)
307
+ * <=> is_square(((n/d)^3 + 7) * d^4)
308
+ * <=> is_square((n^3 + 7*d^3) * d)
309
+ * <=> is_square(g * d)
310
+ */
311
+ secp256k1_fe c ;
312
+ secp256k1_fe_mul (& c , & g , d );
313
+ if (!secp256k1_fe_is_square_var (& c )) return 0 ;
314
+ }
315
+ } else {
316
+ secp256k1_fe_add (& g , & secp256k1_fe_const_b );
317
+ if (!known_on_curve ) {
318
+ /* g at this point equals x^3 + 7. Test if it is square. */
319
+ if (!secp256k1_fe_is_square_var (& g )) return 0 ;
320
+ }
321
+ }
322
+
323
+ /* Compute base point P = (n*g, g^2), the effective affine version of
324
+ * (n*g, g^2, sqrt(d*g)), which has corresponding affine X coordinate
325
+ * n/d. */
326
+ secp256k1_fe_mul (& p .x , & g , n );
327
+ secp256k1_fe_sqr (& p .y , & g );
328
+ p .infinity = 0 ;
329
+
330
+ /* Perform x-only EC multiplication of P with q. */
331
+ secp256k1_ecmult_const (& rj , & p , q , bits );
332
+
333
+ /* The resulting (X, Y, Z) point on the effective-affine isomorphic curve
334
+ * corresponds to (X, Y, Z*sqrt(d*g)) on the secp256k1 curve. The affine
335
+ * version of that has X coordinate (X / (Z^2*d*g)). */
336
+ secp256k1_fe_sqr (& i , & rj .z );
337
+ secp256k1_fe_mul (& i , & i , & g );
338
+ if (d ) secp256k1_fe_mul (& i , & i , d );
339
+ secp256k1_fe_inv (& i , & i );
340
+ secp256k1_fe_mul (r , & rj .x , & i );
341
+
342
+ return 1 ;
343
+ }
344
+
231
345
#endif /* SECP256K1_ECMULT_CONST_IMPL_H */
0 commit comments