-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds a module with an implementation of the Elligator Squared algorithm for encoding/decoding public keys in uniformly random byte arrays.
- Loading branch information
Showing
9 changed files
with
649 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(u1) 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 */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <string.h> | ||
|
||
#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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Oops, something went wrong.