Skip to content

Commit

Permalink
ElligatorSwift
Browse files Browse the repository at this point in the history
  • Loading branch information
sipa committed Jul 21, 2022
1 parent a3bb417 commit 34227ad
Show file tree
Hide file tree
Showing 12 changed files with 848 additions and 3 deletions.
15 changes: 12 additions & 3 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ env:
ECDH: no
RECOVERY: no
SCHNORRSIG: no
ELLSWIFT: no
### test options
SECP256K1_TEST_ITERS:
BENCH: yes
Expand Down Expand Up @@ -67,11 +68,11 @@ task:
<< : *LINUX_CONTAINER
matrix: &ENV_MATRIX
- env: {WIDEMUL: int64, RECOVERY: yes}
- env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes}
- env: {WIDEMUL: int128}
- env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes, ELLSWIFT: yes}
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128, ASM: x86_64}
- env: {WIDEMUL: int128, ASM: x86_64 , ELLSWIFT: yes}
- env: { RECOVERY: yes, SCHNORRSIG: yes}
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no}
- env: {CPPFLAGS: -DDETERMINISTIC}
Expand Down Expand Up @@ -178,6 +179,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
ELLSWIFT: yes
CTIMETEST: no
<< : *MERGE_BASE
test_script:
Expand All @@ -197,6 +199,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
ELLSWIFT: yes
CTIMETEST: no
matrix:
- env: {}
Expand All @@ -217,6 +220,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
ELLSWIFT: yes
CTIMETEST: no
<< : *MERGE_BASE
test_script:
Expand All @@ -234,6 +238,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
ELLSWIFT: yes
CTIMETEST: no
<< : *MERGE_BASE
test_script:
Expand Down Expand Up @@ -271,6 +276,8 @@ task:
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
ELLSWIFT: yes
ELLSWIFT: yes
CTIMETEST: no
# Set non-essential options that affect the CLI messages here.
# (They depend on the user's taste, so we don't want to set them automatically in configure.ac.)
Expand Down Expand Up @@ -304,6 +311,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
ELLSWIFT: yes
CTIMETEST: no
matrix:
- name: "Valgrind (memcheck)"
Expand Down Expand Up @@ -352,6 +360,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
ELLSWIFT: yes
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
Expand Down
4 changes: 4 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,7 @@ endif
if ENABLE_MODULE_SCHNORRSIG
include src/modules/schnorrsig/Makefile.am.include
endif

if ENABLE_MODULE_ELLSWIFT
include src/modules/ellswift/Makefile.am.include
endif
1 change: 1 addition & 0 deletions ci/cirrus.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ $WRAPPER_CMD --version || true
--with-ecmult-window="$ECMULTWINDOW" \
--with-ecmult-gen-precision="$ECMULTGENPRECISION" \
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
--enable-module-ellswift="$ELLSWIFT" \
--enable-module-schnorrsig="$SCHNORRSIG" \
--enable-examples="$EXAMPLES" \
--with-valgrind="$WITH_VALGRIND" \
Expand Down
11 changes: 11 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ AC_ARG_ENABLE(module_schnorrsig,
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_schnorrsig], [no], [yes])])

AC_ARG_ENABLE(module_ellswift,
AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module (experimental)]),
[enable_module_ellswift=$enableval],
[enable_module_ellswift=no])

AC_ARG_ENABLE(external_default_callbacks,
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [],
[SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])])
Expand Down Expand Up @@ -362,6 +367,10 @@ if test x"$enable_module_schnorrsig" = x"yes"; then
enable_module_extrakeys=yes
fi

if test x"$enable_module_ellswift" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_ELLSWIFT, 1, [Define this symbol to enable the ElligatorSwift module])
fi

# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
# module to set enable_module_extrakeys=yes
if test x"$enable_module_extrakeys" = x"yes"; then
Expand Down Expand Up @@ -407,6 +416,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_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"])
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"])
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"])
Expand All @@ -427,6 +437,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 ellswift = $enable_module_ellswift"
echo
echo " asm = $set_asm"
echo " ecmult window size = $set_ecmult_window"
Expand Down
175 changes: 175 additions & 0 deletions include/secp256k1_ellswift.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
#ifndef SECP256K1_ELLSWIFT_H
#define SECP256K1_ELLSWIFT_H

#include "secp256k1.h"

#ifdef __cplusplus
extern "C" {
#endif

/* This module provides an implementation of ElligatorSwift as well as
* a version of x-only ECDH using it.
*
* ElligatorSwift is described in https://eprint.iacr.org/2022/759 by
* Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding
* public keys in 64-byte objects which are indistinguishable from
* uniformly random.
*
* Let f be the function from pairs of field elements to point X coordinates,
* defined as follows (all operations modulo p = 2^256 - 2^32 - 977)
* f(u,t):
* - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852,
* a square root of -3.
* - If u=0, set u=1 instead.
* - If t=0, set t=1 instead.
* - If u^3 + t^2 + 7 = 0, multiply t by 2.
* - Let p = u^3 + t^2 + 7
* - Let m = u^3 - t^2 + 7
* - Let v = (C * m / p - 1) * u / 2
* - Let w = p / (C * t * u)
* - Let x1 = v
* - Let x2 = -u - v
* - Let x3 = u + w^2
* - Return the first of [x3,x2,x1] that is an X coordinate on the curve
* (at least one of them is, for any inputs u and t).
*
* Then an ElligatorSwift encoding of x consists of the 32-byte big-endian
* encodings of field elements u and t concatenated, where f(u,t) = x.
* The encoding algorithm is described in the paper, and effectively picks a
* uniformly random pair (u,t) among those which encode x.
*
* If the Y coordinate is relevant, it is given the same parity as t.
*
* Changes w.r.t. the the paper:
* - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point
* at infinity in the paper. Here they are remapped to finite points.
* - The paper uses an additional encoding bit for the parity of y. Here the
* parity of t is used (negating t does not affect the decoded x coordinate,
* so this is possible).
*/

/** A pointer to a function used for hashing the shared X coordinate along
* with the encoded public keys to a uniform shared secret.
*
* Returns: 1 if a shared secret was was successfully computed.
* 0 will cause secp256k1_ellswift_xdh to fail and return 0.
* Other return values are not allowed, and the behaviour of
* secp256k1_ellswift_xdh is undefined for other return values.
* Out: output: pointer to an array to be filled by the function
* In: x32: pointer to the 32-byte serialized X coordinate
* of the resulting shared point
* ours64: pointer to the 64-byte encoded public key we sent
* to the other party
* theirs64: pointer to the 64-byte encoded public key we received
* from the other party
* data: arbitrary data pointer that is passed through
*/
typedef int (*secp256k1_ellswift_xdh_hash_function)(
unsigned char *output,
const unsigned char *x32,
const unsigned char *ours64,
const unsigned char *theirs64,
void *data
);

/** An implementation of an secp256k1_ellswift_xdh_hash_function which uses
* SHA256(key1 || key2 || x32), where (key1, key2) = sorted([ours64, theirs64]), and
* ignores data. The sorting is lexicographic. */
SECP256K1_API extern const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_sha256;

/** A default secp256k1_ellswift_xdh_hash_function, currently secp256k1_ellswift_xdh_hash_function_sha256. */
SECP256K1_API extern const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_default;

/* Construct a 64-byte ElligatorSwift 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: pubkey: a pointer to a secp256k1_pubkey containing an
* initialized public key
* rnd32: pointer to 32 bytes of entropy (must be unpredictable)
*
* This function runs in variable time.
*/
SECP256K1_API int secp256k1_ellswift_encode(
const secp256k1_context* ctx,
unsigned char *ell64,
const secp256k1_pubkey *pubkey,
const unsigned char *rnd32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);

/** Decode a 64-bytes ElligatorSwift 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_ellswift_decode(
const secp256k1_context* ctx,
secp256k1_pubkey *pubkey,
const unsigned char *ell64
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);

/** Compute an ElligatorSwift public key for a secret key.
*
* Returns: 1: secret was valid, public key was stored.
* 0: secret was invalid, try again.
* Args: ctx: pointer to a context object, initialized for signing.
* Out: ell64: pointer to a 64-byte area to receive the ElligatorSwift public key
* In: seckey32: pointer to a 32-byte secret key.
* auxrand32: (optional) pointer to 32 bytes of additional randomness
*
* Constant time in seckey and auxrand32, but not in the resulting public key.
*
* This function can be used instead of calling secp256k1_ec_pubkey_create followed
* by secp256k1_ellswift_encode. It is safer, as it can use the secret key as
* entropy for the encoding. That means that if the secret key itself is
* unpredictable, no additional auxrand32 is needed to achieve indistinguishability
* of the encoding.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_create(
const secp256k1_context* ctx,
unsigned char *ell64,
const unsigned char *seckey32,
const unsigned char *auxrand32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);

/** Given a private key, and ElligatorSwift public keys sent in both directions,
* compute a shared secret using x-only Diffie-Hellman.
*
* Returns: 1: shared secret was succesfully computed
* 0: secret was invalid or hashfp returned 0
* Args: ctx: pointer to a context object.
* Out: output: pointer to an array to be filled by hashfp.
* In: theirs64: a pointer to the 64-byte ElligatorSquare public key received from the other party.
* ours64: a pointer to the 64-byte ElligatorSquare public key sent to the other party.
* seckey32: a pointer to the 32-byte private key corresponding to ours64.
* hashfp: pointer to a hash function. If NULL,
* secp256k1_elswift_xdh_hash_function_default is used
* (in which case, 32 bytes will be written to output).
* data: arbitrary data pointer that is passed through to hashfp
* (ignored for secp256k1_ellswift_xdh_hash_function_default).
*
* Constant time in seckey32.
*
* This function is more efficient than decoding the public keys, and performing ECDH on them.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_xdh(
const secp256k1_context* ctx,
unsigned char *output,
const unsigned char* theirs64,
const unsigned char* ours64,
const unsigned char* seckey32,
secp256k1_ellswift_xdh_hash_function hashfp,
void *data
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);


#ifdef __cplusplus
}
#endif

#endif /* SECP256K1_ELLSWIFT_H */
9 changes: 9 additions & 0 deletions src/bench.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ static void bench_keygen_run(void* arg, int iters) {
# include "modules/schnorrsig/bench_impl.h"
#endif

#ifdef ENABLE_MODULE_ELLSWIFT
# include "modules/ellswift/bench_impl.h"
#endif

int main(int argc, char** argv) {
int i;
secp256k1_pubkey pubkey;
Expand Down Expand Up @@ -247,5 +251,10 @@ int main(int argc, char** argv) {
run_schnorrsig_bench(iters, argc, argv);
#endif

#ifdef ENABLE_MODULE_ELLSWIFT
/* ElligatorSwift benchmarks */
run_ellswift_bench(iters, argc, argv);
#endif

return 0;
}
4 changes: 4 additions & 0 deletions src/modules/ellswift/Makefile.am.include
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include_HEADERS += include/secp256k1_ellswift.h
noinst_HEADERS += src/modules/ellswift/bench_impl.h
noinst_HEADERS += src/modules/ellswift/main_impl.h
noinst_HEADERS += src/modules/ellswift/tests_impl.h
Loading

0 comments on commit 34227ad

Please sign in to comment.