diff --git a/Makefile.am b/Makefile.am index d8b21de4fb..4a23eea861 100644 --- a/Makefile.am +++ b/Makefile.am @@ -173,3 +173,7 @@ endif if ENABLE_MODULE_SCHNORRSIG include src/modules/schnorrsig/Makefile.am.include endif + +if ENABLE_MODULE_ELLSQ +include src/modules/ellsq/Makefile.am.include +endif diff --git a/configure.ac b/configure.ac index b73bd10fea..e6410fed9b 100644 --- a/configure.ac +++ b/configure.ac @@ -161,6 +161,11 @@ AC_ARG_ENABLE(module_schnorrsig, [enable_module_schnorrsig=$enableval], [enable_module_schnorrsig=no]) +AC_ARG_ENABLE(module_ellsq, + AS_HELP_STRING([--enable-module-ellsq],[enable Elligator^2 module (experimental)]), + [enable_module_ellsq=$enableval], + [enable_module_ellsq=no]) + AC_ARG_ENABLE(external_default_callbacks, AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [use_external_default_callbacks=$enableval], @@ -456,6 +461,10 @@ if test x"$enable_module_extrakeys" = x"yes"; then AC_DEFINE(ENABLE_MODULE_EXTRAKEYS, 1, [Define this symbol to enable the extrakeys module]) fi +if test x"$enable_module_ellsq" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_ELLSQ, 1, [Define this symbol to enable the Elligator^2 module]) +fi + if test x"$use_external_default_callbacks" = x"yes"; then AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used]) fi @@ -470,6 +479,7 @@ if test x"$enable_experimental" = x"yes"; then AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.]) AC_MSG_NOTICE([Building extrakeys module: $enable_module_extrakeys]) AC_MSG_NOTICE([Building schnorrsig module: $enable_module_schnorrsig]) + AC_MSG_NOTICE([Building Elligator^2 module: $enable_module_ellsq]) AC_MSG_NOTICE([******]) else if test x"$enable_module_extrakeys" = x"yes"; then @@ -478,6 +488,9 @@ else if test x"$enable_module_schnorrsig" = x"yes"; then AC_MSG_ERROR([schnorrsig module is experimental. Use --enable-experimental to allow.]) fi + if test x"$enable_module_ellsq" = x"yes"; then + AC_MSG_ERROR([Elligator^2 module is experimental. Use --enable-experimental to allow.]) + fi if test x"$set_asm" = x"arm"; then AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.]) fi @@ -503,6 +516,7 @@ AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_ELLSQ], [test x"$enable_module_ellsq" = x"yes"]) AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"]) AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"]) @@ -525,6 +539,7 @@ echo " module ecdh = $enable_module_ecdh" echo " module recovery = $enable_module_recovery" echo " module extrakeys = $enable_module_extrakeys" echo " module schnorrsig = $enable_module_schnorrsig" +echo " module ellsq = $enable_module_ellsq" echo echo " asm = $set_asm" echo " ecmult window size = $set_ecmult_window" diff --git a/include/secp256k1_ellsq.h b/include/secp256k1_ellsq.h new file mode 100644 index 0000000000..71ce66a0b1 --- /dev/null +++ b/include/secp256k1_ellsq.h @@ -0,0 +1,78 @@ +#ifndef SECP256K1_ELLSQ_H +#define SECP256K1_ELLSQ_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This module provides an implementation of the Elligator Squared encoding + * for secp256k1 public keys. Given a uniformly random public key, this + * produces a 64-byte encoding that is indistinguishable from uniformly + * random bytes. + * + * Elligator Squared is described in https://eprint.iacr.org/2014/043.pdf by + * Mehdi Tibouchi. The mapping function used is described in + * https://www.di.ens.fr/~fouque/pub/latincrypt12.pdf by Fouque and Tibouchi. + * + * Let f be the function from field elements to curve points, defined as + * follows: + * f(t): + * - Let c = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852 + * - Let x1 = (c - 1)/2 - c*t^2 / (t^2 + 8) (mod p) + * - Let x2 = (-c - 1)/2 + c*t^2 / (t^2 + 8) (mod p) + * - Let x3 = 1 - (t^2 + 8)^2 / (3*t^2) (mod p) + * - Let x be the first of [x1,x2,x3] that is an X coordinate on the curve + * (at least one of them is, for any field element t). + * - Let y be the the corresponding Y coordinate to x, with the same parity + * as t (even if t is even, odd if t is odd). + * - Return the curve point with coordinates (x, y). + * + * Then an Elligator Squared encoding of P consists of the 32-byte big-endian + * encodings of field elements u1 and u2 concatenated, where f(u1)+f(u2) = P. + * The encoding algorithm is described in the paper, and effectively picks a + * uniformly random pair (u1,u2) among those which encode P. + * + * To make the encoding able to deal with all inputs, if f(u1)+f(u2) is the + * point at infinity, the decoding is defined to be f(0) instead. + */ + +/* Construct a 64-byte Elligator Squared encoding of a given pubkey. + * + * Returns: 1 when pubkey is valid. + * Args: ctx: pointer to a context object + * Out: ell64: pointer to a 64-byte array to be filled + * In: rnd32: pointer to 32 bytes of entropy (must be unpredictable) + * pubkey: a pointer to a secp256k1_pubkey containing an + * initialized public key + * + * This function runs in variable time. + */ +SECP256K1_API int secp256k1_ellsq_encode( + const secp256k1_context* ctx, + unsigned char *ell64, + const unsigned char *rnd32, + const secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Decode a 64-bytes Elligator Squared encoded public key. + * + * Returns: always 1 + * Args: ctx: pointer to a context object + * Out: pubkey: pointer to a secp256k1_pubkey that will be filled + * In: ell64: pointer to a 64-byte array to decode + * + * This function runs in variable time. + */ +SECP256K1_API int secp256k1_ellsq_decode( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *ell64 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_ELLSQ_H */ diff --git a/src/bench_ellsq.c b/src/bench_ellsq.c new file mode 100644 index 0000000000..de1d97961a --- /dev/null +++ b/src/bench_ellsq.c @@ -0,0 +1,70 @@ +/*********************************************************************** + * Copyright (c) 2021 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#include + +#include "../include/secp256k1.h" +#include "../include/secp256k1_ellsq.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_context *ctx; + secp256k1_pubkey point; + unsigned char rnd64[64]; +} bench_ellsq_data; + +static void bench_ellsq_setup(void* arg) { + bench_ellsq_data *data = (bench_ellsq_data*)arg; + const unsigned char point[] = { + 0x03, + 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, + 0xc2, 0x37, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd, + 0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb, + 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f + }; + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1); +} + +static void bench_ellsq_encode(void* arg, int iters) { + int i; + bench_ellsq_data *data = (bench_ellsq_data*)arg; + + for (i = 0; i < iters; i++) { + data->rnd64[29] ^= 145; + CHECK(secp256k1_ellsq_encode(data->ctx, data->rnd64, data->rnd64 + 16, &data->point) == 1); + } +} + +static void bench_ellsq_decode(void* arg, int iters) { + int i; + secp256k1_pubkey out; + bench_ellsq_data *data = (bench_ellsq_data*)arg; + + for (i = 0; i < iters; i++) { + data->rnd64[13] ^= 247; + data->rnd64[47] ^= 113; + CHECK(secp256k1_ellsq_decode(data->ctx, &out, data->rnd64) == 1); + memcpy(data->rnd64, &out.data, 64); + } +} + +int main(void) { + bench_ellsq_data data; + + int iters = get_iters(10000); + + /* create a context with no capabilities */ + data.ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT); + memset(data.rnd64, 11, sizeof(data.rnd64)); + + run_benchmark("ellsq_encode", bench_ellsq_encode, bench_ellsq_setup, NULL, &data, 10, iters); + run_benchmark("ellsq_decode", bench_ellsq_decode, bench_ellsq_setup, NULL, &data, 10, iters); + + secp256k1_context_destroy(data.ctx); + + return 0; +} diff --git a/src/modules/ellsq/Makefile.am.include b/src/modules/ellsq/Makefile.am.include new file mode 100644 index 0000000000..95baa686c2 --- /dev/null +++ b/src/modules/ellsq/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_ellsq.h +noinst_HEADERS += src/modules/ellsq/main_impl.h +noinst_HEADERS += src/modules/ellsq/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_ellsq +bench_ellsq_SOURCES = src/bench_ellsq.c +bench_ellsq_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +endif diff --git a/src/modules/ellsq/main_impl.h b/src/modules/ellsq/main_impl.h new file mode 100644 index 0000000000..dc080ede75 --- /dev/null +++ b/src/modules/ellsq/main_impl.h @@ -0,0 +1,292 @@ +/*********************************************************************** + * Copyright (c) 2021 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ELLSQ_MAIN_H +#define SECP256K1_MODULE_ELLSQ_MAIN_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_ellsq.h" +#include "../../hash.h" + +/* c1 = the square root of -3 ((-3)**((p+1)/4)). */ +static const secp256k1_fe secp256k1_ellsq_c1 = SECP256K1_FE_CONST(0x0a2d2ba9, 0x3507f1df, 0x233770c2, 0xa797962c, 0xc61f6d15, 0xda14ecd4, 0x7d8d27ae, 0x1cd5f852); +/* c2 = (c1-1)/2 (a cube root of 1). */ +static const secp256k1_fe secp256k1_ellsq_c2 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40); +/* c3 = (-c1-1)/2 (another cube root of 1). */ +static const secp256k1_fe secp256k1_ellsq_c3 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ee); +/* c4 = 16*(c1-1) */ +static const secp256k1_fe secp256k1_ellsq_c4 = SECP256K1_FE_CONST(0xa2d2ba93, 0x507f1df2, 0x33770c2a, 0x797962cc, 0x61f6d15d, 0xa14ecd47, 0xd8d27ae1, 0xcd5f8510); +/* c5 = 1/2 */ +static const secp256k1_fe secp256k1_ellsq_c5 = SECP256K1_FE_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7ffffe18); + +/* Given a field element u, compute a group element out. This functions results in a + * non-infinity point on the curve for every possible input u. It implements the function + * f defined in secp256k1_ellsq.h. + */ +static void secp256k1_ellsq_fe_to_ge_var(secp256k1_ge* out, const secp256k1_fe* u) { + secp256k1_fe t0, t1, t2, t3, t4, x, y; + int ret; + secp256k1_fe_sqr(&t0, u); + secp256k1_fe_set_int(&t1, 8); + secp256k1_fe_add(&t1, &t0); + secp256k1_fe_mul(&t3, &t0, &secp256k1_ellsq_c1); + secp256k1_fe_negate(&t3, &t3, 1); + secp256k1_fe_mul(&t2, &t1, &secp256k1_ellsq_c2); + secp256k1_fe_add(&t2, &t3); + secp256k1_fe_sqr(&t4, &t1); + secp256k1_fe_sqr(&t4, &t4); + secp256k1_fe_mul_int(&t4, 7); + secp256k1_fe_sqr(&t3, &t2); + secp256k1_fe_mul(&t3, &t3, &t2); + secp256k1_fe_mul(&t3, &t3, &t1); + secp256k1_fe_add(&t3, &t4); + if (secp256k1_fe_jacobi_var(&t3) >= 0) { + ret = secp256k1_fe_sqrt(&t4, &t3); + VERIFY_CHECK(ret); + secp256k1_fe_inv_var(&t1, &t1); + secp256k1_fe_mul(&x, &t1, &t2); + secp256k1_fe_sqr(&t1, &t1); + secp256k1_fe_mul(&y, &t1, &t4); + } else { + secp256k1_fe_add(&t2, &t1); + secp256k1_fe_negate(&t2, &t2, 5); + secp256k1_fe_sqr(&t3, &t2); + secp256k1_fe_mul(&t3, &t3, &t2); + secp256k1_fe_mul(&t3, &t3, &t1); + secp256k1_fe_add(&t3, &t4); + if (secp256k1_fe_jacobi_var(&t3) >= 0) { + ret = secp256k1_fe_sqrt(&t4, &t3); + VERIFY_CHECK(ret); + secp256k1_fe_inv_var(&t1, &t1); + secp256k1_fe_mul(&x, &t1, &t2); + secp256k1_fe_sqr(&t1, &t1); + secp256k1_fe_mul(&y, &t1, &t4); + } else { + secp256k1_fe_mul_int(&t0, 3); + secp256k1_fe_inv_var(&t0, &t0); + secp256k1_fe_sqr(&t1, &t1); + secp256k1_fe_mul(&t0, &t0, &t1); + secp256k1_fe_negate(&t0, &t0, 1); + secp256k1_fe_set_int(&x, 1); + secp256k1_fe_add(&x, &t0); + secp256k1_fe_sqr(&t0, &x); + secp256k1_fe_mul(&t0, &t0, &x); + secp256k1_fe_set_int(&t1, 7); + secp256k1_fe_add(&t1, &t0); + ret = secp256k1_fe_sqrt(&y, &t1); + VERIFY_CHECK(ret); + } + } + t0 = *u; + secp256k1_fe_normalize_var(&y); + secp256k1_fe_normalize_var(&t0); + if (secp256k1_fe_is_odd(&y) != secp256k1_fe_is_odd(&t0)) secp256k1_fe_negate(&y, &y, 1); + secp256k1_ge_set_xy(out, &x, &y); +} + +/* Given a point on the curve p, and an integer branch value i in [0,4), compute a + * field element out which secp256k1_ellsq_fe_to_ge_var would map back to p, or + * fail. Combining all non-failing outs for a given p, over all values of i, + * results in the set of all preimages of p under secp256k1_ellsq_fe_to_ge_var. No + * two (p, i) inputs map to the same out, if successful. + * + * i=0 will compute a preimage that maps to p using the "x1" above. + * i=1 will compute a preimage that maps to p using the "x2" above. + * i=2 and i=3 will compute a preimage that maps to using the "x3" above. + * + * All of them will fail if no preimage under the respective x formula exists. + * When i>0, the function will fail when the would-be preimage maps to the curve + * using a lowered-numbered x (so i=1 fails when its x1 lands on the curve, and + * i=2 and i=3 fail when its x1 or x2 land on the curve). In addition, failure is + * returned when a lowered-value i would result in the same preimage. + */ +static int secp256k1_ellsq_ge_to_fe_var(secp256k1_fe* out, const secp256k1_ge* p, int i) { + int ret; + secp256k1_fe t0, t1, t2, t3, u, x = p->x, y = p->y; + secp256k1_fe_normalize_var(&x); + secp256k1_fe_normalize_var(&y); + VERIFY_CHECK(i >= 0); + VERIFY_CHECK(i < 4); + if (i < 2) { + t0 = x; + secp256k1_fe_mul_int(&t0, 2); + secp256k1_fe_set_int(&t1, 1); + secp256k1_fe_add(&t0, &t1); + secp256k1_fe_negate(&t1, &t0, 3); + secp256k1_fe_add(&t1, &secp256k1_ellsq_c1); + secp256k1_fe_add(&t0, &secp256k1_ellsq_c1); + secp256k1_fe_mul(&t2, &t0, &t1); + secp256k1_fe_mul_int(&t2, 8); + if (secp256k1_fe_jacobi_var(&t2) < 0) return 0; + if (i == 0) { + if (secp256k1_fe_normalizes_to_zero_var(&t0)) return 0; + if (secp256k1_fe_normalizes_to_zero_var(&t1) && secp256k1_fe_is_odd(&y)) return 0; + ret = secp256k1_fe_sqrt(&t1, &t2); + VERIFY_CHECK(ret); + secp256k1_fe_inv_var(&t0, &t0); + secp256k1_fe_mul(&u, &t0, &t1); + } else { /* i == 1 */ + secp256k1_fe_set_int(&t0, 1); + secp256k1_fe_add(&t0, &x); + secp256k1_fe_negate(&t0, &t0, 2); + secp256k1_fe_sqr(&t3, &t0); + secp256k1_fe_mul(&t0, &t0, &t3); + secp256k1_fe_set_int(&t3, 7); + secp256k1_fe_add(&t0, &t3); + if (secp256k1_fe_jacobi_var(&t0) >= 0) return 0; + ret = secp256k1_fe_sqrt(&t0, &t2); + VERIFY_CHECK(ret); + secp256k1_fe_inv_var(&t1, &t1); + secp256k1_fe_mul(&u, &t0, &t1); + } + } else { + t0 = x; + secp256k1_fe_mul_int(&t0, 6); + secp256k1_fe_set_int(&t1, 26); + secp256k1_fe_add(&t0, &t1); + secp256k1_fe_sqr(&t1, &t0); + secp256k1_fe_set_int(&t2, 1024); + secp256k1_fe_negate(&t2, &t2, 1); + secp256k1_fe_add(&t2, &t1); + if (secp256k1_fe_jacobi_var(&t2) < 0) return 0; + ret = secp256k1_fe_sqrt(&t1, &t2); + VERIFY_CHECK(ret); + if (i == 3) { + if (secp256k1_fe_normalizes_to_zero_var(&t1)) return 0; + secp256k1_fe_negate(&t1, &t1, 1); + } + secp256k1_fe_negate(&t0, &t0, 7); + secp256k1_fe_add(&t0, &t1); + if (secp256k1_fe_jacobi_var(&t0) < 0) return 0; + secp256k1_fe_set_int(&t1, 32); + secp256k1_fe_normalize_weak(&t0); + secp256k1_fe_add(&t1, &t0); + secp256k1_fe_mul(&t2, &t0, &secp256k1_ellsq_c3); + secp256k1_fe_add(&t2, &secp256k1_ellsq_c4); + secp256k1_fe_sqr(&t3, &t2); + secp256k1_fe_mul(&t3, &t3, &t2); + secp256k1_fe_mul(&t3, &t3, &t1); + secp256k1_fe_sqr(&t1, &t1); + secp256k1_fe_sqr(&t1, &t1); + secp256k1_fe_mul_int(&t1, 7); + secp256k1_fe_add(&t3, &t1); + if (secp256k1_fe_jacobi_var(&t3) >= 0) return 0; + ret = secp256k1_fe_sqrt(&u, &t0); + VERIFY_CHECK(ret); + secp256k1_fe_mul(&u, &u, &secp256k1_ellsq_c5); + } + secp256k1_fe_normalize_var(&u); + if (secp256k1_fe_is_odd(&u) != secp256k1_fe_is_odd(&y)) { + secp256k1_fe_negate(&u, &u, 1); + } + *out = u; + return 1; +} + +int secp256k1_ellsq_encode(const secp256k1_context* ctx, unsigned char *ell64, const unsigned char *rnd32, const secp256k1_pubkey *pubkey) { + secp256k1_ge p; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(ell64 != NULL); + ARG_CHECK(rnd32 != NULL); + ARG_CHECK(pubkey != NULL); + + if (secp256k1_pubkey_load(ctx, &p, pubkey)) { + uint32_t cnt = 0; + /* Field elements and branch values are extracted from + * SHA256("secp256k1_ellsq_encode\x00" + uint32{cnt} + rnd32 + X + byte{Y & 1}) + * for consecutive values of cnt. cnt==0 is first used to populate a pool of + * 128 2-bit branch values. The 128 cnt values that follow are used to + * generate field elements u1. cnt==129 (and multiples thereof) are used to + * repopulate the pool and start over, if that were ever necessary. */ + unsigned char hashdata[23 + 4 + 32 + 32 + 1] = "secp256k1_ellsq_encode"; + /* Pool of 2-bit branch values. */ + unsigned char branch_hash[32]; + /* Number of 2-bit values in branch_hash left. */ + int branches_left = 0; + /* Fill up hashdata, excluding i. */ + memcpy(hashdata + 23 + 4, rnd32, 32); + secp256k1_fe_get_b32(hashdata + 23 + 4 + 32, &p.x); + hashdata[4 + 23 + 32 + 32] = secp256k1_fe_is_odd(&p.y); + while (1) { + int branch; + secp256k1_fe u1, u2; + secp256k1_ge q; + secp256k1_gej qj; + /* If the pool of branch values is empty, populate it. */ + if (branches_left == 0) { + secp256k1_sha256 hash; + hashdata[23 + 0] = cnt; + hashdata[23 + 1] = cnt >> 8; + hashdata[23 + 2] = cnt >> 16; + hashdata[23 + 3] = cnt >> 24; + secp256k1_sha256_initialize(&hash); + secp256k1_sha256_write(&hash, hashdata, sizeof(hashdata)); + secp256k1_sha256_finalize(&hash, branch_hash); + ++cnt; + branches_left = 128; + } + /* Take a 2-bit branch value from the branch pool. */ + --branches_left; + branch = (branch_hash[(127 - branches_left) >> 2] >> (((127 - branches_left) & 3) << 1)) & 3; + /* Compute a new u1 value by hashing (a potential first 32 bytes of the output). */ + { + secp256k1_sha256 hash; + hashdata[23 + 0] = cnt; + hashdata[23 + 1] = cnt >> 8; + hashdata[23 + 2] = cnt >> 16; + hashdata[23 + 3] = cnt >> 24; + secp256k1_sha256_initialize(&hash); + secp256k1_sha256_write(&hash, hashdata, sizeof(hashdata)); + secp256k1_sha256_finalize(&hash, ell64); + ++cnt; + } + if (!secp256k1_fe_set_b32(&u1, ell64)) continue; + /* Compute the remainder Q to encode in the last 32 bytes of the output. */ + secp256k1_ellsq_fe_to_ge_var(&q, &u1); + secp256k1_gej_set_ge(&qj, &q); + secp256k1_gej_neg(&qj, &qj); + secp256k1_gej_add_ge_var(&qj, &qj, &p, NULL); + secp256k1_ge_set_gej(&q, &qj); + /* Try to find a u2 value which encodes Q. */ + if (secp256k1_ellsq_ge_to_fe_var(&u2, &q, branch)) { + /* If that succeeds, store it in the output. */ + secp256k1_fe_normalize_var(&u2); + secp256k1_fe_get_b32(ell64 + 32, &u2); + break; + } + } + memset(hashdata, 0, sizeof(hashdata)); + return 1; + } + /* Only returned in case the provided pubkey is invalid. */ + return 0; +} + +int secp256k1_ellsq_decode(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *ell64) { + secp256k1_fe f1, f2; + secp256k1_ge p1, p2; + secp256k1_gej acc; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(ell64 != NULL); + + secp256k1_fe_set_b32(&f1, ell64); + secp256k1_fe_set_b32(&f2, ell64 + 32); + secp256k1_ellsq_fe_to_ge_var(&p1, &f1); + secp256k1_ellsq_fe_to_ge_var(&p2, &f2); + secp256k1_gej_set_ge(&acc, &p1); + secp256k1_gej_add_ge_var(&acc, &acc, &p2, NULL); + if (secp256k1_gej_is_infinity(&acc)) { + static const secp256k1_fe zero = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_ellsq_fe_to_ge_var(&p1, &zero); + } else { + secp256k1_ge_set_gej_var(&p1, &acc); + } + secp256k1_pubkey_save(pubkey, &p1); + return 1; +} + +#endif diff --git a/src/modules/ellsq/tests_impl.h b/src/modules/ellsq/tests_impl.h new file mode 100644 index 0000000000..565eda6dbe --- /dev/null +++ b/src/modules/ellsq/tests_impl.h @@ -0,0 +1,157 @@ +/*********************************************************************** + * Copyright (c) 2021 Pieter Wuile * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ELLSQ_TESTS_H +#define SECP256K1_MODULE_ELLSQ_TESTS_H + +#include "../../../include/secp256k1_ellsq.h" + +struct ellsq_test { + secp256k1_ge point; + int enc_bitmap; + secp256k1_fe encs[4]; +}; + +/* Set of (point, encodings) test vectors, selected to maximize branch coverage. + * Created using an independent implementation. */ +static const struct ellsq_test ellsq_tests[] = { + {SECP256K1_GE_CONST(0xc27fb7a3, 0x283a7d3e, 0xc9f96421, 0x545ef6f5, 0x8ace7b71, 0x06c8a1b9, 0x07c0ae8a, 0x7598159c, 0xe05a060e, 0x839ef79f, 0xc0c1267c, 0xa17880c9, 0x584cdd34, 0xc05f9695, 0x55482207, 0xe6851f2a), 15, {SECP256K1_FE_CONST(0xc0ad127a, 0xa36824d6, 0x5b1f5be7, 0x4de1aa25, 0xbc4d5cbe, 0xcee15462, 0x0a12682a, 0xfc87df98), SECP256K1_FE_CONST(0xd40fd5bc, 0x51992484, 0x8f13273b, 0x1d857cba, 0x42d45e78, 0x9eaa4e47, 0xf458b83a, 0xbd5f8d1c), SECP256K1_FE_CONST(0xde636141, 0x7deb440b, 0x3a305924, 0x43635cf9, 0xcf42f9b5, 0xf5b891c1, 0x1e119f09, 0x71b570ac), SECP256K1_FE_CONST(0xd55135ce, 0x41bb4d05, 0x5b3757f4, 0xaf1d6537, 0x137376d7, 0x5270caae, 0xda68382d, 0x25d00708)}}, + {SECP256K1_GE_CONST(0x3f5ada4e, 0x8f646ec9, 0x10ffc1a2, 0xb74d94bb, 0xb1860631, 0xa3c2a349, 0xeddf55ca, 0xfd49cce9, 0x28ad9d8d, 0x77d9cd87, 0xf80aaa34, 0x8e9ad1b4, 0x40353d7a, 0x6e717714, 0x60425319, 0x38f530c3), 15, {SECP256K1_FE_CONST(0xac42348f, 0x1b356822, 0x5bb7d4c0, 0x0feab37e, 0xa5fb7fbb, 0x0cc3879d, 0xc74e2dda, 0xf9a393bf), SECP256K1_FE_CONST(0xda7a45b2, 0x6c87dcb6, 0x4a934c1d, 0xc841d250, 0xf98af5f0, 0x511be2a3, 0x82d17bab, 0xe1e4a533), SECP256K1_FE_CONST(0xc3d9b9a6, 0x570ca9c8, 0xa640fc75, 0x945850b2, 0xcc86b6d6, 0x399b4496, 0x4288d76d, 0x832a32d7), SECP256K1_FE_CONST(0xbf5ebc2f, 0x4060abe7, 0x884a1fa7, 0xcc0883cb, 0x97535c5a, 0x31dc6df4, 0xc6968e9d, 0x8554f3b1)}}, + {SECP256K1_GE_CONST(0xf5f74fab, 0x3ebbbcfd, 0xdcaef6cc, 0xd14eb934, 0xf9435a4e, 0x4a1ed2d8, 0x75352c47, 0x306d6c2f, 0xea6a5b2a, 0xe109897d, 0x046e1504, 0xf7a382d6, 0x1eb49a8a, 0xae8852ef, 0x48e29466, 0x194d9e66), 12, {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0xe8362df2, 0x38e0405b, 0x49218747, 0x74f9ebca, 0x36dfe21b, 0x1a49ae2d, 0x0fa23fd4, 0x11a262a6), SECP256K1_FE_CONST(0x9e453426, 0xac973155, 0x19d11d63, 0xc3bb27ee, 0x89a7ec85, 0x5661dce4, 0xe428f6cc, 0x0be059cc)}}, + {SECP256K1_GE_CONST(0x977694f6, 0x6f0a3005, 0x2c638916, 0x61432fa0, 0x605528a7, 0xad87d829, 0x5c9eb9a3, 0x973c6fed, 0x16515f14, 0x00186fec, 0x67f6314c, 0x8a9e2d43, 0x3d2020e9, 0x38f86465, 0x39f749a1, 0x51a793ed), 12, {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x8f091a42, 0xce496be8, 0x877d43fc, 0x2f2b2927, 0x42c9c1fb, 0x0dfe570b, 0x9c9fbd3e, 0x04afa709), SECP256K1_FE_CONST(0xb5930cf1, 0x4db355a5, 0xa92b9f78, 0x9390b59a, 0x013c8e27, 0x7c41ddd6, 0xd8221622, 0x93d39141)}}, + {SECP256K1_GE_CONST(0x9c970ce9, 0x39e8a4ec, 0x70237f33, 0xad858370, 0xc9d30e8a, 0xadaac257, 0x546d1e16, 0xf374973b, 0x95755fab, 0x1bcae32e, 0xc811c63f, 0xb1e56da8, 0x97a1e140, 0xb1aae97e, 0x0b6ae6c5, 0x3879f51c), 13, {SECP256K1_FE_CONST(0xa7424f55, 0x60b58ceb, 0xbb9a6ee1, 0x5fc41b18, 0xf282b2cd, 0xd9e2fb4d, 0x02626c1a, 0xc0a89ec4), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0xd7016e9b, 0x94db9b4c, 0x5bc61c87, 0xaf3b3c9c, 0x72707e5e, 0x48332958, 0xce5371bf, 0xd501a006), SECP256K1_FE_CONST(0xe95cd3a1, 0x2cff74bd, 0x6761a782, 0x61f73f0d, 0x755a80f6, 0x39ccd117, 0x136f9963, 0xf422b82a)}}, + {SECP256K1_GE_CONST(0x48206211, 0x5e6fc771, 0x738b4859, 0x4da66901, 0xa0a8c36e, 0xa61122b7, 0x745cf5fe, 0xec932b64, 0x01c9e1a1, 0x59effb22, 0x4442c868, 0x9119fd26, 0x8cdca070, 0x7edbefb6, 0xea81d5f6, 0x86333768), 13, {SECP256K1_FE_CONST(0xf1047fb9, 0x4cfa6dcd, 0x202e1acc, 0xa85afc88, 0x46381925, 0x7adf32aa, 0x25e19e52, 0xbf3cadd8), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x94dc1b2b, 0x6a24bbdb, 0x36afab1a, 0x6e036e7f, 0xdf1ded22, 0x915bf761, 0x97e5e5a5, 0xc6261582), SECP256K1_FE_CONST(0x8dd664ba, 0x47061bac, 0x0c99d727, 0xac2ade9f, 0xf8d33aff, 0x995a7a28, 0x97f2968c, 0x558ef724)}}, + {SECP256K1_GE_CONST(0x47e54d7b, 0x86025d30, 0x248b18e6, 0xc6b2b128, 0x3f8eb11e, 0x60d11cad, 0xf59884ea, 0x56939f5a, 0xb618d932, 0x6110c200, 0xcbed144f, 0xc6376800, 0xd8ba0de1, 0xd87fa02d, 0x17d1d58d, 0x9652c498), 3, {SECP256K1_FE_CONST(0x8797d6a9, 0xe3614b34, 0x80e43cb6, 0x936cd932, 0xbe4eee02, 0x1e47e067, 0x2d1d9f2f, 0xd0148558), SECP256K1_FE_CONST(0xb19c75d0, 0xb4856c81, 0xb467f8f5, 0xb9f8d849, 0x0e5296f0, 0x4c60d639, 0x6f772b7f, 0x427c5d38), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x8fa5ffb5, 0x597068f6, 0x06785a63, 0x1f74cd6f, 0x8b16e94b, 0xe6cee831, 0x2970e0ec, 0xa9ecda52, 0x6c4f0efe, 0xf1d0eef2, 0xe3281b13, 0x4f29289f, 0x0a9d7b4d, 0xb3118c5f, 0x1d2d1da4, 0x75569ebf), 3, {SECP256K1_FE_CONST(0xe66995d0, 0x9cfdddda, 0xadf4b4ec, 0xc00270ed, 0xaeaacf01, 0x2db38d37, 0xe4143baf, 0x0ae7dfa3), SECP256K1_FE_CONST(0xfe0d264e, 0x3121942c, 0xd5126e26, 0x0766f36c, 0x3a08a689, 0x4e8ec172, 0xf3fdb252, 0x70def1ad), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x016a682d, 0x1df4f869, 0xb32c48b0, 0xa9b442a1, 0x493949fb, 0x85d951d1, 0x21c1143b, 0xd3d5c1af, 0x38d33fe5, 0xd3f9b4b9, 0x82e37dff, 0x7561428d, 0x47ef4ddf, 0x654bd959, 0x51b04e90, 0xa3be50e7), 0, {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x1ec42424, 0xb4d2226f, 0x83f94258, 0xc737d0da, 0xf93a4eb1, 0x1d9b9e3f, 0xd500d5b9, 0xc3aa7c71, 0x84975819, 0xb703da77, 0xca98bd3c, 0xd9bbdc7a, 0xf1dbc7b5, 0x85c590eb, 0xcbd417fd, 0x739ad572), 1, {SECP256K1_FE_CONST(0x945faa12, 0x7e8bf378, 0x63581bfb, 0xde084bf7, 0x63caee39, 0x1449c610, 0xc2074f86, 0xff1bf16c), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x69ee52b2, 0x88dfb06a, 0x449d3db8, 0x7602e094, 0xb4f131e3, 0xf6a4b249, 0xdc0a76ff, 0xdebe989a, 0x3922f1a4, 0xdd208f94, 0xcbac1c5d, 0x34a9278d, 0x84310781, 0x84ff4430, 0x31a14018, 0x95ffd9e6), 1, {SECP256K1_FE_CONST(0xdc1e4760, 0x15bda784, 0xa1b9527b, 0x0357786a, 0xdf2a8028, 0x03957837, 0xe10cff92, 0x5ef4ca7e), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ee, 0x4218f20a, 0xe6c646b3, 0x63db6860, 0x5822fb14, 0x264ca8d2, 0x587fdd6f, 0xbc750d58, 0x7e76a7ee), 0, {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b, 0x3ac01550, 0x68185039, 0x6068aaf0, 0xc3f24144, 0x9a267956, 0x698833d4, 0x80c03dc5, 0x678b67cf), 4, {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0xbde70df5, 0x1939b94c, 0x9c24979f, 0xa7dd04eb, 0xd9b3572d, 0xa7802290, 0x438af2a6, 0x81895441), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x9ddddd8e, 0xc1814a29, 0x3fcca202, 0xebfbe14e, 0x5d808dda, 0x142eee64, 0xc6108381, 0xe99e5cff, 0xb5072d55, 0x37223f39, 0x3e4176d2, 0xcfd93c86, 0x82ca2c22, 0xcd25ec40, 0x877296bd, 0xbb7c08f6), 3, {SECP256K1_FE_CONST(0xadd34f27, 0xc5f90171, 0x75186c23, 0xd14f6ef2, 0xaa182896, 0x77d5373a, 0xd6c31e9f, 0xf6358ae8), SECP256K1_FE_CONST(0xf5ee8614, 0x1916fe03, 0x945d028b, 0xbc354c4a, 0x09f6d6ab, 0x1468ab9a, 0xd8742075, 0x1543c2a2), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x1ee7e9a7, 0xfcd56edf, 0xabf3712e, 0x72cc24a3, 0x0a476f5a, 0x97f77825, 0xf0308620, 0x162f31ad, 0x77bfc7de, 0xc2401a39, 0x8c5e8675, 0x417c8a7b, 0x632f5d64, 0x2f1a5059, 0x9a830b8c, 0x7981f636), 3, {SECP256K1_FE_CONST(0xb3a8d9e7, 0x368af258, 0x3785be92, 0x2ad54dfb, 0x47329513, 0x6ade2d18, 0x2f931cd6, 0x54f35d02), SECP256K1_FE_CONST(0xe1d420e5, 0xfab5c26d, 0xf4294b2b, 0x0c19eb9a, 0x188409bf, 0x48a3741f, 0x31f72acc, 0x6ea93418), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x9e24d0a5, 0xd5014164, 0x987f86bb, 0x1709305a, 0x6fd352a0, 0xa3478fae, 0x3f85e594, 0x21d72a80, 0x3729c39b, 0xbbb26d97, 0xa4ec6bf7, 0xcb4e6453, 0x058e448e, 0x7530b028, 0xd1ae345e, 0x35608d3c), 0, {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x15f2f1a4, 0x339f5f2a, 0x313b9501, 0x5cad8124, 0xd054a171, 0xac2f31cf, 0x529dda7c, 0xfb6a38b4, 0xfe1d0fa5, 0x95b4f7d3, 0x63e82c29, 0x0095189f, 0x5f2be99c, 0x880be4fc, 0x9742a31b, 0x40041eda), 1, {SECP256K1_FE_CONST(0xc1c3ed27, 0x17ffabfd, 0x01132f5e, 0x54dd73c3, 0x475297e0, 0xfdbff814, 0xdc9456b8, 0x4a57b698), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0xd383134d, 0x721cf055, 0x143570e7, 0x82bb323d, 0x5c542a61, 0xe455823e, 0xd60b940f, 0x86826d54, 0x5a88e50b, 0x3f59874e, 0x84dab4a2, 0x07d34623, 0xd836c376, 0xc68dded3, 0xc095a716, 0xf563e4fc), 1, {SECP256K1_FE_CONST(0xe4d2660c, 0x1d50d031, 0x97f5e610, 0x4d9c2066, 0x01f6c791, 0xadb52178, 0xe2bd6c88, 0xe89cf012), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40, 0xbde70df5, 0x1939b94c, 0x9c24979f, 0xa7dd04eb, 0xd9b3572d, 0xa7802290, 0x438af2a6, 0x81895441), 0, {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0xbde70df5, 0x1939b94c, 0x9c24979f, 0xa7dd04eb, 0xd9b3572d, 0xa7802290, 0x438af2a6, 0x81895441), 3, {SECP256K1_FE_CONST(0xd3779b57, 0x3cb17828, 0xac118cff, 0x74412ab5, 0xb84c86f8, 0xa92f48b8, 0xefcbe4c7, 0x0a675631), SECP256K1_FE_CONST(0xea6f729d, 0xdc884123, 0xf0130aa0, 0x339bda36, 0x2166d034, 0xfe50d9d7, 0x53bf0dde, 0x7721fa3f), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x99a70224, 0xc3062c32, 0x6c45d3c6, 0x46a545e9, 0xb152b75b, 0xee868378, 0x07e47951, 0x9e5b600d, 0x95b6675a, 0x10845b66, 0x37ff96e8, 0xe67f2a75, 0xbbf0f764, 0xc56d26c5, 0x4b2db5eb, 0xb026d7de), 3, {SECP256K1_FE_CONST(0xb74a9552, 0xc5b9b6ed, 0x575d380f, 0xec3df8ed, 0xdb524ed1, 0x80b13607, 0x81e2eec6, 0x7ad06c04), SECP256K1_FE_CONST(0xbb702282, 0x4194fbe4, 0x4a74c4f4, 0xabd01ee3, 0xdac8f4cb, 0x5a0e3a67, 0xd2276039, 0xdd4aac1a), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0xb5902433, 0x3110b310, 0x8625f254, 0x47665c1e, 0xbf10c6a6, 0xbbe9f018, 0xc421f4b0, 0xdcb5a993, 0x43bae2cd, 0xaae9c002, 0xe57ac99a, 0x17926e22, 0x76a66728, 0xf92b11bb, 0x7dc953b9, 0xea6d49b7), 3, {SECP256K1_FE_CONST(0xd5a57c1b, 0x71916606, 0xbfb235f0, 0xce8d880d, 0xe9109a01, 0xb86d58c8, 0x2852b211, 0x0e55ee0f), SECP256K1_FE_CONST(0xca6cf74b, 0x128e1d79, 0x75482bfd, 0xc9e81416, 0x71a5c3e7, 0xe2af854b, 0x23707630, 0x97ba917b), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0xb526749e, 0x35fa04ef, 0x5d20b1d6, 0xcda6f57e, 0x2f3c10c9, 0x85098901, 0xc390da79, 0x31769e34, 0x182093b3, 0xce5883a2, 0x7b834af6, 0x18547fd1, 0x6017cee0, 0x4e9398da, 0x6aaaed2b, 0x87ca0e7c), 0, {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x901c52d6, 0xa39718c7, 0x255e94e3, 0x3189cbeb, 0x41f2fa97, 0x95279076, 0xbecd6678, 0x99684c17, 0xf988a838, 0x156cc39f, 0x2182bbc5, 0xf7e4f707, 0x9cf75bfb, 0x58638cff, 0x5b201fd3, 0xcf499fc0), 1, {SECP256K1_FE_CONST(0xa356db31, 0x44b754a3, 0xdafdf2a9, 0x0767b65a, 0xbaea92ca, 0x56c69c3a, 0x31a4ff5b, 0xd7914d9c), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x957d4fd4, 0x4a10f38a, 0x0d0e1e46, 0x2656dd2e, 0x7f2b6b8c, 0x9545ee02, 0x903f28b0, 0x8f9a57e7, 0x3f4bf4de, 0x3731bea3, 0x291627e3, 0x9daa7dac, 0xcdcd4e13, 0xb2418482, 0x488730b7, 0xa7a816b7), 1, {SECP256K1_FE_CONST(0xa761cd3a, 0x58385878, 0x300c6963, 0xe918b545, 0x99eb0254, 0x550f6254, 0xe414628c, 0x2f431bbd), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x0a7b6db2, 0x56f01aea, 0x797a0798, 0x5eaf98d6, 0x64486f82, 0x723758bf, 0x1a5f7b00, 0xb74887e1, 0xe07ce7ec, 0x5f24b6da, 0x199329ff, 0x674788c4, 0x1b7312d4, 0xbb63672f, 0x81ebbfd3, 0x6d962235), 15, {SECP256K1_FE_CONST(0x442e15e3, 0xac31958b, 0x7acdb8b9, 0x7977b6d0, 0x533b1ef0, 0x5094f496, 0x126a04d0, 0xc6d6c327), SECP256K1_FE_CONST(0xc565d637, 0x6c8f4fa4, 0xa22ab5d4, 0xe1c87f5d, 0x6f9beb27, 0x7764a77f, 0x8ebe3796, 0xaa82cba5), SECP256K1_FE_CONST(0x2082a3b7, 0x04d3729c, 0x71a73a0c, 0xd745c7ce, 0x7a7c5e26, 0x77c688e2, 0x772806d1, 0xdd1a849f), SECP256K1_FE_CONST(0xc00c8cc3, 0x5ea8122e, 0xf17b0a8e, 0xc69218d1, 0x8cb45a3f, 0x0227a2c5, 0x68fbd9f9, 0xc6d6d141)}}, + {SECP256K1_GE_CONST(0x770ed6cb, 0xf6d2156b, 0x362523eb, 0xc2908f68, 0x65ab182c, 0x43468bc8, 0x69d6754e, 0x68dc71a0, 0x2a378713, 0x10223129, 0xbaba56c2, 0x0dc4a1e9, 0x634dba32, 0xa034d21f, 0x3104176b, 0x870c9916), 15, {SECP256K1_FE_CONST(0x092c79ab, 0xbbafd66d, 0x58c56208, 0x7ba5c385, 0x9fed6c1b, 0x5f8005af, 0x0087cedb, 0xec7dc084), SECP256K1_FE_CONST(0x3f5c280a, 0x60802515, 0x16dfd84a, 0x4488df47, 0x96198d5f, 0xbce0be21, 0x1ab0ee7d, 0xa456e73e), SECP256K1_FE_CONST(0x94057b6b, 0xd54b13b2, 0xe2b9d322, 0x687569f5, 0xdd16727d, 0x3d912ba3, 0xeb8aa33d, 0x36c15108), SECP256K1_FE_CONST(0x098360ae, 0xcf93979e, 0x7cd6df39, 0x6e8fe2f3, 0x18fa1da3, 0x9efa707a, 0xeab95cd8, 0xcd5dca2a)}}, + {SECP256K1_GE_CONST(0xab01575c, 0x0604c63e, 0xe77d3153, 0x4a5bcfa2, 0x0ce66c9d, 0xf47d6054, 0xb822bfd8, 0x6934f8ec, 0xce488d85, 0xd0875b40, 0x4fb92b6e, 0x8068602a, 0x670ac4f8, 0xd76b78b6, 0xc246b713, 0x595e226b), 12, {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x4ab21b18, 0x1009aa48, 0xb8ba5eb9, 0xd373919b, 0xcfcb36a6, 0xf34961b2, 0xc859f5a8, 0x6da8ba41), SECP256K1_FE_CONST(0x9a11c401, 0x9a4ba9fc, 0xf4698a71, 0x2d85c8e4, 0x70028e02, 0x545ef049, 0xf9f3083d, 0x187c5b41)}}, + {SECP256K1_GE_CONST(0x6084cfdd, 0xf8d9736e, 0xa90100eb, 0xdb43338f, 0x65e2ab43, 0xef35a799, 0x926e6ce3, 0x2a89ae17, 0x753998b5, 0x9eaae7a3, 0xdcab34d9, 0xa15dbc71, 0xe539cdff, 0xdcf05927, 0x0eb27c86, 0xab6b62a4), 12, {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x18b1f707, 0x3fca3167, 0x04e1b3b8, 0x8cc8ff5a, 0x702d79bc, 0x756e4dea, 0x2ff948cc, 0xdb43a9f4), SECP256K1_FE_CONST(0xca02e589, 0x89eb16d1, 0x520463d2, 0x435745cf, 0x6e69fa52, 0x6b5c7adc, 0x57cea2b3, 0xf5a6441c)}}, + {SECP256K1_GE_CONST(0xc9fbac00, 0x9d8eda5d, 0x25c9aabb, 0x2b6794bc, 0x9a801afd, 0x17adef78, 0x78c65392, 0x04eb0f82, 0x95ed9e51, 0x898b903e, 0xe689e6ed, 0xff2b54bf, 0xed5c2da1, 0x69e2bdd0, 0x415a392e, 0x16b3de2b), 13, {SECP256K1_FE_CONST(0x21a95220, 0x8577e3f0, 0xcc5b4b17, 0xf5e434b2, 0x2bbdbaaa, 0x51cd2659, 0xe37880a6, 0xa25aa7dd), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0xcfd1ca13, 0x2f8d3eae, 0x73a97895, 0x01d2c82a, 0x6f057566, 0x7949fab9, 0x267bc1e8, 0xef9bf5bd), SECP256K1_FE_CONST(0x9cde02aa, 0x3acd2596, 0xdbea4b82, 0xf9f47ad1, 0x994ad567, 0x3c0d4fb2, 0xe8a3dca5, 0xe8e067fb)}}, + {SECP256K1_GE_CONST(0x8dcb38d9, 0x0059d4f1, 0x270455af, 0x6f3dd40e, 0x8d671a34, 0xa1fad81d, 0x2470db8a, 0x13b18f76, 0x603ed5be, 0x7bc3e67f, 0x439067da, 0x29949bcb, 0xd3c96c9f, 0x94da4231, 0x3c9c0feb, 0xe5cdf560), 13, {SECP256K1_FE_CONST(0x3ef4008a, 0x8a190a3f, 0x5c97d211, 0x3bb539e1, 0xf4261a78, 0xf7cd85c4, 0xfd254837, 0xeaacd020), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x0fe7af4f, 0xcab80199, 0x37ee0026, 0x47d55d97, 0x575474b3, 0x4b9cc1bb, 0x133f4261, 0x017124a0), SECP256K1_FE_CONST(0x09dcec3b, 0x93c4ab42, 0x91d01dce, 0xccc19525, 0xc801add3, 0x77170c2c, 0x919f5488, 0xf41d6d3e)}}, + {SECP256K1_GE_CONST(0xf69dfe44, 0x890d2b09, 0x4b749a56, 0xf680e851, 0x50c47c4c, 0xd51e7796, 0x3fec4e6a, 0x09dcd0a1, 0xfb5d321c, 0x1e243b63, 0x6dfb71f3, 0xcf0e8a01, 0x2e52b22c, 0x905cec6d, 0x2f6ae32a, 0x6a4eb7be), 3, {SECP256K1_FE_CONST(0xa17fd528, 0x7276cbf6, 0xc168dcde, 0xb32aba14, 0xe1aeae2f, 0xe7f5bea5, 0xa87d384e, 0xe8046aac), SECP256K1_FE_CONST(0x637f176a, 0xf2fe854a, 0x968ab19b, 0xee010554, 0x313e3eff, 0xc6ff8cb4, 0xcb538a6d, 0xbaedd954), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x043a0631, 0x871a3f67, 0xac03c5f8, 0x406b69a0, 0xdc14bd5b, 0x23e55f27, 0xa5d4462b, 0x0f0a2d23, 0x247b9bcc, 0x0019091c, 0x31eb4b03, 0xe731a0b5, 0xa9b33f75, 0xad9e5e63, 0x39286573, 0xa6439d88), 3, {SECP256K1_FE_CONST(0xd65add13, 0xad3044d9, 0x2ebcd0e6, 0xd42853d8, 0xe5733ff6, 0x5297f544, 0x09a3ce89, 0xfdaffbdc), SECP256K1_FE_CONST(0x7281ad3c, 0x85de3870, 0x84f64e14, 0x42b37154, 0xeab39453, 0x8b1c0753, 0x4b303ae7, 0x37f3973e), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x8855508a, 0xade16ec5, 0x73d21e6a, 0x485dfd0a, 0x7624085c, 0x1a14b5ec, 0xdd6485de, 0x0c6839a4, 0xe50aaeba, 0xa0ceceec, 0xa1bce62e, 0x5f0fac4b, 0xe78ab03a, 0x7b2deaa6, 0xe5c17e88, 0x98e277e9), 1, {SECP256K1_FE_CONST(0x4e96da73, 0xae14fc85, 0x25eccb2d, 0xf4416924, 0x8a7fd269, 0xa065e065, 0x04d315e6, 0x63666b03), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0xc66327bc, 0x5b0b8b90, 0x37adfd63, 0xc2a9f192, 0x2ce2144a, 0xa513b390, 0xd48bc387, 0xae3ebff6, 0x17a1ca89, 0x64eb0b41, 0x162894e6, 0x4fb4112b, 0x638f96ec, 0xe0c6f30d, 0xef7616fe, 0x0e78386a), 1, {SECP256K1_FE_CONST(0x56e8e17e, 0xfaf989d6, 0xa7efb81d, 0x5a602393, 0x6814930e, 0xbc3f6fdf, 0x72ebf472, 0x69ba4c9a), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b, 0xc53feaaf, 0x97e7afc6, 0x9f97550f, 0x3c0dbebb, 0x65d986a9, 0x9677cc2b, 0x7f3fc239, 0x98749460), 4, {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x4218f20a, 0xe6c646b3, 0x63db6860, 0x5822fb14, 0x264ca8d2, 0x587fdd6f, 0xbc750d58, 0x7e76a7ee), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x9d709c02, 0x74604cb6, 0x3b531fea, 0x35932e2e, 0xc965f4bf, 0x5913e577, 0xff31080b, 0x67727a2e, 0xf2b0b821, 0xa24081a9, 0xd0ca84d9, 0x303068cf, 0x7ea32788, 0x05926b0a, 0xb90b9af7, 0x498efbd5), 3, {SECP256K1_FE_CONST(0xb06abefa, 0x192a6498, 0xbce368ff, 0xacc843fb, 0xb39f8117, 0xa56a1870, 0xf57197ef, 0xd9312f6d), SECP256K1_FE_CONST(0x1263d142, 0xaac9cfc5, 0x64c56650, 0x0fa4a62f, 0x38e727fb, 0xb4dbeaf2, 0x6fdf7d05, 0xfd022c71), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0xb4955dcb, 0x4daaa784, 0x9b421c14, 0x53ec8945, 0xd685d554, 0xf41103f8, 0x12cbfb2f, 0x54a4539b, 0x354d18e4, 0xb1cee7a3, 0xf98b0651, 0xf5544091, 0xe8a00656, 0x0c74750d, 0xaadf460e, 0xc3f620ea), 3, {SECP256K1_FE_CONST(0x6281a8a7, 0x0a3b5745, 0xb897ce4f, 0x58305fb0, 0xd6a0f8ab, 0xa6c5ba18, 0xed278ce1, 0x50f7911c), SECP256K1_FE_CONST(0x5f95a708, 0x2d2f6d69, 0xf7ff9b74, 0x2b88063c, 0x39a3003b, 0xb03f333c, 0x7e3d7c5e, 0xd861fb04), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x6ad63dfd, 0xcd231967, 0xff2508f4, 0x75896976, 0xf8728e40, 0xdd7a2acc, 0x6b5ced37, 0xcada8291, 0xf93e5181, 0x8f5329b8, 0xd520a9af, 0xd72938e1, 0x2e3f8be6, 0x421d2bce, 0x89d7b14e, 0x25bf5336), 1, {SECP256K1_FE_CONST(0x0f050318, 0x622f79f1, 0x5a2b23d9, 0xf76329b7, 0x8e195f1a, 0x4651aae0, 0x65d58bcd, 0xdfa4d3b6), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0xa91b7f2a, 0xb93de821, 0xabeec175, 0x0258e4d4, 0xf5f09831, 0xb0a11dda, 0x47e89ddf, 0x6944d819, 0x22eb9bf6, 0x4a517df2, 0xc27d1c55, 0x1df07609, 0x166fc995, 0xe2b39fee, 0x0473ea46, 0xed14efc1), 1, {SECP256K1_FE_CONST(0x7a01651a, 0x81a7f09e, 0x2733cf34, 0x9e6472a1, 0x18c16780, 0x6f5c880f, 0x534b89a6, 0x52be06a7), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x4218f20a, 0xe6c646b3, 0x63db6860, 0x5822fb14, 0x264ca8d2, 0x587fdd6f, 0xbc750d58, 0x7e76a7ee), 3, {SECP256K1_FE_CONST(0x2c8864a8, 0xc34e87d7, 0x53ee7300, 0x8bbed54a, 0x47b37907, 0x56d0b747, 0x10341b37, 0xf598a5fe), SECP256K1_FE_CONST(0x15908d62, 0x2377bedc, 0x0fecf55f, 0xcc6425c9, 0xde992fcb, 0x01af2628, 0xac40f220, 0x88de01f0), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0xa64de96a, 0x6254cefc, 0xffbeaf89, 0x8f2c228a, 0xf6d405f3, 0xbcc6a4cc, 0xe068312a, 0xf7ccf8e1, 0x8f9b3a1b, 0x2d146ea9, 0x54bfc5e2, 0xcdfe861c, 0xcbed8431, 0xc741c5f9, 0xd32f16a3, 0x073ea496), 3, {SECP256K1_FE_CONST(0x4591d33d, 0x1a133a87, 0x94689b1b, 0x0ca445b7, 0x8ada3bce, 0xc2e812b0, 0x8315e2b1, 0x07940ad4), SECP256K1_FE_CONST(0xa763d217, 0x6027d40e, 0x8a8ff34b, 0xd9c639b7, 0x3e2ea045, 0x92274fdc, 0xfa4051c6, 0x6d93a1b6), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x49a0dc06, 0x8c3f117a, 0xefdc842d, 0x3d358153, 0xf677f04c, 0x6dabc9c9, 0x1b09d452, 0xfef27b66, 0x7b944da4, 0x8a175dbc, 0x444ead8d, 0xb82eff66, 0xb081a8aa, 0xe6453fed, 0x2bca9720, 0xb44dd6e5), 3, {SECP256K1_FE_CONST(0x7bf1e2b1, 0x720c1c44, 0x0db64687, 0xf16439fa, 0x41b39833, 0x8095f24e, 0xbeec0cfa, 0x88750dc9), SECP256K1_FE_CONST(0xdc97e26d, 0x3137445d, 0x6c1269b6, 0x1a765501, 0x0c19c36a, 0x2e361066, 0xe31e2bb1, 0x0403470b), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0xd09a4047, 0xf158fe52, 0xf96c661d, 0x02c68657, 0xc4c976ea, 0x96ea85ef, 0x46d6985b, 0xd540756b, 0xe793bfaa, 0xe9300f18, 0xe6f9b55a, 0xae263223, 0x68b61d51, 0xae5022ef, 0xe266c72d, 0x574178bc), 1, {SECP256K1_FE_CONST(0x7e6175fd, 0xfbb9fb4f, 0xaf6e2b92, 0x5ef86c4a, 0x444d819a, 0xaa82dbee, 0x545d3d9b, 0x296375be), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}}, + {SECP256K1_GE_CONST(0x34986625, 0x04b73c7c, 0x8cecb6c3, 0x3cd493bd, 0xfc190e0f, 0x87d913d7, 0xff9ad42e, 0x222bfe95, 0x245b3a61, 0xb8d46997, 0xf14f2fea, 0x28748996, 0x91eb3254, 0x2b9907d6, 0x5eb9d21d, 0x42454021), 1, {SECP256K1_FE_CONST(0x7f556282, 0xc3dd9d26, 0x3390d6bb, 0xddada698, 0xab8fd7c7, 0xd1a06498, 0xf42b3043, 0x7c8361ad), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)}} +}; + +struct ellsq_enc_test { + unsigned char ell64[64]; + unsigned char pubkey[33]; +}; + +/* Set of (ell64, point) test vectors, selected to maximize branch coverage. + * Created using an independent implementation. */ +static const struct ellsq_enc_test ellsq_enc_tests[] = { + {{0x54,0xca,0xd2,0x27,0xb2,0xc9,0x8d,0x5f,0x7c,0x78,0x8c,0xfc,0x3d,0xaf,0xd6,0x52,0xf5,0x8f,0x69,0xcf,0xef,0x63,0x2b,0x82,0x2b,0x35,0xd0,0xb0,0xe2,0x4f,0xc0,0x3a,0xd2,0x8c,0xa1,0x4b,0x6f,0x62,0xd4,0x53,0x79,0xc5,0x3f,0x70,0xee,0x40,0x5c,0xa9,0x2c,0xe7,0xb6,0xf9,0x70,0x83,0x13,0x05,0xf2,0x7d,0xc4,0x1e,0xb6,0x9d,0xe0,0x6e}, {0x02,0x11,0x62,0x89,0x03,0x32,0x88,0x91,0xae,0x09,0xd1,0x08,0xd8,0x92,0x43,0xe4,0x7e,0x10,0x9f,0xe7,0xb8,0xbb,0x1e,0x2d,0xf1,0xa3,0xae,0x9b,0x0e,0x78,0x08,0x54,0x9c}}, + {{0xfb,0xe6,0xce,0xab,0x4c,0x5f,0xdf,0xa5,0xfb,0xee,0x8f,0x3d,0x09,0xa2,0xf7,0x23,0x53,0xe7,0x4e,0x5a,0x9c,0xd4,0xab,0x8e,0x6a,0x34,0xd4,0x95,0x23,0xa7,0xd1,0xa2,0xc4,0x50,0xb7,0x45,0xda,0xb1,0xaf,0xa9,0x95,0x4b,0x3a,0x35,0x75,0xe4,0xe8,0xe2,0xdb,0x3d,0xa5,0xcd,0x4d,0x56,0x48,0xea,0xd0,0x0a,0x60,0xb4,0xcd,0xfe,0x84,0xb3}, {0x02,0xc0,0x4c,0x84,0x85,0xf9,0x8d,0x56,0x6c,0x79,0xbf,0x33,0xa7,0x0c,0xb2,0x32,0x54,0x9e,0x3d,0xe1,0xc3,0xe3,0x01,0xe3,0x57,0x1c,0x83,0x68,0x97,0xf0,0x7c,0x5d,0x12}}, + {{0x71,0x7e,0x63,0xd7,0x71,0xdb,0xda,0x67,0x67,0xd5,0x8f,0x26,0xab,0x5f,0x54,0x9b,0xd2,0xd1,0x8a,0xcf,0x59,0xff,0x50,0x77,0x5f,0x4e,0xb5,0x0a,0xc0,0x17,0x4d,0xf1,0x7d,0xd0,0x34,0xc8,0xed,0x08,0x11,0x61,0x5e,0x3e,0xbb,0x36,0xf8,0xf3,0x3e,0x09,0x23,0x8e,0x4d,0xa8,0xf5,0x01,0x9d,0x37,0x00,0x78,0x4f,0x37,0xc1,0x53,0x53,0x94}, {0x02,0x72,0x81,0x15,0x0c,0xeb,0xc3,0xd7,0xb3,0xbb,0xb9,0x92,0xf5,0x81,0xbb,0xcb,0x9e,0x30,0x4f,0x87,0x44,0xf0,0x19,0x98,0xa7,0x1f,0x5d,0xe1,0x14,0xf8,0x22,0x91,0xc4}}, + {{0x01,0xf0,0xbf,0xe4,0xf9,0xbd,0xee,0x52,0x5e,0xb7,0x7c,0x8e,0x35,0x1e,0x1f,0x88,0x3f,0xb9,0xcd,0x37,0x7e,0xf7,0xc5,0xbd,0xde,0xe4,0xf6,0x60,0x64,0x43,0x90,0xf5,0x95,0x3e,0x7d,0x2b,0x6c,0xde,0x36,0x90,0x3e,0xa1,0x34,0x4b,0x0d,0x16,0x33,0x5c,0xc5,0x11,0x5d,0xaa,0x97,0x7c,0x3c,0x2b,0xf9,0x31,0xac,0xde,0x2f,0xf5,0x78,0x9a}, {0x02,0x10,0x44,0x9d,0x7e,0xa0,0x62,0x3e,0x80,0xa5,0x87,0x01,0x9f,0xa5,0x11,0xaf,0xd3,0x94,0xb2,0x55,0xb0,0x8f,0x91,0xb5,0xf7,0x48,0x2a,0xe9,0xd1,0xa1,0xa7,0xfb,0x7c}}, + {{0x82,0xd5,0x87,0x1e,0x18,0x37,0x66,0xbd,0x22,0xe1,0x13,0xa8,0x52,0x79,0xaa,0x61,0x7e,0x6b,0x9f,0x73,0x52,0x2c,0xd4,0x6b,0x90,0x59,0xba,0x51,0x97,0xfa,0x56,0x44,0xaf,0x90,0x41,0x89,0x30,0x98,0x7d,0xb7,0xab,0x4a,0x84,0x0c,0x72,0x64,0x1b,0x58,0xb3,0x66,0xe5,0x7c,0x92,0x8c,0x98,0x3a,0x47,0x37,0x82,0x00,0x3c,0x36,0x10,0xab}, {0x03,0xc8,0xb2,0x62,0xf9,0x31,0x69,0x43,0x75,0x51,0x48,0x3b,0x8a,0x61,0x19,0x83,0x82,0xe3,0x11,0x41,0xaf,0x61,0xbf,0x36,0x10,0x0b,0xd0,0x68,0x46,0x5d,0xdd,0xa8,0x40}}, + {{0xda,0x82,0x53,0xb4,0x3b,0x5a,0xc2,0x3b,0x42,0x36,0x07,0xe9,0x18,0xab,0x5c,0xaa,0x5d,0x7d,0x34,0x3d,0x77,0xa3,0x99,0x6a,0x42,0xeb,0x33,0x2a,0x3b,0x55,0x1d,0x8c,0xda,0x6c,0xb6,0xf9,0x57,0x4c,0xe3,0x60,0x91,0x2c,0xf4,0x5b,0x90,0x9a,0x96,0x2e,0x4d,0xed,0x63,0xae,0x5a,0xac,0xb0,0xab,0x23,0x29,0x45,0xb1,0x01,0xf7,0x2b,0x62}, {0x02,0xe7,0x28,0x34,0x1d,0xf6,0x93,0x48,0x71,0xb3,0x94,0xbb,0x4f,0xb2,0x8b,0xd8,0xd2,0xdf,0x39,0x92,0x55,0xb0,0x30,0x02,0xed,0x6f,0xc3,0x8f,0x28,0xcf,0xbf,0x53,0x56}}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, {0x03,0x1b,0x41,0x2e,0x7a,0x96,0x6d,0x2c,0x24,0x3d,0xbc,0x5b,0x18,0xb7,0xf9,0xba,0xf1,0x85,0xbc,0xfe,0x41,0x38,0x96,0x04,0x79,0x64,0x1a,0xb1,0xe6,0x3b,0x38,0x1e,0x11}}, + {{0xdc,0x30,0x98,0xe4,0x00,0x61,0x83,0x30,0xf3,0x8b,0x19,0xe9,0x20,0x0a,0xdf,0x7f,0xfb,0x96,0x84,0x3f,0xa8,0x3c,0x49,0x1c,0xf6,0x7f,0x34,0xa7,0x90,0xbb,0xcf,0xe1,0x23,0xdc,0x30,0x07,0xa4,0xfd,0x13,0x3a,0x39,0x44,0x0b,0x06,0x03,0x1e,0x9e,0x2c,0x38,0x8e,0x41,0x47,0xaf,0x0e,0x82,0xbe,0xda,0x6d,0x56,0x4b,0xf8,0xcc,0x37,0xb1}, {0x02,0x5b,0x74,0x48,0x15,0x22,0xd4,0xc2,0x9f,0x2e,0x6a,0x2f,0x11,0x7f,0x9e,0x39,0xf9,0xab,0x01,0xb1,0xe9,0xf2,0xc3,0x4c,0x68,0xbe,0x8f,0x53,0x1b,0xe0,0x1f,0x6e,0xa7}}, + {{0x35,0xd7,0x0a,0x71,0x2c,0xc0,0x85,0x7f,0x8d,0xb1,0xbc,0x55,0x6a,0x6c,0x4e,0xf8,0x66,0x24,0xfd,0x0a,0x47,0x7f,0x96,0x7e,0xed,0xc0,0x32,0xfc,0xda,0xac,0xe7,0x96,0xc6,0x73,0xc5,0x43,0xd0,0x07,0x34,0x32,0x07,0x85,0x5b,0xeb,0xad,0x85,0xe9,0x4b,0xca,0xc7,0x78,0x2b,0x11,0x57,0x9a,0x70,0xdc,0x88,0xe2,0xa4,0x8d,0x9d,0xf2,0xd4}, {0x02,0xdb,0x21,0xb4,0x8f,0xe9,0xf9,0x95,0x08,0x3a,0x1f,0x9c,0x1f,0x3f,0x4b,0x31,0x1d,0x2c,0x43,0xa1,0x28,0xdb,0xb3,0xa4,0xd4,0x78,0x41,0xe4,0xff,0x5d,0xd0,0x2e,0x61}}, + {{0xde,0x17,0x8b,0x8a,0x45,0x8a,0xfb,0xeb,0x1b,0x3a,0x78,0x86,0x09,0x3d,0xc3,0x1b,0x76,0x11,0x3f,0xbf,0xb8,0xef,0x09,0x57,0x63,0x72,0x6e,0x6f,0x07,0x61,0x03,0xd2,0x9e,0xe1,0xc6,0x95,0x3b,0x6e,0x0b,0xd0,0x89,0x31,0xd3,0x9b,0x90,0x71,0xc3,0x8e,0xb9,0x32,0x92,0xbb,0x36,0xae,0x23,0x40,0x16,0xc2,0xb2,0xcd,0x59,0x22,0x75,0x77}, {0x03,0x64,0xad,0x96,0xf9,0x30,0xbb,0x61,0x57,0x9c,0x7f,0x50,0x77,0x1b,0x50,0x98,0xd3,0x51,0x2c,0x87,0xbd,0x7c,0xc8,0x0b,0x81,0x65,0x61,0x20,0xbf,0x3e,0x45,0x86,0x67}}, + {{0x5f,0xb8,0x07,0xce,0x10,0x0c,0x90,0xd2,0x83,0x7c,0xcf,0xc9,0x4d,0x8f,0x8b,0xa5,0xd3,0x5c,0xd3,0xd6,0xfa,0xfc,0xd2,0xf4,0x1f,0x24,0x5b,0x59,0x6e,0x36,0x00,0x57,0xa0,0x47,0xf8,0x31,0xef,0xf3,0x6f,0x2d,0x7c,0x83,0x30,0x36,0xb2,0x70,0x74,0x5a,0x2c,0xa3,0x2c,0x29,0x05,0x03,0x2d,0x0b,0xe0,0xdb,0xa4,0xa5,0x91,0xc9,0xfb,0xd8}, {0x02,0x85,0x16,0x95,0xd4,0x9a,0x83,0xf8,0xef,0x91,0x9b,0xb8,0x61,0x53,0xcb,0xcb,0x16,0x63,0x0f,0xb6,0x8a,0xed,0x0a,0x76,0x6a,0x3e,0xc6,0x93,0xd6,0x8e,0x6a,0xfa,0x40}}, + {{0x86,0xef,0x92,0xfd,0x28,0x09,0x85,0x4f,0x74,0xf7,0x5a,0xeb,0xbe,0xa1,0x8a,0xee,0xc0,0xee,0xdd,0x4e,0x81,0x92,0xc8,0x8c,0xd7,0xcf,0xf5,0xdf,0xc0,0x8a,0x57,0xdc,0x32,0x73,0xbf,0x6f,0x39,0x2d,0xee,0x48,0x4a,0x72,0x2c,0x3d,0xb0,0x0c,0x0e,0xfb,0x40,0xd5,0x1e,0x8a,0x72,0xfc,0xfb,0x78,0x3f,0xa7,0xeb,0xd4,0x30,0x82,0xdb,0x71}, {0x02,0x31,0x74,0x79,0x29,0x80,0x2d,0x79,0x76,0x02,0x26,0x71,0xb2,0xf7,0x5a,0xc0,0x31,0x18,0x56,0xb3,0x84,0xf4,0xb9,0xa8,0x00,0x0d,0x44,0xa2,0xab,0xc5,0x90,0x3a,0xd4}} +}; + +void run_ellsq_tests(void) { + int i = 0; + /* Verify that secp256k1_ellsq_fe_to_ge_var maps everything to curve points for random inputs. */ + for (i = 0; i < 1000*count; i++) { + secp256k1_fe t; + secp256k1_ge g; + random_field_element_test(&t); + secp256k1_ellsq_fe_to_ge_var(&g, &t); + CHECK(secp256k1_ge_is_valid_var(&g)); + } + /* Verify that secp256k1_ellsq_ge_to_fe_var + fe_to_ge_var roundtrips for random inputs. */ + for (i = 0; i < 1000*count; i++) { + int j; + secp256k1_ge g; + random_group_element_test(&g); + for (j = 0; j < 4; j++) { + secp256k1_fe f; + if (secp256k1_ellsq_ge_to_fe_var(&f, &g, j)) { + secp256k1_ge g2; + secp256k1_ellsq_fe_to_ge_var(&g2, &f); + ge_equals_ge(&g, &g2); + } + } + } + /* Verify precomputed test cases. */ + for (i = 0; i < (int)sizeof(ellsq_tests) / (int)sizeof(ellsq_tests[0]); ++i) { + int j; + const struct ellsq_test *test = ellsq_tests + i; + for (j = 0; j < 4; j++) { + secp256k1_fe f; + int ret; + ret = secp256k1_ellsq_ge_to_fe_var(&f, &test->point, j); + CHECK(ret == ((test->enc_bitmap >> j) & 1)); + if (ret) { + secp256k1_ge g; + CHECK(check_fe_equal(&f, &test->encs[j])); + secp256k1_ellsq_fe_to_ge_var(&g, &f); + ge_equals_ge(&test->point, &g); + } + } + } + /* Verify that secp256k1_ellsq_encode + decode roundtrips. */ + for (i = 0; i < 1000*count; i++) { + unsigned char rnd32[32]; + unsigned char ell64[64]; + secp256k1_ge g, g2; + secp256k1_pubkey pubkey, pubkey2; + random_group_element_test(&g); + secp256k1_pubkey_save(&pubkey, &g); + secp256k1_testrand256(rnd32); + secp256k1_ellsq_encode(ctx, ell64, rnd32, &pubkey); + secp256k1_ellsq_decode(ctx, &pubkey2, ell64); + secp256k1_pubkey_load(ctx, &g2, &pubkey2); + ge_equals_ge(&g, &g2); + } + /* Verify decoding of precomputed test cases. */ + for (i = 0; i < (int)sizeof(ellsq_enc_tests) / (int)sizeof(ellsq_enc_tests[0]); ++i) { + secp256k1_pubkey pubkey; + unsigned char pk33[33]; + size_t size = 33; + secp256k1_ellsq_decode(ctx, &pubkey, ellsq_enc_tests[i].ell64); + secp256k1_ec_pubkey_serialize(ctx, pk33, &size, &pubkey, SECP256K1_EC_COMPRESSED); + CHECK(size == 33); + CHECK(secp256k1_memcmp_var(&pk33, ellsq_enc_tests[i].pubkey, size) == 0); + } +} + +#endif diff --git a/src/secp256k1.c b/src/secp256k1.c index 9066920d4f..3ae22a7a06 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -801,3 +801,7 @@ int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32, #ifdef ENABLE_MODULE_SCHNORRSIG # include "modules/schnorrsig/main_impl.h" #endif + +#ifdef ENABLE_MODULE_ELLSQ +# include "modules/ellsq/main_impl.h" +#endif diff --git a/src/tests.c b/src/tests.c index 104a928cd8..e3319310ca 100644 --- a/src/tests.c +++ b/src/tests.c @@ -6500,6 +6500,10 @@ void run_ecdsa_openssl(void) { # include "modules/schnorrsig/tests_impl.h" #endif +#ifdef ENABLE_MODULE_ELLSQ +# include "modules/ellsq/tests_impl.h" +#endif + void run_secp256k1_memczero_test(void) { unsigned char buf1[6] = {1, 2, 3, 4, 5, 6}; unsigned char buf2[sizeof(buf1)]; @@ -6787,6 +6791,10 @@ int main(int argc, char **argv) { run_schnorrsig_tests(); #endif +#ifdef ENABLE_MODULE_ELLSQ + run_ellsq_tests(); +#endif + /* util tests */ run_secp256k1_memczero_test();