Skip to content

Commit c94ed24

Browse files
committed
Elligator Squared module
This adds a module with an implementation of the Elligator Squared algorithm for encoding/decoding public keys in uniformly random byte arrays.
1 parent 042f91b commit c94ed24

File tree

9 files changed

+636
-0
lines changed

9 files changed

+636
-0
lines changed

Makefile.am

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,7 @@ endif
173173
if ENABLE_MODULE_SCHNORRSIG
174174
include src/modules/schnorrsig/Makefile.am.include
175175
endif
176+
177+
if ENABLE_MODULE_ELLSQ
178+
include src/modules/ellsq/Makefile.am.include
179+
endif

configure.ac

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ AC_ARG_ENABLE(module_schnorrsig,
161161
[enable_module_schnorrsig=$enableval],
162162
[enable_module_schnorrsig=no])
163163

164+
AC_ARG_ENABLE(module_ellsq,
165+
AS_HELP_STRING([--enable-module-ellsq],[enable Elligator^2 module (experimental)]),
166+
[enable_module_ellsq=$enableval],
167+
[enable_module_ellsq=no])
168+
164169
AC_ARG_ENABLE(external_default_callbacks,
165170
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]),
166171
[use_external_default_callbacks=$enableval],
@@ -456,6 +461,10 @@ if test x"$enable_module_extrakeys" = x"yes"; then
456461
AC_DEFINE(ENABLE_MODULE_EXTRAKEYS, 1, [Define this symbol to enable the extrakeys module])
457462
fi
458463

464+
if test x"$enable_module_ellsq" = x"yes"; then
465+
AC_DEFINE(ENABLE_MODULE_ELLSQ, 1, [Define this symbol to enable the Elligator^2 module])
466+
fi
467+
459468
if test x"$use_external_default_callbacks" = x"yes"; then
460469
AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used])
461470
fi
@@ -470,6 +479,7 @@ if test x"$enable_experimental" = x"yes"; then
470479
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
471480
AC_MSG_NOTICE([Building extrakeys module: $enable_module_extrakeys])
472481
AC_MSG_NOTICE([Building schnorrsig module: $enable_module_schnorrsig])
482+
AC_MSG_NOTICE([Building Elligator^2 module: $enable_module_ellsq])
473483
AC_MSG_NOTICE([******])
474484
else
475485
if test x"$enable_module_extrakeys" = x"yes"; then
@@ -478,6 +488,9 @@ else
478488
if test x"$enable_module_schnorrsig" = x"yes"; then
479489
AC_MSG_ERROR([schnorrsig module is experimental. Use --enable-experimental to allow.])
480490
fi
491+
if test x"$enable_module_ellsq" = x"yes"; then
492+
AC_MSG_ERROR([Elligator^2 module is experimental. Use --enable-experimental to allow.])
493+
fi
481494
if test x"$set_asm" = x"arm"; then
482495
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
483496
fi
@@ -503,6 +516,7 @@ AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
503516
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
504517
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
505518
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
519+
AM_CONDITIONAL([ENABLE_MODULE_ELLSQ], [test x"$enable_module_ellsq" = x"yes"])
506520
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
507521
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
508522

@@ -525,6 +539,7 @@ echo " module ecdh = $enable_module_ecdh"
525539
echo " module recovery = $enable_module_recovery"
526540
echo " module extrakeys = $enable_module_extrakeys"
527541
echo " module schnorrsig = $enable_module_schnorrsig"
542+
echo " module ellsq = $enable_module_ellsq"
528543
echo
529544
echo " asm = $set_asm"
530545
echo " ecmult window size = $set_ecmult_window"

include/secp256k1_ellsq.h

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#ifndef SECP256K1_ELLSQ_H
2+
#define SECP256K1_ELLSQ_H
3+
4+
#include "secp256k1.h"
5+
6+
#ifdef __cplusplus
7+
extern "C" {
8+
#endif
9+
10+
/* This module provides an implementation of the Elligator Squared encoding
11+
* for secp256k1 public keys. Given a uniformly random public key, this
12+
* produces a 64-byte encoding that is indistinguishable from uniformly
13+
* random bytes.
14+
*
15+
* Elligator Squared is described in https://eprint.iacr.org/2014/043.pdf by
16+
* Mehdi Tibouchi. The mapping function used is described in
17+
* https://www.di.ens.fr/~fouque/pub/latincrypt12.pdf by Fouque and Tibouchi.
18+
*
19+
* Let f be the function from field elements to curve points, defined as
20+
* follows:
21+
* f(t):
22+
* - Let c = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852
23+
* - Let x1 = (c - 1)/2 - c*t^2 / (t^2 + 8) (mod p)
24+
* - Let x2 = (-c - 1)/2 + c*t^2 / (t^2 + 8) (mod p)
25+
* - Let x3 = 1 - (t^2 + 8)^2 / (3*t^2) (mod p)
26+
* - Let x be the first of [x1,x2,x3] that is an X coordinate on the curve
27+
* (at least one of them is, for any field element t).
28+
* - Let y be the the corresponding Y coordinate to x, with the same parity
29+
* as t (even if t is even, odd if t is odd).
30+
* - Return the curve point with coordinates (x, y).
31+
*
32+
* Then an Elligator Squared encoding of P consists of the 32-byte big-endian
33+
* encodings of field elements u1 and u2 concatenated, where f(u1)+f(u2) = P.
34+
* The encoding algorithm is described in the paper, and effectively picks a
35+
* uniformly random pair (u1,u2) among those which encode P.
36+
*
37+
* To make the encoding able to deal with all inputs, if f(u1)+f(u2) is the
38+
* point at infinity, the decoding is defined to be f(0) instead.
39+
*/
40+
41+
/* Construct a 64-byte Elligator Squared encoding of a given pubkey.
42+
*
43+
* Returns: 1 when pubkey is valid.
44+
* Args: ctx: pointer to a context object
45+
* Out: ell64: pointer to a 64-byte array to be filled
46+
* In: rnd32: pointer to 32 bytes of entropy (must be unpredictable)
47+
* pubkey: a pointer to a secp256k1_pubkey containing an
48+
* initialized public key
49+
*
50+
* This function runs in variable time.
51+
*/
52+
SECP256K1_API int secp256k1_ellsq_encode(
53+
const secp256k1_context* ctx,
54+
unsigned char *ell64,
55+
const unsigned char *rnd32,
56+
const secp256k1_pubkey *pubkey
57+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
58+
59+
/** Decode a 64-bytes Elligator Squared encoded public key.
60+
*
61+
* Returns: always 1
62+
* Args: ctx: pointer to a context object
63+
* Out: pubkey: pointer to a secp256k1_pubkey that will be filled
64+
* In: ell64: pointer to a 64-byte array to decode
65+
*
66+
* This function runs in variable time.
67+
*/
68+
SECP256K1_API int secp256k1_ellsq_decode(
69+
const secp256k1_context* ctx,
70+
secp256k1_pubkey *pubkey,
71+
const unsigned char *ell64
72+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
73+
74+
#ifdef __cplusplus
75+
}
76+
#endif
77+
78+
#endif /* SECP256K1_ELLSQ_H */

src/bench_ellsq.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/***********************************************************************
2+
* Copyright (c) 2021 Pieter Wuille *
3+
* Distributed under the MIT software license, see the accompanying *
4+
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
5+
***********************************************************************/
6+
7+
#include <string.h>
8+
9+
#include "../include/secp256k1.h"
10+
#include "../include/secp256k1_ellsq.h"
11+
#include "util.h"
12+
#include "bench.h"
13+
14+
typedef struct {
15+
secp256k1_context *ctx;
16+
secp256k1_pubkey point;
17+
unsigned char rnd64[64];
18+
} bench_ellsq_data;
19+
20+
static void bench_ellsq_setup(void* arg) {
21+
bench_ellsq_data *data = (bench_ellsq_data*)arg;
22+
const unsigned char point[] = {
23+
0x03,
24+
0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06,
25+
0xc2, 0x37, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd,
26+
0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb,
27+
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f
28+
};
29+
CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1);
30+
}
31+
32+
static void bench_ellsq_encode(void* arg, int iters) {
33+
int i;
34+
bench_ellsq_data *data = (bench_ellsq_data*)arg;
35+
36+
for (i = 0; i < iters; i++) {
37+
data->rnd64[29] ^= 145;
38+
CHECK(secp256k1_ellsq_encode(data->ctx, data->rnd64, data->rnd64 + 16, &data->point) == 1);
39+
}
40+
}
41+
42+
static void bench_ellsq_decode(void* arg, int iters) {
43+
int i;
44+
secp256k1_pubkey out;
45+
bench_ellsq_data *data = (bench_ellsq_data*)arg;
46+
47+
for (i = 0; i < iters; i++) {
48+
data->rnd64[13] ^= 247;
49+
data->rnd64[47] ^= 113;
50+
CHECK(secp256k1_ellsq_decode(data->ctx, &out, data->rnd64) == 1);
51+
memcpy(data->rnd64, &out.data, 64);
52+
}
53+
}
54+
55+
int main(void) {
56+
bench_ellsq_data data;
57+
58+
int iters = get_iters(10000);
59+
60+
/* create a context with no capabilities */
61+
data.ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT);
62+
memset(data.rnd64, 11, sizeof(data.rnd64));
63+
64+
run_benchmark("ellsq_encode", bench_ellsq_encode, bench_ellsq_setup, NULL, &data, 10, iters);
65+
run_benchmark("ellsq_decode", bench_ellsq_decode, bench_ellsq_setup, NULL, &data, 10, iters);
66+
67+
secp256k1_context_destroy(data.ctx);
68+
69+
return 0;
70+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
include_HEADERS += include/secp256k1_ellsq.h
2+
noinst_HEADERS += src/modules/ellsq/main_impl.h
3+
noinst_HEADERS += src/modules/ellsq/tests_impl.h
4+
if USE_BENCHMARK
5+
noinst_PROGRAMS += bench_ellsq
6+
bench_ellsq_SOURCES = src/bench_ellsq.c
7+
bench_ellsq_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
8+
endif

0 commit comments

Comments
 (0)