@@ -228,4 +228,139 @@ 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 (or at least does not appear in
245
+ * the formulas implemented in this codebase, both affine and Jacobian). See also Example 9.5.2
246
+ * in https://www.math.auckland.ac.nz/~sgal018/crypto-book/ch9.pdf.
247
+ *
248
+ * This means any linear combination of secp256k1 points can be computed by applying phi_u
249
+ * (with non-zero u) on all input points (including the generator, if used), computing the
250
+ * linear combination on the isomorphic curve (using the same group laws), and then applying
251
+ * phi_u^{-1} to get back to secp256k1.
252
+ *
253
+ * Switching to Jacobian coordinates, note that phi_u applied to (X, Y, Z) is simply
254
+ * (X, Y, Z/u). Thus, if we want to compute (X1, Y1, Z) + (X2, Y2, Z), with identical Z
255
+ * coordinates, we can use phi_Z to transform it to (X1, Y1, 1) + (X2, Y2, 1) on an isomorphic
256
+ * curve where the affine addition formula can be used instead.
257
+ * If (X3, Y3, Z3) = (X1, Y1) + (X2, Y2) on that curve, then our answer on secp256k1 is
258
+ * (X3, Y3, Z3*Z).
259
+ *
260
+ * This is the effective affine technique: if we have a linear combination of group elements
261
+ * to compute, and all those group elements have the same Z coordinate, we can simply pretend
262
+ * that all those Z coordinates are 1, perform the computation that way, and then multiply the
263
+ * original Z coordinate back in.
264
+ *
265
+ * The technique works on any a=0 short Weierstrass curve. It is possible to generalize it to
266
+ * other curves too, but there the isomorphic curves will have different 'a' coefficients,
267
+ * which typically does affect the group laws.
268
+ *
269
+ *
270
+ * === Avoiding the square root for x-only point multiplication ===
271
+ *
272
+ * In this function, we want to compute the X coordinate of q*(n/d, y), for
273
+ * y = sqrt((n/d)^3 + 7). Its negation would also be a valid Y coordinate, but by convention
274
+ * we pick whatever sqrt returns (which we assume to be a deterministic function).
275
+ *
276
+ * Let g = y^2*d^3 = n^3 + 7*d^3. This also means y = sqrt(g/d^3).
277
+ * Further let v = sqrt(d*g), which must exist as d*g = y^2*d^4 = (y*d^2)^2.
278
+ *
279
+ * The input point (n/d, y) also has Jacobian coordinates:
280
+ *
281
+ * (n/d, y, 1)
282
+ * = (n/d * v^2, y * v^3, v)
283
+ * = (n/d * d*g, y * sqrt(d^3*g^3), v)
284
+ * = (n/d * d*g, sqrt(y^2 * d^3*g^3), v)
285
+ * = (n*g, sqrt(g/d^3 * d^3*g^3), v)
286
+ * = (n*g, sqrt(g^4), v)
287
+ * = (n*g, g^2, v)
288
+ *
289
+ * It is easy to verify that both (n*g, g^2, v) and its negation (n*g, -g^2, v) have affine X
290
+ * coordinate n/d, and this holds even when the square root function doesn't have a
291
+ * determinstic sign. We choose the (n*g, g^2, v) version.
292
+ *
293
+ * Now switch to the effective affine curve using phi_v, where the input point has coordinates
294
+ * (n*g, g^2). Compute (X, Y, Z) = q * (n*g, g^2) there.
295
+ *
296
+ * Back on secp256k1, that means q * (n*g, g^2, v) = (X, Y, v*Z). This last point has affine X
297
+ * coordinate X / (v^2*Z^2) = X / (d*g*Z^2). Determining the affine Y coordinate would involve
298
+ * a square root, but as long as we only care about the resulting X coordinate, no square root
299
+ * is needed anywhere in this computation.
300
+ */
301
+
302
+ secp256k1_fe g , i ;
303
+ secp256k1_ge p ;
304
+ secp256k1_gej rj ;
305
+
306
+ /* Compute g = (n^3 + B*d^3). */
307
+ secp256k1_fe_sqr (& g , n );
308
+ secp256k1_fe_mul (& g , & g , n );
309
+ if (d ) {
310
+ secp256k1_fe b ;
311
+ #ifdef VERIFY
312
+ VERIFY_CHECK (!secp256k1_fe_normalizes_to_zero (d ));
313
+ #endif
314
+ secp256k1_fe_sqr (& b , d );
315
+ VERIFY_CHECK (SECP256K1_B <= 8 ); /* magnitude of b will be <= 8 after the next call */
316
+ secp256k1_fe_mul_int (& b , SECP256K1_B );
317
+ secp256k1_fe_mul (& b , & b , d );
318
+ secp256k1_fe_add (& g , & b );
319
+ if (!known_on_curve ) {
320
+ /* We need to determine whether (n/d)^3 + 7 is square.
321
+ *
322
+ * is_square((n/d)^3 + 7)
323
+ * <=> is_square(((n/d)^3 + 7) * d^4)
324
+ * <=> is_square((n^3 + 7*d^3) * d)
325
+ * <=> is_square(g * d)
326
+ */
327
+ secp256k1_fe c ;
328
+ secp256k1_fe_mul (& c , & g , d );
329
+ if (!secp256k1_fe_is_square_var (& c )) return 0 ;
330
+ }
331
+ } else {
332
+ secp256k1_fe_add_int (& g , SECP256K1_B );
333
+ if (!known_on_curve ) {
334
+ /* g at this point equals x^3 + 7. Test if it is square. */
335
+ if (!secp256k1_fe_is_square_var (& g )) return 0 ;
336
+ }
337
+ }
338
+
339
+ /* Compute base point P = (n*g, g^2), the effective affine version of (n*g, g^2, v), which has
340
+ * corresponding affine X coordinate n/d. */
341
+ secp256k1_fe_mul (& p .x , & g , n );
342
+ secp256k1_fe_sqr (& p .y , & g );
343
+ p .infinity = 0 ;
344
+
345
+ /* Perform x-only EC multiplication of P with q. */
346
+ #ifdef VERIFY
347
+ VERIFY_CHECK (!secp256k1_scalar_is_zero (q ));
348
+ #endif
349
+ secp256k1_ecmult_const (& rj , & p , q , bits );
350
+ #ifdef VERIFY
351
+ VERIFY_CHECK (!secp256k1_gej_is_infinity (& rj ));
352
+ #endif
353
+
354
+ /* The resulting (X, Y, Z) point on the effective-affine isomorphic curve corresponds to
355
+ * (X, Y, Z*v) on the secp256k1 curve. The affine version of that has X coordinate
356
+ * (X / (Z^2*d*g)). */
357
+ secp256k1_fe_sqr (& i , & rj .z );
358
+ secp256k1_fe_mul (& i , & i , & g );
359
+ if (d ) secp256k1_fe_mul (& i , & i , d );
360
+ secp256k1_fe_inv (& i , & i );
361
+ secp256k1_fe_mul (r , & rj .x , & i );
362
+
363
+ return 1 ;
364
+ }
365
+
231
366
#endif /* SECP256K1_ECMULT_CONST_IMPL_H */
0 commit comments