Squashed 'src/secp256k1/' changes from 7a49cac..8225239
8225239 Merge #433: Make the libcrypto detection fail the newer API. 12de863 Make the libcrypto detection fail the newer API. 2928420 Merge #427: Remove Schnorr from travis as well 8eecc4a Remove Schnorr from travis as well a8abae7 Merge #310: Add exhaustive test for group functions on a low-order subgroup b4ceedf Add exhaustive test for verification 83836a9 Add exhaustive tests for group arithmetic, signing, and ecmult on a small group 20b8877 Add exhaustive test for group functions on a low-order subgroup 80773a6 Merge #425: Remove Schnorr experiment e06e878 Remove Schnorr experiment 04c8ef3 Merge #407: Modify parameter order of internal functions to match API parameter order 6e06696 Merge #411: Remove guarantees about memcmp-ability 40c8d7e Merge #421: Update scalar_4x64_impl.h a922365 Merge #422: Restructure nonce clearing 3769783 Restructure nonce clearing 0f9e69d Restructure nonce clearing 9d67afa Update scalar_4x64_impl.h 7d15cd7 Merge #413: fix auto-enabled static precompuatation 00c5d2e fix auto-enabled static precompuatation 91219a1 Remove guarantees about memcmp-ability 353c1bf Fix secp256k1_ge_set_table_gej_var parameter order 541b783 Fix secp256k1_ge_set_all_gej_var parameter order 7d893f4 Fix secp256k1_fe_inv_all_var parameter order git-subtree-dir: src/secp256k1 git-subtree-split: 8225239f490f79842a5a3b82ad6cc8aa11d5208e
This commit is contained in:
parent
b2135359b3
commit
7b49f22bdb
33 changed files with 676 additions and 937 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -6,6 +6,7 @@ bench_schnorr_verify
|
|||
bench_recover
|
||||
bench_internal
|
||||
tests
|
||||
exhaustive_tests
|
||||
gen_context
|
||||
*.exe
|
||||
*.so
|
||||
|
|
|
@ -11,7 +11,7 @@ cache:
|
|||
- src/java/guava/
|
||||
env:
|
||||
global:
|
||||
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no EXPERIMENTAL=no
|
||||
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no
|
||||
- GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar
|
||||
matrix:
|
||||
- SCALAR=32bit RECOVERY=yes
|
||||
|
@ -22,15 +22,14 @@ env:
|
|||
- FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes
|
||||
- FIELD=64bit ASM=x86_64
|
||||
- FIELD=64bit ENDOMORPHISM=yes ASM=x86_64
|
||||
- FIELD=32bit SCHNORR=yes EXPERIMENTAL=yes
|
||||
- FIELD=32bit ENDOMORPHISM=yes
|
||||
- BIGNUM=no
|
||||
- BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes EXPERIMENTAL=yes
|
||||
- BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes
|
||||
- BIGNUM=no STATICPRECOMPUTATION=no
|
||||
- BUILD=distcheck
|
||||
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
|
||||
- EXTRAFLAGS=CFLAGS=-O0
|
||||
- BUILD=check-java ECDH=yes SCHNORR=yes EXPERIMENTAL=yes
|
||||
- BUILD=check-java ECDH=yes EXPERIMENTAL=yes
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
|
@ -66,5 +65,5 @@ before_script: ./autogen.sh
|
|||
script:
|
||||
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
|
||||
- if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi
|
||||
- ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-schnorr=$SCHNORR --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
|
||||
- ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
|
||||
os: linux
|
||||
|
|
18
Makefile.am
18
Makefile.am
|
@ -12,9 +12,11 @@ noinst_HEADERS =
|
|||
noinst_HEADERS += src/scalar.h
|
||||
noinst_HEADERS += src/scalar_4x64.h
|
||||
noinst_HEADERS += src/scalar_8x32.h
|
||||
noinst_HEADERS += src/scalar_low.h
|
||||
noinst_HEADERS += src/scalar_impl.h
|
||||
noinst_HEADERS += src/scalar_4x64_impl.h
|
||||
noinst_HEADERS += src/scalar_8x32_impl.h
|
||||
noinst_HEADERS += src/scalar_low_impl.h
|
||||
noinst_HEADERS += src/group.h
|
||||
noinst_HEADERS += src/group_impl.h
|
||||
noinst_HEADERS += src/num_gmp.h
|
||||
|
@ -87,13 +89,23 @@ bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB)
|
|||
bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
|
||||
endif
|
||||
|
||||
TESTS =
|
||||
if USE_TESTS
|
||||
noinst_PROGRAMS += tests
|
||||
tests_SOURCES = src/tests.c
|
||||
tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
|
||||
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
|
||||
tests_LDFLAGS = -static
|
||||
TESTS = tests
|
||||
TESTS += tests
|
||||
endif
|
||||
|
||||
if USE_EXHAUSTIVE_TESTS
|
||||
noinst_PROGRAMS += exhaustive_tests
|
||||
exhaustive_tests_SOURCES = src/tests_exhaustive.c
|
||||
exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src $(SECP_INCLUDES)
|
||||
exhaustive_tests_LDADD = $(SECP_LIBS)
|
||||
exhaustive_tests_LDFLAGS = -static
|
||||
TESTS += exhaustive_tests
|
||||
endif
|
||||
|
||||
JAVAROOT=src/java
|
||||
|
@ -154,10 +166,6 @@ if ENABLE_MODULE_ECDH
|
|||
include src/modules/ecdh/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_SCHNORR
|
||||
include src/modules/schnorr/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_RECOVERY
|
||||
include src/modules/recovery/Makefile.am.include
|
||||
endif
|
||||
|
|
|
@ -46,6 +46,10 @@ if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then
|
|||
ECDSA_sign(0, NULL, 0, NULL, NULL, eckey);
|
||||
ECDSA_verify(0, NULL, 0, NULL, 0, eckey);
|
||||
EC_KEY_free(eckey);
|
||||
ECDSA_SIG *sig_openssl;
|
||||
sig_openssl = ECDSA_SIG_new();
|
||||
(void)sig_openssl->r;
|
||||
ECDSA_SIG_free(sig_openssl);
|
||||
]])],[has_openssl_ec=yes],[has_openssl_ec=no])
|
||||
AC_MSG_RESULT([$has_openssl_ec])
|
||||
fi
|
||||
|
|
30
configure.ac
30
configure.ac
|
@ -104,6 +104,11 @@ AC_ARG_ENABLE(experimental,
|
|||
[use_experimental=$enableval],
|
||||
[use_experimental=no])
|
||||
|
||||
AC_ARG_ENABLE(exhaustive_tests,
|
||||
AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]),
|
||||
[use_exhaustive_tests=$enableval],
|
||||
[use_exhaustive_tests=yes])
|
||||
|
||||
AC_ARG_ENABLE(endomorphism,
|
||||
AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]),
|
||||
[use_endomorphism=$enableval],
|
||||
|
@ -119,11 +124,6 @@ AC_ARG_ENABLE(module_ecdh,
|
|||
[enable_module_ecdh=$enableval],
|
||||
[enable_module_ecdh=no])
|
||||
|
||||
AC_ARG_ENABLE(module_schnorr,
|
||||
AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (experimental)]),
|
||||
[enable_module_schnorr=$enableval],
|
||||
[enable_module_schnorr=no])
|
||||
|
||||
AC_ARG_ENABLE(module_recovery,
|
||||
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]),
|
||||
[enable_module_recovery=$enableval],
|
||||
|
@ -381,9 +381,6 @@ fi
|
|||
if test x"$use_jni" != x"no"; then
|
||||
AX_JNI_INCLUDE_DIR
|
||||
have_jni_dependencies=yes
|
||||
if test x"$enable_module_schnorr" = x"no"; then
|
||||
have_jni_dependencies=no
|
||||
fi
|
||||
if test x"$enable_module_ecdh" = x"no"; then
|
||||
have_jni_dependencies=no
|
||||
fi
|
||||
|
@ -392,7 +389,7 @@ if test x"$use_jni" != x"no"; then
|
|||
fi
|
||||
if test "x$have_jni_dependencies" = "xno"; then
|
||||
if test x"$use_jni" = x"yes"; then
|
||||
AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and Schnorr and try again.])
|
||||
AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and try again.])
|
||||
fi
|
||||
AC_MSG_WARN([jni headers/dependencies not found. jni support disabled])
|
||||
use_jni=no
|
||||
|
@ -413,7 +410,7 @@ if test x"$use_endomorphism" = x"yes"; then
|
|||
AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization])
|
||||
fi
|
||||
|
||||
if test x"$use_ecmult_static_precomputation" = x"yes"; then
|
||||
if test x"$set_precomp" = x"yes"; then
|
||||
AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table])
|
||||
fi
|
||||
|
||||
|
@ -421,10 +418,6 @@ if test x"$enable_module_ecdh" = x"yes"; then
|
|||
AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module])
|
||||
fi
|
||||
|
||||
if test x"$enable_module_schnorr" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_SCHNORR, 1, [Define this symbol to enable the Schnorr signature module])
|
||||
fi
|
||||
|
||||
if test x"$enable_module_recovery" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])
|
||||
fi
|
||||
|
@ -442,7 +435,6 @@ AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
|
|||
AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
|
||||
AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
|
||||
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
|
||||
AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr])
|
||||
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
|
||||
AC_MSG_NOTICE([Using jni: $use_jni])
|
||||
|
||||
|
@ -451,12 +443,8 @@ if test x"$enable_experimental" = x"yes"; then
|
|||
AC_MSG_NOTICE([WARNING: experimental build])
|
||||
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
|
||||
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
|
||||
AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr])
|
||||
AC_MSG_NOTICE([******])
|
||||
else
|
||||
if test x"$enable_module_schnorr" = x"yes"; then
|
||||
AC_MSG_ERROR([Schnorr signature module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_ecdh" = x"yes"; then
|
||||
AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
|
@ -473,10 +461,10 @@ AC_SUBST(SECP_LIBS)
|
|||
AC_SUBST(SECP_TEST_LIBS)
|
||||
AC_SUBST(SECP_TEST_INCLUDES)
|
||||
AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
|
||||
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"])
|
||||
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
|
||||
AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$use_ecmult_static_precomputation" = x"yes"])
|
||||
AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
|
||||
AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"])
|
||||
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
|
||||
|
|
|
@ -47,11 +47,8 @@ typedef struct secp256k1_context_struct secp256k1_context;
|
|||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage or transmission, use
|
||||
* secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse.
|
||||
*
|
||||
* Furthermore, it is guaranteed that identical public keys (ignoring
|
||||
* compression) will have identical representation, so they can be memcmp'ed.
|
||||
* If you need to convert to a format suitable for storage, transmission, or
|
||||
* comparison, use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[64];
|
||||
|
@ -62,12 +59,9 @@ typedef struct {
|
|||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage or transmission, use
|
||||
* the secp256k1_ecdsa_signature_serialize_* and
|
||||
* If you need to convert to a format suitable for storage, transmission, or
|
||||
* comparison, use the secp256k1_ecdsa_signature_serialize_* and
|
||||
* secp256k1_ecdsa_signature_serialize_* functions.
|
||||
*
|
||||
* Furthermore, it is guaranteed to identical signatures will have identical
|
||||
* representation, so they can be memcmp'ed.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[64];
|
||||
|
|
|
@ -1,173 +0,0 @@
|
|||
#ifndef _SECP256K1_SCHNORR_
|
||||
# define _SECP256K1_SCHNORR_
|
||||
|
||||
# include "secp256k1.h"
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
/** Create a signature using a custom EC-Schnorr-SHA256 construction. It
|
||||
* produces non-malleable 64-byte signatures which support public key recovery
|
||||
* batch validation, and multiparty signing.
|
||||
* Returns: 1: signature created
|
||||
* 0: the nonce generation function failed, or the private key was
|
||||
* invalid.
|
||||
* Args: ctx: pointer to a context object, initialized for signing
|
||||
* (cannot be NULL)
|
||||
* Out: sig64: pointer to a 64-byte array where the signature will be
|
||||
* placed (cannot be NULL)
|
||||
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
|
||||
* seckey: pointer to a 32-byte secret key (cannot be NULL)
|
||||
* noncefp:pointer to a nonce generation function. If NULL,
|
||||
* secp256k1_nonce_function_default is used
|
||||
* ndata: pointer to arbitrary data used by the nonce generation
|
||||
* function (can be NULL)
|
||||
*/
|
||||
SECP256K1_API int secp256k1_schnorr_sign(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *sig64,
|
||||
const unsigned char *msg32,
|
||||
const unsigned char *seckey,
|
||||
secp256k1_nonce_function noncefp,
|
||||
const void *ndata
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Verify a signature created by secp256k1_schnorr_sign.
|
||||
* Returns: 1: correct signature
|
||||
* 0: incorrect signature
|
||||
* Args: ctx: a secp256k1 context object, initialized for verification.
|
||||
* In: sig64: the 64-byte signature being verified (cannot be NULL)
|
||||
* msg32: the 32-byte message hash being verified (cannot be NULL)
|
||||
* pubkey: the public key to verify with (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify(
|
||||
const secp256k1_context* ctx,
|
||||
const unsigned char *sig64,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Recover an EC public key from a Schnorr signature created using
|
||||
* secp256k1_schnorr_sign.
|
||||
* Returns: 1: public key successfully recovered (which guarantees a correct
|
||||
* signature).
|
||||
* 0: otherwise.
|
||||
* Args: ctx: pointer to a context object, initialized for
|
||||
* verification (cannot be NULL)
|
||||
* Out: pubkey: pointer to a pubkey to set to the recovered public key
|
||||
* (cannot be NULL).
|
||||
* In: sig64: signature as 64 byte array (cannot be NULL)
|
||||
* msg32: the 32-byte message hash assumed to be signed (cannot
|
||||
* be NULL)
|
||||
*/
|
||||
SECP256K1_API int secp256k1_schnorr_recover(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const unsigned char *sig64,
|
||||
const unsigned char *msg32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Generate a nonce pair deterministically for use with
|
||||
* secp256k1_schnorr_partial_sign.
|
||||
* Returns: 1: valid nonce pair was generated.
|
||||
* 0: otherwise (nonce generation function failed)
|
||||
* Args: ctx: pointer to a context object, initialized for signing
|
||||
* (cannot be NULL)
|
||||
* Out: pubnonce: public side of the nonce (cannot be NULL)
|
||||
* privnonce32: private side of the nonce (32 byte) (cannot be NULL)
|
||||
* In: msg32: the 32-byte message hash assumed to be signed (cannot
|
||||
* be NULL)
|
||||
* sec32: the 32-byte private key (cannot be NULL)
|
||||
* noncefp: pointer to a nonce generation function. If NULL,
|
||||
* secp256k1_nonce_function_default is used
|
||||
* noncedata: pointer to arbitrary data used by the nonce generation
|
||||
* function (can be NULL)
|
||||
*
|
||||
* Do not use the output as a private/public key pair for signing/validation.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_schnorr_generate_nonce_pair(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pubkey *pubnonce,
|
||||
unsigned char *privnonce32,
|
||||
const unsigned char *msg32,
|
||||
const unsigned char *sec32,
|
||||
secp256k1_nonce_function noncefp,
|
||||
const void* noncedata
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Produce a partial Schnorr signature, which can be combined using
|
||||
* secp256k1_schnorr_partial_combine, to end up with a full signature that is
|
||||
* verifiable using secp256k1_schnorr_verify.
|
||||
* Returns: 1: signature created successfully.
|
||||
* 0: no valid signature exists with this combination of keys, nonces
|
||||
* and message (chance around 1 in 2^128)
|
||||
* -1: invalid private key, nonce, or public nonces.
|
||||
* Args: ctx: pointer to context object, initialized for signing (cannot
|
||||
* be NULL)
|
||||
* Out: sig64: pointer to 64-byte array to put partial signature in
|
||||
* In: msg32: pointer to 32-byte message to sign
|
||||
* sec32: pointer to 32-byte private key
|
||||
* pubnonce_others: pointer to pubkey containing the sum of the other's
|
||||
* nonces (see secp256k1_ec_pubkey_combine)
|
||||
* secnonce32: pointer to 32-byte array containing our nonce
|
||||
*
|
||||
* The intended procedure for creating a multiparty signature is:
|
||||
* - Each signer S[i] with private key x[i] and public key Q[i] runs
|
||||
* secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of
|
||||
* private/public nonces.
|
||||
* - All signers communicate their public nonces to each other (revealing your
|
||||
* private nonce can lead to discovery of your private key, so it should be
|
||||
* considered secret).
|
||||
* - All signers combine all the public nonces they received (excluding their
|
||||
* own) using secp256k1_ec_pubkey_combine to obtain an
|
||||
* Rall[i] = sum(R[0..i-1,i+1..n]).
|
||||
* - All signers produce a partial signature using
|
||||
* secp256k1_schnorr_partial_sign, passing in their own private key x[i],
|
||||
* their own private nonce k[i], and the sum of the others' public nonces
|
||||
* Rall[i].
|
||||
* - All signers communicate their partial signatures to each other.
|
||||
* - Someone combines all partial signatures using
|
||||
* secp256k1_schnorr_partial_combine, to obtain a full signature.
|
||||
* - The resulting signature is validatable using secp256k1_schnorr_verify, with
|
||||
* public key equal to the result of secp256k1_ec_pubkey_combine of the
|
||||
* signers' public keys (sum(Q[0..n])).
|
||||
*
|
||||
* Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine
|
||||
* function take their arguments in any order, and it is possible to
|
||||
* pre-combine several inputs already with one call, and add more inputs later
|
||||
* by calling the function again (they are commutative and associative).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_sign(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *sig64,
|
||||
const unsigned char *msg32,
|
||||
const unsigned char *sec32,
|
||||
const secp256k1_pubkey *pubnonce_others,
|
||||
const unsigned char *secnonce32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
|
||||
|
||||
/** Combine multiple Schnorr partial signatures.
|
||||
* Returns: 1: the passed signatures were successfully combined.
|
||||
* 0: the resulting signature is not valid (chance of 1 in 2^256)
|
||||
* -1: some inputs were invalid, or the signatures were not created
|
||||
* using the same set of nonces
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: sig64: pointer to a 64-byte array to place the combined signature
|
||||
* (cannot be NULL)
|
||||
* In: sig64sin: pointer to an array of n pointers to 64-byte input
|
||||
* signatures
|
||||
* n: the number of signatures to combine (at least 1)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_combine(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *sig64,
|
||||
const unsigned char * const * sig64sin,
|
||||
size_t n
|
||||
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
|
@ -203,7 +203,9 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const
|
|||
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) {
|
||||
unsigned char c[32];
|
||||
secp256k1_scalar sn, u1, u2;
|
||||
#if !defined(EXHAUSTIVE_TEST_ORDER)
|
||||
secp256k1_fe xr;
|
||||
#endif
|
||||
secp256k1_gej pubkeyj;
|
||||
secp256k1_gej pr;
|
||||
|
||||
|
@ -219,6 +221,21 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const
|
|||
if (secp256k1_gej_is_infinity(&pr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
{
|
||||
secp256k1_scalar computed_r;
|
||||
int overflow = 0;
|
||||
secp256k1_ge pr_ge;
|
||||
secp256k1_ge_set_gej(&pr_ge, &pr);
|
||||
secp256k1_fe_normalize(&pr_ge.x);
|
||||
|
||||
secp256k1_fe_get_b32(c, &pr_ge.x);
|
||||
secp256k1_scalar_set_b32(&computed_r, c, &overflow);
|
||||
/* we fully expect overflow */
|
||||
return secp256k1_scalar_eq(sigr, &computed_r);
|
||||
}
|
||||
#else
|
||||
secp256k1_scalar_get_b32(c, sigr);
|
||||
secp256k1_fe_set_b32(&xr, c);
|
||||
|
||||
|
@ -252,6 +269,7 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const
|
|||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) {
|
||||
|
|
|
@ -78,7 +78,7 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
|
|||
/* Negative numbers will be negated to keep their bit representation below the maximum width */
|
||||
flip = secp256k1_scalar_is_high(&s);
|
||||
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
|
||||
bit = flip ^ (s.d[0] & 1);
|
||||
bit = flip ^ !secp256k1_scalar_is_even(&s);
|
||||
/* We check for negative one, since adding 2 to it will cause an overflow */
|
||||
secp256k1_scalar_negate(&neg_s, &s);
|
||||
not_neg_one = !secp256k1_scalar_is_one(&neg_s);
|
||||
|
|
|
@ -77,7 +77,7 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx
|
|||
secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL);
|
||||
}
|
||||
}
|
||||
secp256k1_ge_set_all_gej_var(1024, prec, precj, cb);
|
||||
secp256k1_ge_set_all_gej_var(prec, precj, 1024, cb);
|
||||
}
|
||||
for (j = 0; j < 64; j++) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
|
|
|
@ -7,15 +7,29 @@
|
|||
#ifndef _SECP256K1_ECMULT_IMPL_H_
|
||||
#define _SECP256K1_ECMULT_IMPL_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
#include "ecmult.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
/* We need to lower these values for exhaustive tests because
|
||||
* the tables cannot have infinities in them (this breaks the
|
||||
* affine-isomorphism stuff which tracks z-ratios) */
|
||||
# if EXHAUSTIVE_TEST_ORDER > 128
|
||||
# define WINDOW_A 5
|
||||
# define WINDOW_G 8
|
||||
# elif EXHAUSTIVE_TEST_ORDER > 8
|
||||
# define WINDOW_A 4
|
||||
# define WINDOW_G 4
|
||||
# else
|
||||
# define WINDOW_A 2
|
||||
# define WINDOW_G 2
|
||||
# endif
|
||||
#else
|
||||
/* optimal for 128-bit and 256-bit exponents. */
|
||||
#define WINDOW_A 5
|
||||
|
||||
/** larger numbers may result in slightly better performance, at the cost of
|
||||
exponentially larger precomputed tables. */
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
|
@ -25,6 +39,7 @@
|
|||
/** One table for window size 16: 1.375 MiB. */
|
||||
#define WINDOW_G 16
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** The number of entries a table with precomputed multiples needs to have. */
|
||||
#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2))
|
||||
|
@ -103,7 +118,7 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge
|
|||
/* Compute the odd multiples in Jacobian form. */
|
||||
secp256k1_ecmult_odd_multiples_table(n, prej, zr, a);
|
||||
/* Convert them in batch to affine coordinates. */
|
||||
secp256k1_ge_set_table_gej_var(n, prea, prej, zr);
|
||||
secp256k1_ge_set_table_gej_var(prea, prej, zr, n);
|
||||
/* Convert them to compact storage form. */
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_ge_to_storage(&pre[i], &prea[i]);
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#error "Please select field implementation"
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
|
||||
/** Normalize a field element. */
|
||||
static void secp256k1_fe_normalize(secp256k1_fe *r);
|
||||
|
||||
|
@ -50,6 +52,9 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r);
|
|||
/** Set a field element equal to a small integer. Resulting field element is normalized. */
|
||||
static void secp256k1_fe_set_int(secp256k1_fe *r, int a);
|
||||
|
||||
/** Sets a field element equal to zero, initializing all fields. */
|
||||
static void secp256k1_fe_clear(secp256k1_fe *a);
|
||||
|
||||
/** Verify whether a field element is zero. Requires the input to be normalized. */
|
||||
static int secp256k1_fe_is_zero(const secp256k1_fe *a);
|
||||
|
||||
|
@ -110,7 +115,7 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a);
|
|||
/** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be
|
||||
* at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and
|
||||
* outputs must not overlap in memory. */
|
||||
static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a);
|
||||
static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len);
|
||||
|
||||
/** Convert a field element to the storage type. */
|
||||
static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
|
||||
|
|
|
@ -260,7 +260,7 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len) {
|
||||
secp256k1_fe u;
|
||||
size_t i;
|
||||
if (len < 1) {
|
||||
|
|
|
@ -65,12 +65,12 @@ static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a);
|
|||
static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a);
|
||||
|
||||
/** Set a batch of group elements equal to the inputs given in jacobian coordinates */
|
||||
static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb);
|
||||
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb);
|
||||
|
||||
/** Set a batch of group elements equal to the inputs given in jacobian
|
||||
* coordinates (with known z-ratios). zr must contain the known z-ratios such
|
||||
* that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */
|
||||
static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr);
|
||||
static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len);
|
||||
|
||||
/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to
|
||||
* the same global z "denominator". zr must contain the known z-ratios such
|
||||
|
|
|
@ -11,6 +11,53 @@
|
|||
#include "field.h"
|
||||
#include "group.h"
|
||||
|
||||
/* These points can be generated in sage as follows:
|
||||
*
|
||||
* 0. Setup a worksheet with the following parameters.
|
||||
* b = 4 # whatever CURVE_B will be set to
|
||||
* F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
|
||||
* C = EllipticCurve ([F (0), F (b)])
|
||||
*
|
||||
* 1. Determine all the small orders available to you. (If there are
|
||||
* no satisfactory ones, go back and change b.)
|
||||
* print C.order().factor(limit=1000)
|
||||
*
|
||||
* 2. Choose an order as one of the prime factors listed in the above step.
|
||||
* (You can also multiply some to get a composite order, though the
|
||||
* tests will crash trying to invert scalars during signing.) We take a
|
||||
* random point and scale it to drop its order to the desired value.
|
||||
* There is some probability this won't work; just try again.
|
||||
* order = 199
|
||||
* P = C.random_point()
|
||||
* P = (int(P.order()) / int(order)) * P
|
||||
* assert(P.order() == order)
|
||||
*
|
||||
* 3. Print the values. You'll need to use a vim macro or something to
|
||||
* split the hex output into 4-byte chunks.
|
||||
* print "%x %x" % P.xy()
|
||||
*/
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
# if EXHAUSTIVE_TEST_ORDER == 199
|
||||
const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
|
||||
0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069,
|
||||
0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18,
|
||||
0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868,
|
||||
0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED
|
||||
);
|
||||
|
||||
const int CURVE_B = 4;
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 13
|
||||
const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
|
||||
0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0,
|
||||
0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15,
|
||||
0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e,
|
||||
0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac
|
||||
);
|
||||
const int CURVE_B = 2;
|
||||
# else
|
||||
# error No known generator for the specified exhaustive test group order.
|
||||
# endif
|
||||
#else
|
||||
/** Generator for secp256k1, value 'g' defined in
|
||||
* "Standards for Efficient Cryptography" (SEC2) 2.7.1.
|
||||
*/
|
||||
|
@ -21,8 +68,11 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
|
|||
0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL
|
||||
);
|
||||
|
||||
const int CURVE_B = 7;
|
||||
#endif
|
||||
|
||||
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
|
||||
secp256k1_fe zi2;
|
||||
secp256k1_fe zi2;
|
||||
secp256k1_fe zi3;
|
||||
secp256k1_fe_sqr(&zi2, zi);
|
||||
secp256k1_fe_mul(&zi3, &zi2, zi);
|
||||
|
@ -76,7 +126,7 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
|
|||
r->y = a->y;
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb) {
|
||||
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb) {
|
||||
secp256k1_fe *az;
|
||||
secp256k1_fe *azi;
|
||||
size_t i;
|
||||
|
@ -89,7 +139,7 @@ static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp
|
|||
}
|
||||
|
||||
azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count);
|
||||
secp256k1_fe_inv_all_var(count, azi, az);
|
||||
secp256k1_fe_inv_all_var(azi, az, count);
|
||||
free(az);
|
||||
|
||||
count = 0;
|
||||
|
@ -102,7 +152,7 @@ static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp
|
|||
free(azi);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr) {
|
||||
static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len) {
|
||||
size_t i = len - 1;
|
||||
secp256k1_fe zi;
|
||||
|
||||
|
@ -145,9 +195,15 @@ static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp
|
|||
|
||||
static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
|
||||
r->infinity = 1;
|
||||
secp256k1_fe_set_int(&r->x, 0);
|
||||
secp256k1_fe_set_int(&r->y, 0);
|
||||
secp256k1_fe_set_int(&r->z, 0);
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
secp256k1_fe_clear(&r->z);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
|
||||
r->infinity = 1;
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_clear(secp256k1_gej *r) {
|
||||
|
@ -169,7 +225,7 @@ static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) {
|
|||
secp256k1_fe_sqr(&x2, x);
|
||||
secp256k1_fe_mul(&x3, x, &x2);
|
||||
r->infinity = 0;
|
||||
secp256k1_fe_set_int(&c, 7);
|
||||
secp256k1_fe_set_int(&c, CURVE_B);
|
||||
secp256k1_fe_add(&c, &x3);
|
||||
return secp256k1_fe_sqrt(&r->y, &c);
|
||||
}
|
||||
|
@ -228,7 +284,7 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) {
|
|||
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
|
||||
secp256k1_fe_sqr(&z2, &a->z);
|
||||
secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2);
|
||||
secp256k1_fe_mul_int(&z6, 7);
|
||||
secp256k1_fe_mul_int(&z6, CURVE_B);
|
||||
secp256k1_fe_add(&x3, &z6);
|
||||
secp256k1_fe_normalize_weak(&x3);
|
||||
return secp256k1_fe_equal_var(&y2, &x3);
|
||||
|
@ -242,7 +298,7 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
|
|||
/* y^2 = x^3 + 7 */
|
||||
secp256k1_fe_sqr(&y2, &a->y);
|
||||
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
|
||||
secp256k1_fe_set_int(&c, 7);
|
||||
secp256k1_fe_set_int(&c, CURVE_B);
|
||||
secp256k1_fe_add(&x3, &c);
|
||||
secp256k1_fe_normalize_weak(&x3);
|
||||
return secp256k1_fe_equal_var(&y2, &x3);
|
||||
|
@ -260,7 +316,7 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
|
|||
/** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
|
||||
* Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
|
||||
* y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
|
||||
*
|
||||
*
|
||||
* Having said this, if this function receives a point on a sextic twist, e.g. by
|
||||
* a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6,
|
||||
* since -6 does have a cube root mod p. For this point, this function will not set
|
||||
|
|
|
@ -32,7 +32,7 @@ import static org.bitcoin.NativeSecp256k1Util.*;
|
|||
* <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>
|
||||
*
|
||||
* <p>To build secp256k1 for use with bitcoinj, run
|
||||
* `./configure --enable-jni --enable-experimental --enable-module-schnorr --enable-module-ecdh`
|
||||
* `./configure --enable-jni --enable-experimental --enable-module-ecdh`
|
||||
* and `make` then copy `.libs/libsecp256k1.so` to your system library path
|
||||
* or point the JVM to the folder containing it with -Djava.library.path
|
||||
* </p>
|
||||
|
@ -417,36 +417,6 @@ public class NativeSecp256k1 {
|
|||
}
|
||||
}
|
||||
|
||||
public static byte[] schnorrSign(byte[] data, byte[] sec) throws AssertFailException {
|
||||
Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null) {
|
||||
byteBuff = ByteBuffer.allocateDirect(32 + 32);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(data);
|
||||
byteBuff.put(sec);
|
||||
|
||||
byte[][] retByteArray;
|
||||
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_schnorr_sign(byteBuff, Secp256k1Context.getContext());
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] sigArr = retByteArray[0];
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||
|
||||
assertEquals(sigArr.length, 64, "Got bad signature length.");
|
||||
|
||||
return retVal == 0 ? new byte[0] : sigArr;
|
||||
}
|
||||
|
||||
private static native long secp256k1_ctx_clone(long context);
|
||||
|
||||
private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
|
||||
|
@ -471,8 +441,6 @@ public class NativeSecp256k1 {
|
|||
|
||||
private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
|
||||
|
||||
private static native byte[][] secp256k1_schnorr_sign(ByteBuffer byteBuff, long context);
|
||||
|
||||
private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
|
||||
|
||||
}
|
||||
|
|
|
@ -167,22 +167,6 @@ public class NativeSecp256k1Test {
|
|||
assertEquals( result, true, "testRandomize");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests signSchnorr() for a valid secretkey
|
||||
*/
|
||||
public static void testSchnorrSign() throws AssertFailException{
|
||||
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.schnorrSign(data, sec);
|
||||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( sigString, "C5E929AA058B982048760422D3B563749B7D0E50C5EBD8CD2FFC23214BD6A2F1B072C13880997EBA847CF20F2F90FCE07C1CA33A890A4127095A351127F8D95F" , "testSchnorrSign");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests signSchnorr() for a valid secretkey
|
||||
*/
|
||||
public static void testCreateECDHSecret() throws AssertFailException{
|
||||
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||
|
@ -216,11 +200,6 @@ public class NativeSecp256k1Test {
|
|||
testSignPos();
|
||||
testSignNeg();
|
||||
|
||||
//Test Schnorr (partial support) //TODO
|
||||
testSchnorrSign();
|
||||
//testSchnorrVerify
|
||||
//testSchnorrRecovery
|
||||
|
||||
//Test privKeyTweakAdd() 1
|
||||
testPrivKeyTweakAdd_1();
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "include/secp256k1.h"
|
||||
#include "include/secp256k1_ecdh.h"
|
||||
#include "include/secp256k1_recovery.h"
|
||||
#include "include/secp256k1_schnorr.h"
|
||||
|
||||
|
||||
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
|
||||
|
@ -333,39 +332,6 @@ SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1p
|
|||
return 0;
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
unsigned char* secKey = (unsigned char*) (data + 32);
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray sigArray, intsByteArray;
|
||||
unsigned char intsarray[1];
|
||||
unsigned char sig[64];
|
||||
|
||||
int ret = secp256k1_schnorr_sign(ctx, sig, data, secKey, NULL, NULL);
|
||||
|
||||
intsarray[0] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
sigArray = (*env)->NewByteArray(env, 64);
|
||||
(*env)->SetByteArrayRegion(env, sigArray, 0, 64, (jbyte*)sig);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 1);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
||||
{
|
||||
|
|
|
@ -104,14 +104,6 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
|
|||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse
|
||||
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_schnorr_sign
|
||||
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ecdh
|
||||
|
|
4
src/modules/recovery/main_impl.h
Normal file → Executable file
4
src/modules/recovery/main_impl.h
Normal file → Executable file
|
@ -138,16 +138,15 @@ int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecd
|
|||
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
|
||||
/* Fail if the secret key is invalid. */
|
||||
if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
|
||||
unsigned char nonce32[32];
|
||||
unsigned int count = 0;
|
||||
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
||||
while (1) {
|
||||
unsigned char nonce32[32];
|
||||
ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
|
||||
if (!ret) {
|
||||
break;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
|
||||
memset(nonce32, 0, 32);
|
||||
if (!secp256k1_scalar_is_zero(&non) && !overflow) {
|
||||
if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) {
|
||||
break;
|
||||
|
@ -155,6 +154,7 @@ int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecd
|
|||
}
|
||||
count++;
|
||||
}
|
||||
memset(nonce32, 0, 32);
|
||||
secp256k1_scalar_clear(&msg);
|
||||
secp256k1_scalar_clear(&non);
|
||||
secp256k1_scalar_clear(&sec);
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
include_HEADERS += include/secp256k1_schnorr.h
|
||||
noinst_HEADERS += src/modules/schnorr/main_impl.h
|
||||
noinst_HEADERS += src/modules/schnorr/schnorr.h
|
||||
noinst_HEADERS += src/modules/schnorr/schnorr_impl.h
|
||||
noinst_HEADERS += src/modules/schnorr/tests_impl.h
|
||||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_schnorr_verify
|
||||
bench_schnorr_verify_SOURCES = src/bench_schnorr_verify.c
|
||||
bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
|
||||
endif
|
|
@ -1,164 +0,0 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2014-2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_SCHNORR_MAIN
|
||||
#define SECP256K1_MODULE_SCHNORR_MAIN
|
||||
|
||||
#include "include/secp256k1_schnorr.h"
|
||||
#include "modules/schnorr/schnorr_impl.h"
|
||||
|
||||
static void secp256k1_schnorr_msghash_sha256(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) {
|
||||
secp256k1_sha256_t sha;
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, r32, 32);
|
||||
secp256k1_sha256_write(&sha, msg32, 32);
|
||||
secp256k1_sha256_finalize(&sha, h32);
|
||||
}
|
||||
|
||||
static const unsigned char secp256k1_schnorr_algo16[17] = "Schnorr+SHA256 ";
|
||||
|
||||
int secp256k1_schnorr_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
|
||||
secp256k1_scalar sec, non;
|
||||
int ret = 0;
|
||||
int overflow = 0;
|
||||
unsigned int count = 0;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(seckey != NULL);
|
||||
if (noncefp == NULL) {
|
||||
noncefp = secp256k1_nonce_function_default;
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_b32(&sec, seckey, NULL);
|
||||
while (1) {
|
||||
unsigned char nonce32[32];
|
||||
ret = noncefp(nonce32, msg32, seckey, secp256k1_schnorr_algo16, (void*)noncedata, count);
|
||||
if (!ret) {
|
||||
break;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
|
||||
memset(nonce32, 0, 32);
|
||||
if (!secp256k1_scalar_is_zero(&non) && !overflow) {
|
||||
if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, NULL, secp256k1_schnorr_msghash_sha256, msg32)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
if (!ret) {
|
||||
memset(sig64, 0, 64);
|
||||
}
|
||||
secp256k1_scalar_clear(&non);
|
||||
secp256k1_scalar_clear(&sec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_schnorr_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_pubkey *pubkey) {
|
||||
secp256k1_ge q;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
secp256k1_pubkey_load(ctx, &q, pubkey);
|
||||
return secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32);
|
||||
}
|
||||
|
||||
int secp256k1_schnorr_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *sig64, const unsigned char *msg32) {
|
||||
secp256k1_ge q;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32)) {
|
||||
secp256k1_pubkey_save(pubkey, &q);
|
||||
return 1;
|
||||
} else {
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int secp256k1_schnorr_generate_nonce_pair(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, unsigned char *privnonce32, const unsigned char *sec32, const unsigned char *msg32, secp256k1_nonce_function noncefp, const void* noncedata) {
|
||||
int count = 0;
|
||||
int ret = 1;
|
||||
secp256k1_gej Qj;
|
||||
secp256k1_ge Q;
|
||||
secp256k1_scalar sec;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(sec32 != NULL);
|
||||
ARG_CHECK(pubnonce != NULL);
|
||||
ARG_CHECK(privnonce32 != NULL);
|
||||
|
||||
if (noncefp == NULL) {
|
||||
noncefp = secp256k1_nonce_function_default;
|
||||
}
|
||||
|
||||
do {
|
||||
int overflow;
|
||||
ret = noncefp(privnonce32, sec32, msg32, secp256k1_schnorr_algo16, (void*)noncedata, count++);
|
||||
if (!ret) {
|
||||
break;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&sec, privnonce32, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&sec)) {
|
||||
continue;
|
||||
}
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sec);
|
||||
secp256k1_ge_set_gej(&Q, &Qj);
|
||||
|
||||
secp256k1_pubkey_save(pubnonce, &Q);
|
||||
break;
|
||||
} while(1);
|
||||
|
||||
secp256k1_scalar_clear(&sec);
|
||||
if (!ret) {
|
||||
memset(pubnonce, 0, sizeof(*pubnonce));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_schnorr_partial_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *sec32, const secp256k1_pubkey *pubnonce_others, const unsigned char *secnonce32) {
|
||||
int overflow = 0;
|
||||
secp256k1_scalar sec, non;
|
||||
secp256k1_ge pubnon;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(sec32 != NULL);
|
||||
ARG_CHECK(secnonce32 != NULL);
|
||||
ARG_CHECK(pubnonce_others != NULL);
|
||||
|
||||
secp256k1_scalar_set_b32(&sec, sec32, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&sec)) {
|
||||
return -1;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&non, secnonce32, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&non)) {
|
||||
return -1;
|
||||
}
|
||||
secp256k1_pubkey_load(ctx, &pubnon, pubnonce_others);
|
||||
return secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, &pubnon, secp256k1_schnorr_msghash_sha256, msg32);
|
||||
}
|
||||
|
||||
int secp256k1_schnorr_partial_combine(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char * const *sig64sin, size_t n) {
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(n >= 1);
|
||||
ARG_CHECK(sig64sin != NULL);
|
||||
return secp256k1_schnorr_sig_combine(sig64, n, sig64sin);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,20 +0,0 @@
|
|||
/***********************************************************************
|
||||
* Copyright (c) 2014-2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php. *
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_SCHNORR_H_
|
||||
#define _SECP256K1_MODULE_SCHNORR_H_
|
||||
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
|
||||
typedef void (*secp256k1_schnorr_msghash)(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32);
|
||||
|
||||
static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32);
|
||||
static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32);
|
||||
static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32);
|
||||
static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins);
|
||||
|
||||
#endif
|
|
@ -1,207 +0,0 @@
|
|||
/***********************************************************************
|
||||
* Copyright (c) 2014-2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php. *
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_SCHNORR_IMPL_H_
|
||||
#define _SECP256K1_SCHNORR_IMPL_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "schnorr.h"
|
||||
#include "num.h"
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
#include "ecmult.h"
|
||||
#include "ecmult_gen.h"
|
||||
|
||||
/**
|
||||
* Custom Schnorr-based signature scheme. They support multiparty signing, public key
|
||||
* recovery and batch validation.
|
||||
*
|
||||
* Rationale for verifying R's y coordinate:
|
||||
* In order to support batch validation and public key recovery, the full R point must
|
||||
* be known to verifiers, rather than just its x coordinate. In order to not risk
|
||||
* being more strict in batch validation than normal validation, validators must be
|
||||
* required to reject signatures with incorrect y coordinate. This is only possible
|
||||
* by including a (relatively slow) field inverse, or a field square root. However,
|
||||
* batch validation offers potentially much higher benefits than this cost.
|
||||
*
|
||||
* Rationale for having an implicit y coordinate oddness:
|
||||
* If we commit to having the full R point known to verifiers, there are two mechanism.
|
||||
* Either include its oddness in the signature, or give it an implicit fixed value.
|
||||
* As the R y coordinate can be flipped by a simple negation of the nonce, we choose the
|
||||
* latter, as it comes with nearly zero impact on signing or validation performance, and
|
||||
* saves a byte in the signature.
|
||||
*
|
||||
* Signing:
|
||||
* Inputs: 32-byte message m, 32-byte scalar key x (!=0), 32-byte scalar nonce k (!=0)
|
||||
*
|
||||
* Compute point R = k * G. Reject nonce if R's y coordinate is odd (or negate nonce).
|
||||
* Compute 32-byte r, the serialization of R's x coordinate.
|
||||
* Compute scalar h = Hash(r || m). Reject nonce if h == 0 or h >= order.
|
||||
* Compute scalar s = k - h * x.
|
||||
* The signature is (r, s).
|
||||
*
|
||||
*
|
||||
* Verification:
|
||||
* Inputs: 32-byte message m, public key point Q, signature: (32-byte r, scalar s)
|
||||
*
|
||||
* Signature is invalid if s >= order.
|
||||
* Signature is invalid if r >= p.
|
||||
* Compute scalar h = Hash(r || m). Signature is invalid if h == 0 or h >= order.
|
||||
* Option 1 (faster for single verification):
|
||||
* Compute point R = h * Q + s * G. Signature is invalid if R is infinity or R's y coordinate is odd.
|
||||
* Signature is valid if the serialization of R's x coordinate equals r.
|
||||
* Option 2 (allows batch validation and pubkey recovery):
|
||||
* Decompress x coordinate r into point R, with odd y coordinate. Fail if R is not on the curve.
|
||||
* Signature is valid if R + h * Q + s * G == 0.
|
||||
*/
|
||||
|
||||
static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32) {
|
||||
secp256k1_gej Rj;
|
||||
secp256k1_ge Ra;
|
||||
unsigned char h32[32];
|
||||
secp256k1_scalar h, s;
|
||||
int overflow;
|
||||
secp256k1_scalar n;
|
||||
|
||||
if (secp256k1_scalar_is_zero(key) || secp256k1_scalar_is_zero(nonce)) {
|
||||
return 0;
|
||||
}
|
||||
n = *nonce;
|
||||
|
||||
secp256k1_ecmult_gen(ctx, &Rj, &n);
|
||||
if (pubnonce != NULL) {
|
||||
secp256k1_gej_add_ge(&Rj, &Rj, pubnonce);
|
||||
}
|
||||
secp256k1_ge_set_gej(&Ra, &Rj);
|
||||
secp256k1_fe_normalize(&Ra.y);
|
||||
if (secp256k1_fe_is_odd(&Ra.y)) {
|
||||
/* R's y coordinate is odd, which is not allowed (see rationale above).
|
||||
Force it to be even by negating the nonce. Note that this even works
|
||||
for multiparty signing, as the R point is known to all participants,
|
||||
which can all decide to flip the sign in unison, resulting in the
|
||||
overall R point to be negated too. */
|
||||
secp256k1_scalar_negate(&n, &n);
|
||||
}
|
||||
secp256k1_fe_normalize(&Ra.x);
|
||||
secp256k1_fe_get_b32(sig64, &Ra.x);
|
||||
hash(h32, sig64, msg32);
|
||||
overflow = 0;
|
||||
secp256k1_scalar_set_b32(&h, h32, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&h)) {
|
||||
secp256k1_scalar_clear(&n);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_mul(&s, &h, key);
|
||||
secp256k1_scalar_negate(&s, &s);
|
||||
secp256k1_scalar_add(&s, &s, &n);
|
||||
secp256k1_scalar_clear(&n);
|
||||
secp256k1_scalar_get_b32(sig64 + 32, &s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) {
|
||||
secp256k1_gej Qj, Rj;
|
||||
secp256k1_ge Ra;
|
||||
secp256k1_fe Rx;
|
||||
secp256k1_scalar h, s;
|
||||
unsigned char hh[32];
|
||||
int overflow;
|
||||
|
||||
if (secp256k1_ge_is_infinity(pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
hash(hh, sig64, msg32);
|
||||
overflow = 0;
|
||||
secp256k1_scalar_set_b32(&h, hh, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&h)) {
|
||||
return 0;
|
||||
}
|
||||
overflow = 0;
|
||||
secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_fe_set_b32(&Rx, sig64)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_set_ge(&Qj, pubkey);
|
||||
secp256k1_ecmult(ctx, &Rj, &Qj, &h, &s);
|
||||
if (secp256k1_gej_is_infinity(&Rj)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej_var(&Ra, &Rj);
|
||||
secp256k1_fe_normalize_var(&Ra.y);
|
||||
if (secp256k1_fe_is_odd(&Ra.y)) {
|
||||
return 0;
|
||||
}
|
||||
return secp256k1_fe_equal_var(&Rx, &Ra.x);
|
||||
}
|
||||
|
||||
static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) {
|
||||
secp256k1_gej Qj, Rj;
|
||||
secp256k1_ge Ra;
|
||||
secp256k1_fe Rx;
|
||||
secp256k1_scalar h, s;
|
||||
unsigned char hh[32];
|
||||
int overflow;
|
||||
|
||||
hash(hh, sig64, msg32);
|
||||
overflow = 0;
|
||||
secp256k1_scalar_set_b32(&h, hh, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&h)) {
|
||||
return 0;
|
||||
}
|
||||
overflow = 0;
|
||||
secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_fe_set_b32(&Rx, sig64)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_ge_set_xo_var(&Ra, &Rx, 0)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_set_ge(&Rj, &Ra);
|
||||
secp256k1_scalar_inverse_var(&h, &h);
|
||||
secp256k1_scalar_negate(&s, &s);
|
||||
secp256k1_scalar_mul(&s, &s, &h);
|
||||
secp256k1_ecmult(ctx, &Qj, &Rj, &h, &s);
|
||||
if (secp256k1_gej_is_infinity(&Qj)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej(pubkey, &Qj);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins) {
|
||||
secp256k1_scalar s = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar si;
|
||||
int overflow;
|
||||
secp256k1_scalar_set_b32(&si, sig64ins[i] + 32, &overflow);
|
||||
if (overflow) {
|
||||
return -1;
|
||||
}
|
||||
if (i) {
|
||||
if (memcmp(sig64ins[i - 1], sig64ins[i], 32) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
secp256k1_scalar_add(&s, &s, &si);
|
||||
}
|
||||
if (secp256k1_scalar_is_zero(&s)) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(sig64, sig64ins[0], 32);
|
||||
secp256k1_scalar_get_b32(sig64 + 32, &s);
|
||||
secp256k1_scalar_clear(&s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,175 +0,0 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2014-2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_SCHNORR_TESTS
|
||||
#define SECP256K1_MODULE_SCHNORR_TESTS
|
||||
|
||||
#include "include/secp256k1_schnorr.h"
|
||||
|
||||
void test_schnorr_end_to_end(void) {
|
||||
unsigned char privkey[32];
|
||||
unsigned char message[32];
|
||||
unsigned char schnorr_signature[64];
|
||||
secp256k1_pubkey pubkey, recpubkey;
|
||||
|
||||
/* Generate a random key and message. */
|
||||
{
|
||||
secp256k1_scalar key;
|
||||
random_scalar_order_test(&key);
|
||||
secp256k1_scalar_get_b32(privkey, &key);
|
||||
secp256k1_rand256_test(message);
|
||||
}
|
||||
|
||||
/* Construct and verify corresponding public key. */
|
||||
CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
|
||||
|
||||
/* Schnorr sign. */
|
||||
CHECK(secp256k1_schnorr_sign(ctx, schnorr_signature, message, privkey, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 1);
|
||||
CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) == 1);
|
||||
CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
|
||||
/* Destroy signature and verify again. */
|
||||
schnorr_signature[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255);
|
||||
CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 0);
|
||||
CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) != 1 ||
|
||||
memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
|
||||
}
|
||||
|
||||
/** Horribly broken hash function. Do not use for anything but tests. */
|
||||
void test_schnorr_hash(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) {
|
||||
int i;
|
||||
for (i = 0; i < 32; i++) {
|
||||
h32[i] = r32[i] ^ msg32[i];
|
||||
}
|
||||
}
|
||||
|
||||
void test_schnorr_sign_verify(void) {
|
||||
unsigned char msg32[32];
|
||||
unsigned char sig64[3][64];
|
||||
secp256k1_gej pubkeyj[3];
|
||||
secp256k1_ge pubkey[3];
|
||||
secp256k1_scalar nonce[3], key[3];
|
||||
int i = 0;
|
||||
int k;
|
||||
|
||||
secp256k1_rand256_test(msg32);
|
||||
|
||||
for (k = 0; k < 3; k++) {
|
||||
random_scalar_order_test(&key[k]);
|
||||
|
||||
do {
|
||||
random_scalar_order_test(&nonce[k]);
|
||||
if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64[k], &key[k], &nonce[k], NULL, &test_schnorr_hash, msg32)) {
|
||||
break;
|
||||
}
|
||||
} while(1);
|
||||
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkeyj[k], &key[k]);
|
||||
secp256k1_ge_set_gej_var(&pubkey[k], &pubkeyj[k]);
|
||||
CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32));
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
int pos = secp256k1_rand_bits(6);
|
||||
int mod = 1 + secp256k1_rand_int(255);
|
||||
sig64[k][pos] ^= mod;
|
||||
CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32) == 0);
|
||||
sig64[k][pos] ^= mod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_schnorr_threshold(void) {
|
||||
unsigned char msg[32];
|
||||
unsigned char sec[5][32];
|
||||
secp256k1_pubkey pub[5];
|
||||
unsigned char nonce[5][32];
|
||||
secp256k1_pubkey pubnonce[5];
|
||||
unsigned char sig[5][64];
|
||||
const unsigned char* sigs[5];
|
||||
unsigned char allsig[64];
|
||||
const secp256k1_pubkey* pubs[5];
|
||||
secp256k1_pubkey allpub;
|
||||
int n, i;
|
||||
int damage;
|
||||
int ret = 0;
|
||||
|
||||
damage = secp256k1_rand_bits(1) ? (1 + secp256k1_rand_int(4)) : 0;
|
||||
secp256k1_rand256_test(msg);
|
||||
n = 2 + secp256k1_rand_int(4);
|
||||
for (i = 0; i < n; i++) {
|
||||
do {
|
||||
secp256k1_rand256_test(sec[i]);
|
||||
} while (!secp256k1_ec_seckey_verify(ctx, sec[i]));
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i]));
|
||||
CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL));
|
||||
pubs[i] = &pub[i];
|
||||
}
|
||||
if (damage == 1) {
|
||||
nonce[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255);
|
||||
} else if (damage == 2) {
|
||||
sec[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255);
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_pubkey allpubnonce;
|
||||
const secp256k1_pubkey *pubnonces[4];
|
||||
int j;
|
||||
for (j = 0; j < i; j++) {
|
||||
pubnonces[j] = &pubnonce[j];
|
||||
}
|
||||
for (j = i + 1; j < n; j++) {
|
||||
pubnonces[j - 1] = &pubnonce[j];
|
||||
}
|
||||
CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1));
|
||||
ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1;
|
||||
sigs[i] = sig[i];
|
||||
}
|
||||
if (damage == 3) {
|
||||
sig[secp256k1_rand_int(n)][secp256k1_rand_bits(6)] ^= 1 + secp256k1_rand_int(255);
|
||||
}
|
||||
ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2;
|
||||
if ((ret & 1) == 0) {
|
||||
ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4;
|
||||
}
|
||||
if (damage == 4) {
|
||||
allsig[secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255);
|
||||
}
|
||||
if ((ret & 7) == 0) {
|
||||
ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8;
|
||||
}
|
||||
CHECK((ret == 0) == (damage == 0));
|
||||
}
|
||||
|
||||
void test_schnorr_recovery(void) {
|
||||
unsigned char msg32[32];
|
||||
unsigned char sig64[64];
|
||||
secp256k1_ge Q;
|
||||
|
||||
secp256k1_rand256_test(msg32);
|
||||
secp256k1_rand256_test(sig64);
|
||||
secp256k1_rand256_test(sig64 + 32);
|
||||
if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1) {
|
||||
CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
void run_schnorr_tests(void) {
|
||||
int i;
|
||||
for (i = 0; i < 32*count; i++) {
|
||||
test_schnorr_end_to_end();
|
||||
}
|
||||
for (i = 0; i < 32 * count; i++) {
|
||||
test_schnorr_sign_verify();
|
||||
}
|
||||
for (i = 0; i < 16 * count; i++) {
|
||||
test_schnorr_recovery();
|
||||
}
|
||||
for (i = 0; i < 10 * count; i++) {
|
||||
test_schnorr_threshold();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -13,7 +13,9 @@
|
|||
#include "libsecp256k1-config.h"
|
||||
#endif
|
||||
|
||||
#if defined(USE_SCALAR_4X64)
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
#include "scalar_low.h"
|
||||
#elif defined(USE_SCALAR_4X64)
|
||||
#include "scalar_4x64.h"
|
||||
#elif defined(USE_SCALAR_8X32)
|
||||
#include "scalar_8x32.h"
|
||||
|
|
|
@ -282,8 +282,8 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
|
|||
"movq 56(%%rsi), %%r14\n"
|
||||
/* Initialize r8,r9,r10 */
|
||||
"movq 0(%%rsi), %%r8\n"
|
||||
"movq $0, %%r9\n"
|
||||
"movq $0, %%r10\n"
|
||||
"xorq %%r9, %%r9\n"
|
||||
"xorq %%r10, %%r10\n"
|
||||
/* (r8,r9) += n0 * c0 */
|
||||
"movq %8, %%rax\n"
|
||||
"mulq %%r11\n"
|
||||
|
@ -291,7 +291,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
|
|||
"adcq %%rdx, %%r9\n"
|
||||
/* extract m0 */
|
||||
"movq %%r8, %q0\n"
|
||||
"movq $0, %%r8\n"
|
||||
"xorq %%r8, %%r8\n"
|
||||
/* (r9,r10) += l1 */
|
||||
"addq 8(%%rsi), %%r9\n"
|
||||
"adcq $0, %%r10\n"
|
||||
|
@ -309,7 +309,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
|
|||
"adcq $0, %%r8\n"
|
||||
/* extract m1 */
|
||||
"movq %%r9, %q1\n"
|
||||
"movq $0, %%r9\n"
|
||||
"xorq %%r9, %%r9\n"
|
||||
/* (r10,r8,r9) += l2 */
|
||||
"addq 16(%%rsi), %%r10\n"
|
||||
"adcq $0, %%r8\n"
|
||||
|
@ -332,7 +332,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
|
|||
"adcq $0, %%r9\n"
|
||||
/* extract m2 */
|
||||
"movq %%r10, %q2\n"
|
||||
"movq $0, %%r10\n"
|
||||
"xorq %%r10, %%r10\n"
|
||||
/* (r8,r9,r10) += l3 */
|
||||
"addq 24(%%rsi), %%r8\n"
|
||||
"adcq $0, %%r9\n"
|
||||
|
@ -355,7 +355,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
|
|||
"adcq $0, %%r10\n"
|
||||
/* extract m3 */
|
||||
"movq %%r8, %q3\n"
|
||||
"movq $0, %%r8\n"
|
||||
"xorq %%r8, %%r8\n"
|
||||
/* (r9,r10,r8) += n3 * c1 */
|
||||
"movq %9, %%rax\n"
|
||||
"mulq %%r14\n"
|
||||
|
@ -387,8 +387,8 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
|
|||
"movq %q11, %%r13\n"
|
||||
/* Initialize (r8,r9,r10) */
|
||||
"movq %q5, %%r8\n"
|
||||
"movq $0, %%r9\n"
|
||||
"movq $0, %%r10\n"
|
||||
"xorq %%r9, %%r9\n"
|
||||
"xorq %%r10, %%r10\n"
|
||||
/* (r8,r9) += m4 * c0 */
|
||||
"movq %12, %%rax\n"
|
||||
"mulq %%r11\n"
|
||||
|
@ -396,7 +396,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
|
|||
"adcq %%rdx, %%r9\n"
|
||||
/* extract p0 */
|
||||
"movq %%r8, %q0\n"
|
||||
"movq $0, %%r8\n"
|
||||
"xorq %%r8, %%r8\n"
|
||||
/* (r9,r10) += m1 */
|
||||
"addq %q6, %%r9\n"
|
||||
"adcq $0, %%r10\n"
|
||||
|
@ -414,7 +414,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
|
|||
"adcq $0, %%r8\n"
|
||||
/* extract p1 */
|
||||
"movq %%r9, %q1\n"
|
||||
"movq $0, %%r9\n"
|
||||
"xorq %%r9, %%r9\n"
|
||||
/* (r10,r8,r9) += m2 */
|
||||
"addq %q7, %%r10\n"
|
||||
"adcq $0, %%r8\n"
|
||||
|
@ -472,7 +472,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
|
|||
"movq %%rax, 0(%q6)\n"
|
||||
/* Move to (r8,r9) */
|
||||
"movq %%rdx, %%r8\n"
|
||||
"movq $0, %%r9\n"
|
||||
"xorq %%r9, %%r9\n"
|
||||
/* (r8,r9) += p1 */
|
||||
"addq %q2, %%r8\n"
|
||||
"adcq $0, %%r9\n"
|
||||
|
@ -483,7 +483,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
|
|||
"adcq %%rdx, %%r9\n"
|
||||
/* Extract r1 */
|
||||
"movq %%r8, 8(%q6)\n"
|
||||
"movq $0, %%r8\n"
|
||||
"xorq %%r8, %%r8\n"
|
||||
/* (r9,r8) += p4 */
|
||||
"addq %%r10, %%r9\n"
|
||||
"adcq $0, %%r8\n"
|
||||
|
@ -492,7 +492,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
|
|||
"adcq $0, %%r8\n"
|
||||
/* Extract r2 */
|
||||
"movq %%r9, 16(%q6)\n"
|
||||
"movq $0, %%r9\n"
|
||||
"xorq %%r9, %%r9\n"
|
||||
/* (r8,r9) += p3 */
|
||||
"addq %q4, %%r8\n"
|
||||
"adcq $0, %%r9\n"
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
#include "libsecp256k1-config.h"
|
||||
#endif
|
||||
|
||||
#if defined(USE_SCALAR_4X64)
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
#include "scalar_low_impl.h"
|
||||
#elif defined(USE_SCALAR_4X64)
|
||||
#include "scalar_4x64_impl.h"
|
||||
#elif defined(USE_SCALAR_8X32)
|
||||
#include "scalar_8x32_impl.h"
|
||||
|
@ -31,17 +33,37 @@ static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a
|
|||
|
||||
/** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */
|
||||
static void secp256k1_scalar_order_get_num(secp256k1_num *r) {
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
static const unsigned char order[32] = {
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,EXHAUSTIVE_TEST_ORDER
|
||||
};
|
||||
#else
|
||||
static const unsigned char order[32] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
|
||||
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
|
||||
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41
|
||||
};
|
||||
#endif
|
||||
secp256k1_num_set_bin(r, order, 32);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) {
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
int i;
|
||||
*r = 0;
|
||||
for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++)
|
||||
if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1)
|
||||
*r = i;
|
||||
/* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus
|
||||
* have a composite group order; fix it in exhaustive_tests.c). */
|
||||
VERIFY_CHECK(*r != 0);
|
||||
}
|
||||
#else
|
||||
secp256k1_scalar *t;
|
||||
int i;
|
||||
/* First compute x ^ (2^N - 1) for some values of N. */
|
||||
|
@ -233,9 +255,9 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar
|
|||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
|
||||
/* d[0] is present and is the lowest word for all representations */
|
||||
return !(a->d[0] & 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) {
|
||||
#if defined(USE_SCALAR_INV_BUILTIN)
|
||||
|
@ -259,6 +281,18 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc
|
|||
}
|
||||
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
/**
|
||||
* Find k1 and k2 given k, such that k1 + k2 * lambda == k mod n; unlike in the
|
||||
* full case we don't bother making k1 and k2 be small, we just want them to be
|
||||
* nontrivial to get full test coverage for the exhaustive tests. We therefore
|
||||
* (arbitrarily) set k2 = k + 5 and k1 = k - k2 * lambda.
|
||||
*/
|
||||
static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
|
||||
*r2 = (*a + 5) % EXHAUSTIVE_TEST_ORDER;
|
||||
*r1 = (*a + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER;
|
||||
}
|
||||
#else
|
||||
/**
|
||||
* The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where
|
||||
* lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a,
|
||||
|
@ -331,5 +365,6 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar
|
|||
secp256k1_scalar_add(r1, r1, a);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
15
src/scalar_low.h
Normal file
15
src/scalar_low.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2015 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_SCALAR_REPR_
|
||||
#define _SECP256K1_SCALAR_REPR_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** A scalar modulo the group order of the secp256k1 curve. */
|
||||
typedef uint32_t secp256k1_scalar;
|
||||
|
||||
#endif
|
114
src/scalar_low_impl.h
Normal file
114
src/scalar_low_impl.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2015 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_
|
||||
#define _SECP256K1_SCALAR_REPR_IMPL_H_
|
||||
|
||||
#include "scalar.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
|
||||
return !(*a & 1);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; }
|
||||
SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; }
|
||||
|
||||
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
|
||||
if (offset < 32)
|
||||
return ((*a >> offset) & ((((uint32_t)1) << count) - 1));
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
|
||||
return secp256k1_scalar_get_bits(a, offset, count);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; }
|
||||
|
||||
static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
|
||||
*r = (*a + *b) % EXHAUSTIVE_TEST_ORDER;
|
||||
return *r < *b;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
|
||||
if (flag && bit < 32)
|
||||
*r += (1 << bit);
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
|
||||
const int base = 0x100 % EXHAUSTIVE_TEST_ORDER;
|
||||
int i;
|
||||
*r = 0;
|
||||
for (i = 0; i < 32; i++) {
|
||||
*r = ((*r * base) + b32[i]) % EXHAUSTIVE_TEST_ORDER;
|
||||
}
|
||||
/* just deny overflow, it basically always happens */
|
||||
if (overflow) *overflow = 0;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
|
||||
memset(bin, 0, 32);
|
||||
bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
|
||||
return *a == 0;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
|
||||
if (*a == 0) {
|
||||
*r = 0;
|
||||
} else {
|
||||
*r = EXHAUSTIVE_TEST_ORDER - *a;
|
||||
}
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
|
||||
return *a == 1;
|
||||
}
|
||||
|
||||
static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
|
||||
return *a > EXHAUSTIVE_TEST_ORDER / 2;
|
||||
}
|
||||
|
||||
static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
|
||||
if (flag) secp256k1_scalar_negate(r, r);
|
||||
return flag ? -1 : 1;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
|
||||
*r = (*a * *b) % EXHAUSTIVE_TEST_ORDER;
|
||||
}
|
||||
|
||||
static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
|
||||
int ret;
|
||||
VERIFY_CHECK(n > 0);
|
||||
VERIFY_CHECK(n < 16);
|
||||
ret = *r & ((1 << n) - 1);
|
||||
*r >>= n;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {
|
||||
*r = (*a * *a) % EXHAUSTIVE_TEST_ORDER;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
|
||||
*r1 = *a;
|
||||
*r2 = 0;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {
|
||||
return *a == *b;
|
||||
}
|
||||
|
||||
#endif
|
4
src/secp256k1.c
Normal file → Executable file
4
src/secp256k1.c
Normal file → Executable file
|
@ -359,16 +359,15 @@ int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature
|
|||
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
|
||||
/* Fail if the secret key is invalid. */
|
||||
if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
|
||||
unsigned char nonce32[32];
|
||||
unsigned int count = 0;
|
||||
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
||||
while (1) {
|
||||
unsigned char nonce32[32];
|
||||
ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
|
||||
if (!ret) {
|
||||
break;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
|
||||
memset(nonce32, 0, 32);
|
||||
if (!overflow && !secp256k1_scalar_is_zero(&non)) {
|
||||
if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) {
|
||||
break;
|
||||
|
@ -376,6 +375,7 @@ int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature
|
|||
}
|
||||
count++;
|
||||
}
|
||||
memset(nonce32, 0, 32);
|
||||
secp256k1_scalar_clear(&msg);
|
||||
secp256k1_scalar_clear(&non);
|
||||
secp256k1_scalar_clear(&sec);
|
||||
|
|
20
src/tests.c
20
src/tests.c
|
@ -520,7 +520,7 @@ void test_num_mod(void) {
|
|||
secp256k1_num order, n;
|
||||
|
||||
/* check that 0 mod anything is 0 */
|
||||
random_scalar_order_test(&s);
|
||||
random_scalar_order_test(&s);
|
||||
secp256k1_scalar_get_num(&order, &s);
|
||||
secp256k1_scalar_set_int(&s, 0);
|
||||
secp256k1_scalar_get_num(&n, &s);
|
||||
|
@ -535,7 +535,7 @@ void test_num_mod(void) {
|
|||
CHECK(secp256k1_num_is_zero(&n));
|
||||
|
||||
/* check that increasing the number past 2^256 does not break this */
|
||||
random_scalar_order_test(&s);
|
||||
random_scalar_order_test(&s);
|
||||
secp256k1_scalar_get_num(&n, &s);
|
||||
/* multiply by 2^8, which'll test this case with high probability */
|
||||
for (i = 0; i < 8; ++i) {
|
||||
|
@ -568,7 +568,7 @@ void test_num_jacobi(void) {
|
|||
/* we first need a scalar which is not a multiple of 5 */
|
||||
do {
|
||||
secp256k1_num fiven;
|
||||
random_scalar_order_test(&sqr);
|
||||
random_scalar_order_test(&sqr);
|
||||
secp256k1_scalar_get_num(&fiven, &five);
|
||||
secp256k1_scalar_get_num(&n, &sqr);
|
||||
secp256k1_num_mod(&n, &fiven);
|
||||
|
@ -587,7 +587,7 @@ void test_num_jacobi(void) {
|
|||
|
||||
/** test with secp group order as order */
|
||||
secp256k1_scalar_order_get_num(&order);
|
||||
random_scalar_order_test(&sqr);
|
||||
random_scalar_order_test(&sqr);
|
||||
secp256k1_scalar_sqr(&sqr, &sqr);
|
||||
/* test residue */
|
||||
secp256k1_scalar_get_num(&n, &sqr);
|
||||
|
@ -1733,18 +1733,18 @@ void run_field_inv_all_var(void) {
|
|||
secp256k1_fe x[16], xi[16], xii[16];
|
||||
int i;
|
||||
/* Check it's safe to call for 0 elements */
|
||||
secp256k1_fe_inv_all_var(0, xi, x);
|
||||
secp256k1_fe_inv_all_var(xi, x, 0);
|
||||
for (i = 0; i < count; i++) {
|
||||
size_t j;
|
||||
size_t len = secp256k1_rand_int(15) + 1;
|
||||
for (j = 0; j < len; j++) {
|
||||
random_fe_non_zero(&x[j]);
|
||||
}
|
||||
secp256k1_fe_inv_all_var(len, xi, x);
|
||||
secp256k1_fe_inv_all_var(xi, x, len);
|
||||
for (j = 0; j < len; j++) {
|
||||
CHECK(check_fe_inverse(&x[j], &xi[j]));
|
||||
}
|
||||
secp256k1_fe_inv_all_var(len, xii, xi);
|
||||
secp256k1_fe_inv_all_var(xii, xi, len);
|
||||
for (j = 0; j < len; j++) {
|
||||
CHECK(check_fe_equal(&x[j], &xii[j]));
|
||||
}
|
||||
|
@ -1930,7 +1930,7 @@ void test_ge(void) {
|
|||
zs[i] = gej[i].z;
|
||||
}
|
||||
}
|
||||
secp256k1_fe_inv_all_var(4 * runs + 1, zinv, zs);
|
||||
secp256k1_fe_inv_all_var(zinv, zs, 4 * runs + 1);
|
||||
free(zs);
|
||||
}
|
||||
|
||||
|
@ -2050,8 +2050,8 @@ void test_ge(void) {
|
|||
secp256k1_fe_mul(&zr[i + 1], &zinv[i], &gej[i + 1].z);
|
||||
}
|
||||
}
|
||||
secp256k1_ge_set_table_gej_var(4 * runs + 1, ge_set_table, gej, zr);
|
||||
secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej, &ctx->error_callback);
|
||||
secp256k1_ge_set_table_gej_var(ge_set_table, gej, zr, 4 * runs + 1);
|
||||
secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1, &ctx->error_callback);
|
||||
for (i = 0; i < 4 * runs + 1; i++) {
|
||||
secp256k1_fe s;
|
||||
random_fe_non_zero(&s);
|
||||
|
|
329
src/tests_exhaustive.c
Normal file
329
src/tests_exhaustive.c
Normal file
|
@ -0,0 +1,329 @@
|
|||
/***********************************************************************
|
||||
* Copyright (c) 2016 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#if defined HAVE_CONFIG_H
|
||||
#include "libsecp256k1-config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#undef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||
|
||||
#ifndef EXHAUSTIVE_TEST_ORDER
|
||||
/* see group_impl.h for allowable values */
|
||||
#define EXHAUSTIVE_TEST_ORDER 13
|
||||
#define EXHAUSTIVE_TEST_LAMBDA 9 /* cube root of 1 mod 13 */
|
||||
#endif
|
||||
|
||||
#include "include/secp256k1.h"
|
||||
#include "group.h"
|
||||
#include "secp256k1.c"
|
||||
#include "testrand_impl.h"
|
||||
|
||||
/** stolen from tests.c */
|
||||
void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
|
||||
CHECK(a->infinity == b->infinity);
|
||||
if (a->infinity) {
|
||||
return;
|
||||
}
|
||||
CHECK(secp256k1_fe_equal_var(&a->x, &b->x));
|
||||
CHECK(secp256k1_fe_equal_var(&a->y, &b->y));
|
||||
}
|
||||
|
||||
void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {
|
||||
secp256k1_fe z2s;
|
||||
secp256k1_fe u1, u2, s1, s2;
|
||||
CHECK(a->infinity == b->infinity);
|
||||
if (a->infinity) {
|
||||
return;
|
||||
}
|
||||
/* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */
|
||||
secp256k1_fe_sqr(&z2s, &b->z);
|
||||
secp256k1_fe_mul(&u1, &a->x, &z2s);
|
||||
u2 = b->x; secp256k1_fe_normalize_weak(&u2);
|
||||
secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z);
|
||||
s2 = b->y; secp256k1_fe_normalize_weak(&s2);
|
||||
CHECK(secp256k1_fe_equal_var(&u1, &u2));
|
||||
CHECK(secp256k1_fe_equal_var(&s1, &s2));
|
||||
}
|
||||
|
||||
void random_fe(secp256k1_fe *x) {
|
||||
unsigned char bin[32];
|
||||
do {
|
||||
secp256k1_rand256(bin);
|
||||
if (secp256k1_fe_set_b32(x, bin)) {
|
||||
return;
|
||||
}
|
||||
} while(1);
|
||||
}
|
||||
/** END stolen from tests.c */
|
||||
|
||||
int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32,
|
||||
const unsigned char *key32, const unsigned char *algo16,
|
||||
void *data, unsigned int attempt) {
|
||||
secp256k1_scalar s;
|
||||
int *idata = data;
|
||||
(void)msg32;
|
||||
(void)key32;
|
||||
(void)algo16;
|
||||
/* Some nonces cannot be used because they'd cause s and/or r to be zero.
|
||||
* The signing function has retry logic here that just re-calls the nonce
|
||||
* function with an increased `attempt`. So if attempt > 0 this means we
|
||||
* need to change the nonce to avoid an infinite loop. */
|
||||
if (attempt > 0) {
|
||||
(*idata)++;
|
||||
}
|
||||
secp256k1_scalar_set_int(&s, *idata);
|
||||
secp256k1_scalar_get_b32(nonce32, &s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
void test_exhaustive_endomorphism(const secp256k1_ge *group, int order) {
|
||||
int i;
|
||||
for (i = 0; i < order; i++) {
|
||||
secp256k1_ge res;
|
||||
secp256k1_ge_mul_lambda(&res, &group[i]);
|
||||
ge_equals_ge(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj, int order) {
|
||||
int i, j;
|
||||
|
||||
/* Sanity-check (and check infinity functions) */
|
||||
CHECK(secp256k1_ge_is_infinity(&group[0]));
|
||||
CHECK(secp256k1_gej_is_infinity(&groupj[0]));
|
||||
for (i = 1; i < order; i++) {
|
||||
CHECK(!secp256k1_ge_is_infinity(&group[i]));
|
||||
CHECK(!secp256k1_gej_is_infinity(&groupj[i]));
|
||||
}
|
||||
|
||||
/* Check all addition formulae */
|
||||
for (j = 0; j < order; j++) {
|
||||
secp256k1_fe fe_inv;
|
||||
secp256k1_fe_inv(&fe_inv, &groupj[j].z);
|
||||
for (i = 0; i < order; i++) {
|
||||
secp256k1_ge zless_gej;
|
||||
secp256k1_gej tmp;
|
||||
/* add_var */
|
||||
secp256k1_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL);
|
||||
ge_equals_gej(&group[(i + j) % order], &tmp);
|
||||
/* add_ge */
|
||||
if (j > 0) {
|
||||
secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]);
|
||||
ge_equals_gej(&group[(i + j) % order], &tmp);
|
||||
}
|
||||
/* add_ge_var */
|
||||
secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL);
|
||||
ge_equals_gej(&group[(i + j) % order], &tmp);
|
||||
/* add_zinv_var */
|
||||
zless_gej.infinity = groupj[j].infinity;
|
||||
zless_gej.x = groupj[j].x;
|
||||
zless_gej.y = groupj[j].y;
|
||||
secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv);
|
||||
ge_equals_gej(&group[(i + j) % order], &tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check doubling */
|
||||
for (i = 0; i < order; i++) {
|
||||
secp256k1_gej tmp;
|
||||
if (i > 0) {
|
||||
secp256k1_gej_double_nonzero(&tmp, &groupj[i], NULL);
|
||||
ge_equals_gej(&group[(2 * i) % order], &tmp);
|
||||
}
|
||||
secp256k1_gej_double_var(&tmp, &groupj[i], NULL);
|
||||
ge_equals_gej(&group[(2 * i) % order], &tmp);
|
||||
}
|
||||
|
||||
/* Check negation */
|
||||
for (i = 1; i < order; i++) {
|
||||
secp256k1_ge tmp;
|
||||
secp256k1_gej tmpj;
|
||||
secp256k1_ge_neg(&tmp, &group[i]);
|
||||
ge_equals_ge(&group[order - i], &tmp);
|
||||
secp256k1_gej_neg(&tmpj, &groupj[i]);
|
||||
ge_equals_gej(&group[order - i], &tmpj);
|
||||
}
|
||||
}
|
||||
|
||||
void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *group, const secp256k1_gej *groupj, int order) {
|
||||
int i, j, r_log;
|
||||
for (r_log = 1; r_log < order; r_log++) {
|
||||
for (j = 0; j < order; j++) {
|
||||
for (i = 0; i < order; i++) {
|
||||
secp256k1_gej tmp;
|
||||
secp256k1_scalar na, ng;
|
||||
secp256k1_scalar_set_int(&na, i);
|
||||
secp256k1_scalar_set_int(&ng, j);
|
||||
|
||||
secp256k1_ecmult(&ctx->ecmult_ctx, &tmp, &groupj[r_log], &na, &ng);
|
||||
ge_equals_gej(&group[(i * r_log + j) % order], &tmp);
|
||||
|
||||
if (i > 0) {
|
||||
secp256k1_ecmult_const(&tmp, &group[i], &ng);
|
||||
ge_equals_gej(&group[(i * j) % order], &tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) {
|
||||
secp256k1_fe x;
|
||||
unsigned char x_bin[32];
|
||||
k %= EXHAUSTIVE_TEST_ORDER;
|
||||
x = group[k].x;
|
||||
secp256k1_fe_normalize(&x);
|
||||
secp256k1_fe_get_b32(x_bin, &x);
|
||||
secp256k1_scalar_set_b32(r, x_bin, NULL);
|
||||
}
|
||||
|
||||
void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {
|
||||
int s, r, msg, key;
|
||||
for (s = 1; s < order; s++) {
|
||||
for (r = 1; r < order; r++) {
|
||||
for (msg = 1; msg < order; msg++) {
|
||||
for (key = 1; key < order; key++) {
|
||||
secp256k1_ge nonconst_ge;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
secp256k1_pubkey pk;
|
||||
secp256k1_scalar sk_s, msg_s, r_s, s_s;
|
||||
secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s;
|
||||
int k, should_verify;
|
||||
unsigned char msg32[32];
|
||||
|
||||
secp256k1_scalar_set_int(&s_s, s);
|
||||
secp256k1_scalar_set_int(&r_s, r);
|
||||
secp256k1_scalar_set_int(&msg_s, msg);
|
||||
secp256k1_scalar_set_int(&sk_s, key);
|
||||
|
||||
/* Verify by hand */
|
||||
/* Run through every k value that gives us this r and check that *one* works.
|
||||
* Note there could be none, there could be multiple, ECDSA is weird. */
|
||||
should_verify = 0;
|
||||
for (k = 0; k < order; k++) {
|
||||
secp256k1_scalar check_x_s;
|
||||
r_from_k(&check_x_s, group, k);
|
||||
if (r_s == check_x_s) {
|
||||
secp256k1_scalar_set_int(&s_times_k_s, k);
|
||||
secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s);
|
||||
secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s);
|
||||
secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s);
|
||||
should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s);
|
||||
}
|
||||
}
|
||||
/* nb we have a "high s" rule */
|
||||
should_verify &= !secp256k1_scalar_is_high(&s_s);
|
||||
|
||||
/* Verify by calling verify */
|
||||
secp256k1_ecdsa_signature_save(&sig, &r_s, &s_s);
|
||||
memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge));
|
||||
secp256k1_pubkey_save(&pk, &nonconst_ge);
|
||||
secp256k1_scalar_get_b32(msg32, &msg_s);
|
||||
CHECK(should_verify ==
|
||||
secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {
|
||||
int i, j, k;
|
||||
|
||||
/* Loop */
|
||||
for (i = 1; i < order; i++) { /* message */
|
||||
for (j = 1; j < order; j++) { /* key */
|
||||
for (k = 1; k < order; k++) { /* nonce */
|
||||
secp256k1_ecdsa_signature sig;
|
||||
secp256k1_scalar sk, msg, r, s, expected_r;
|
||||
unsigned char sk32[32], msg32[32];
|
||||
secp256k1_scalar_set_int(&msg, i);
|
||||
secp256k1_scalar_set_int(&sk, j);
|
||||
secp256k1_scalar_get_b32(sk32, &sk);
|
||||
secp256k1_scalar_get_b32(msg32, &msg);
|
||||
|
||||
secp256k1_ecdsa_sign(ctx, &sig, msg32, sk32, secp256k1_nonce_function_smallint, &k);
|
||||
|
||||
secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig);
|
||||
/* Note that we compute expected_r *after* signing -- this is important
|
||||
* because our nonce-computing function function might change k during
|
||||
* signing. */
|
||||
r_from_k(&expected_r, group, k);
|
||||
CHECK(r == expected_r);
|
||||
CHECK((k * s) % order == (i + r * j) % order ||
|
||||
(k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We would like to verify zero-knowledge here by counting how often every
|
||||
* possible (s, r) tuple appears, but because the group order is larger
|
||||
* than the field order, when coercing the x-values to scalar values, some
|
||||
* appear more often than others, so we are actually not zero-knowledge.
|
||||
* (This effect also appears in the real code, but the difference is on the
|
||||
* order of 1/2^128th the field order, so the deviation is not useful to a
|
||||
* computationally bounded attacker.)
|
||||
*/
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int i;
|
||||
secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER];
|
||||
secp256k1_ge group[EXHAUSTIVE_TEST_ORDER];
|
||||
|
||||
/* Build context */
|
||||
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
|
||||
/* TODO set z = 1, then do num_tests runs with random z values */
|
||||
|
||||
/* Generate the entire group */
|
||||
secp256k1_gej_set_infinity(&groupj[0]);
|
||||
secp256k1_ge_set_gej(&group[0], &groupj[0]);
|
||||
for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) {
|
||||
/* Set a different random z-value for each Jacobian point */
|
||||
secp256k1_fe z;
|
||||
random_fe(&z);
|
||||
|
||||
secp256k1_gej_add_ge(&groupj[i], &groupj[i - 1], &secp256k1_ge_const_g);
|
||||
secp256k1_ge_set_gej(&group[i], &groupj[i]);
|
||||
secp256k1_gej_rescale(&groupj[i], &z);
|
||||
|
||||
/* Verify against ecmult_gen */
|
||||
{
|
||||
secp256k1_scalar scalar_i;
|
||||
secp256k1_gej generatedj;
|
||||
secp256k1_ge generated;
|
||||
|
||||
secp256k1_scalar_set_int(&scalar_i, i);
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i);
|
||||
secp256k1_ge_set_gej(&generated, &generatedj);
|
||||
|
||||
CHECK(group[i].infinity == 0);
|
||||
CHECK(generated.infinity == 0);
|
||||
CHECK(secp256k1_fe_equal_var(&generated.x, &group[i].x));
|
||||
CHECK(secp256k1_fe_equal_var(&generated.y, &group[i].y));
|
||||
}
|
||||
}
|
||||
|
||||
/* Run the tests */
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
test_exhaustive_endomorphism(group, EXHAUSTIVE_TEST_ORDER);
|
||||
#endif
|
||||
test_exhaustive_addition(group, groupj, EXHAUSTIVE_TEST_ORDER);
|
||||
test_exhaustive_ecmult(ctx, group, groupj, EXHAUSTIVE_TEST_ORDER);
|
||||
test_exhaustive_sign(ctx, group, EXHAUSTIVE_TEST_ORDER);
|
||||
test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in a new issue