diff --git a/configure.ac b/configure.ac index d024570aa7..f3fce9de7e 100644 --- a/configure.ac +++ b/configure.ac @@ -909,7 +909,7 @@ PKGCONFIG_LIBDIR_TEMP="$PKG_CONFIG_LIBDIR" unset PKG_CONFIG_LIBDIR PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" -ac_configure_args="${ac_configure_args} --disable-shared --with-pic" +ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-module-schnorr --enable-module-ecdh --enable-module-rangeproof" AC_CONFIG_SUBDIRS([src/secp256k1]) AC_OUTPUT diff --git a/src/blind.cpp b/src/blind.cpp index 5de469a72f..a018037c30 100644 --- a/src/blind.cpp +++ b/src/blind.cpp @@ -6,14 +6,17 @@ #include "util.h" #include +#include static secp256k1_context_t* secp256k1_context = NULL; void ECC_Blinding_Start() { assert(secp256k1_context == NULL); - secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_COMMIT | SECP256K1_CONTEXT_RANGEPROOF); + secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); assert(ctx != NULL); + secp256k1_pedersen_context_initialize(ctx); + secp256k1_rangeproof_context_initialize(ctx); secp256k1_context = ctx; } @@ -42,14 +45,13 @@ int UnblindOutput(const CKey &key, const CTxOut& txout, CAmount& amount_out, std if (!ephemeral_key.IsValid()) { return 0; } - CPubKey nonce_key = key.ECDH(ephemeral_key); - unsigned char nonce[32]; - CHash256().Write(nonce_key.begin(), nonce_key.size()).Finalize(nonce); + uint256 nonce = key.ECDH(ephemeral_key); + CSHA256().Write(nonce.begin(), 32).Finalize(nonce.begin()); unsigned char msg[4096]; int msg_size; uint64_t min_value, max_value, amount; blinding_factor_out.resize(32); - int res = secp256k1_rangeproof_rewind(secp256k1_context, &blinding_factor_out[0], &amount, msg, &msg_size, nonce, &min_value, &max_value, &txout.nValue.vchCommitment[0], &txout.nValue.vchRangeproof[0], txout.nValue.vchRangeproof.size()); + int res = secp256k1_rangeproof_rewind(secp256k1_context, &blinding_factor_out[0], &amount, msg, &msg_size, nonce.begin(), &min_value, &max_value, &txout.nValue.vchCommitment[0], &txout.nValue.vchRangeproof[0], txout.nValue.vchRangeproof.size()); if (!res || amount > (uint64_t)MAX_MONEY || !MoneyRange((CAmount)amount)) { amount_out = 0; blinding_factor_out.resize(0); @@ -121,14 +123,13 @@ void BlindOutputs(const std::vector >& input_blinding value.vchNonceCommitment.resize(33); memcpy(&value.vchNonceCommitment[0], &ephemeral_pubkey[0], 33); // Generate nonce - CPubKey nonce_key = ephemeral_key.ECDH(output_pubkeys[nOut]); - unsigned char nonce[32]; - CHash256().Write(nonce_key.begin(), nonce_key.size()).Finalize(nonce); + uint256 nonce = ephemeral_key.ECDH(output_pubkeys[nOut]); + CSHA256().Write(nonce.begin(), 32).Finalize(nonce.begin()); // Create range proof int nRangeProofLen = 5134; // TODO: smarter min_value selection value.vchRangeproof.resize(nRangeProofLen); - int res = secp256k1_rangeproof_sign(ECC_Blinding_Context(), &value.vchRangeproof[0], &nRangeProofLen, 0, &value.vchCommitment[0], blindptrs.back(), nonce, std::min(std::max((int)GetArg("-ct_exponent", 0), -1),18), std::min(std::max((int)GetArg("-ct_bits", 32), 1), 51), amount); + int res = secp256k1_rangeproof_sign(ECC_Blinding_Context(), &value.vchRangeproof[0], &nRangeProofLen, 0, &value.vchCommitment[0], blindptrs.back(), nonce.begin(), std::min(std::max((int)GetArg("-ct_exponent", 0), -1),18), std::min(std::max((int)GetArg("-ct_bits", 32), 1), 51), amount); value.vchRangeproof.resize(nRangeProofLen); // TODO: do something smarter here assert(res); diff --git a/src/coins.cpp b/src/coins.cpp index b5d873c6a6..68ecd7ac70 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -9,6 +9,7 @@ #include #include +#include /** * calculate number of bytes for the bitmask, and its number of non-zero bytes diff --git a/src/key.cpp b/src/key.cpp index 9f5f4edeec..aa85e5b8bf 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -12,6 +12,8 @@ #include "random.h" #include +#include +#include static secp256k1_context_t* secp256k1_context = NULL; @@ -51,21 +53,21 @@ CPubKey CKey::GetPubKey() const { assert(fValid); CPubKey result; int clen = 65; - int ret = secp256k1_ec_pubkey_create(secp256k1_context, (unsigned char*)result.begin(), &clen, begin(), fCompressed); + secp256k1_pubkey_t pubkey; + int ret = secp256k1_ec_pubkey_create(secp256k1_context, &pubkey, begin()); + secp256k1_ec_pubkey_serialize(secp256k1_context, (unsigned char*)result.begin(), &clen, &pubkey, fCompressed); assert((int)result.size() == clen); assert(ret); assert(result.IsValid()); return result; } -CPubKey CKey::ECDH(const CPubKey& pubkey) const { +uint256 CKey::ECDH(const CPubKey& pubkey) const { assert(fValid); - CPubKey result = pubkey; - int clen = result.size(); - int ret = secp256k1_point_multiply((unsigned char*)result.begin(), &clen, begin()); - assert((int)result.size() == clen); - assert(ret); - assert(result.IsValid()); + uint256 result; + secp256k1_pubkey_t pkey; + assert(secp256k1_ec_pubkey_parse(secp256k1_context, &pkey, pubkey.begin(), pubkey.size())); + assert(secp256k1_ecdh(secp256k1_context, result.begin(), &pkey, begin())); return result; } @@ -101,9 +103,9 @@ bool CKey::SignCompact(const uint256 &hash, std::vector& vchSig) return false; vchSig.resize(65); int rec = -1; - int ret = secp256k1_ecdsa_sign_compact(secp256k1_context, hash.begin(), &vchSig[1], begin(), secp256k1_nonce_function_rfc6979, NULL, &rec); - assert(ret); - assert(rec != -1); + secp256k1_ecdsa_signature_t sig; + assert(secp256k1_ecdsa_sign(secp256k1_context, hash.begin(), &sig, begin(), secp256k1_nonce_function_rfc6979, NULL)); + assert(secp256k1_ecdsa_signature_serialize_compact(secp256k1_context, &vchSig[1], &rec, &sig)); vchSig[0] = 27 + rec + (fCompressed ? 4 : 0); return true; } diff --git a/src/key.h b/src/key.h index 080fce9a15..b261d49858 100644 --- a/src/key.h +++ b/src/key.h @@ -125,7 +125,7 @@ public: /** * Compute the ECDH exchange result using this private key and another public key. */ - CPubKey ECDH(const CPubKey& pubkey) const; + uint256 ECDH(const CPubKey& pubkey) const; /** * Create a DER-serialized signature. diff --git a/src/pubkey.cpp b/src/pubkey.cpp index c3fa54f9bb..a5805bf99f 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -5,6 +5,8 @@ #include "pubkey.h" #include +#include +#include secp256k1_context_t* secp256k1_bitcoin_verify_context = NULL; static secp256k1_context_t*& secp256k1_context = secp256k1_bitcoin_verify_context; @@ -14,7 +16,10 @@ bool CPubKey::Verify(const uint256 &hash, const std::vector& vchS return false; if (vchSig.size() != 64) return false; - if (secp256k1_schnorr_verify(secp256k1_context, (const unsigned char*)&hash, &vchSig[0], begin(), size()) != 1) + secp256k1_pubkey_t pubkey; + if (!secp256k1_ec_pubkey_parse(secp256k1_context, &pubkey, begin(), size())) + return false; + if (secp256k1_schnorr_verify(secp256k1_context, (const unsigned char*)&hash, &vchSig[0], &pubkey) != 1) return false; return true; } @@ -24,17 +29,26 @@ bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector #include "json/json_spirit_utils.h" #include "json/json_spirit_value.h" -#include +#include using namespace boost; using namespace boost::assign; using namespace json_spirit; using namespace std; +extern secp256k1_context_t* secp256k1_bitcoin_verify_context; + void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex) { txnouttype type; @@ -91,7 +93,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) int mantissa; uint64_t minv; uint64_t maxv; - if (secp256k1_rangeproof_info(NULL, &exp, &mantissa, &minv, &maxv, &txout.nValue.vchRangeproof[0], txout.nValue.vchRangeproof.size())) { + if (secp256k1_rangeproof_info(secp256k1_bitcoin_verify_context, &exp, &mantissa, &minv, &maxv, &txout.nValue.vchRangeproof[0], txout.nValue.vchRangeproof.size())) { if (exp == -1) { out.push_back(Pair("value", ValueFromAmount((CAmount)minv))); } else { diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 378eda21a6..ffe0df2337 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1462,7 +1462,11 @@ bool EvalScript(vector >& stack, const CScript& script, un unsigned char *pub_start = &(*(sdpc - 33)); CHMAC_SHA256(pub_start, 33).Write(&vcontract[0], 40).Finalize(tweak); // If someone creates a tweak that makes this fail, they broke SHA256 - assert(secp256k1_ec_pubkey_tweak_add(secp256k1_context, pub_start, 33, tweak) != 0); + secp256k1_pubkey_t pubkey; + int pubkeylen = 33; + assert(secp256k1_ec_pubkey_parse(secp256k1_context, &pubkey, pub_start, 33)); + assert(secp256k1_ec_pubkey_tweak_add(secp256k1_context, &pubkey, tweak) != 0); + assert(secp256k1_ec_pubkey_serialize(secp256k1_context, pub_start, &pubkeylen, &pubkey, 1)); } } } diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore index a697a794cc..e0b7b7a48a 100644 --- a/src/secp256k1/.gitignore +++ b/src/secp256k1/.gitignore @@ -2,9 +2,11 @@ bench_inv bench_ecdh bench_sign bench_verify +bench_schnorr_verify bench_recover bench_internal tests +gen_context *.exe *.so *.a @@ -29,6 +31,7 @@ build-aux/ *~ src/libsecp256k1-config.h src/libsecp256k1-config.h.in +src/ecmult_static_context.h m4/libtool.m4 m4/ltoptions.m4 m4/ltsugar.m4 diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml index 0d8089cfe4..0e1c8f96c9 100644 --- a/src/secp256k1/.travis.yml +++ b/src/secp256k1/.travis.yml @@ -8,18 +8,21 @@ compiler: - gcc env: global: - - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no ASM=no BUILD=check EXTRAFLAGS= HOST= + - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=NO matrix: - SCALAR=32bit + - SCALAR=32bit FIELD=32bit ECDH=yes - SCALAR=64bit - FIELD=64bit - FIELD=64bit ENDOMORPHISM=yes + - FIELD=64bit ENDOMORPHISM=yes ECDH=yes - FIELD=64bit ASM=x86_64 - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 - - FIELD=32bit + - FIELD=32bit SCHNORR=yes - FIELD=32bit ENDOMORPHISM=yes - BIGNUM=no - - BIGNUM=no ENDOMORPHISM=yes + - BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes + - BIGNUM=no STATICPRECOMPUTATION=no - BUILD=distcheck - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC matrix: @@ -55,5 +58,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-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR $EXTRAFLAGS $USE_HOST && make -j2 $BUILD + - ./configure --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 $EXTRAFLAGS $USE_HOST && make -j2 $BUILD os: linux diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am index 59bbc28cb7..dda3d13704 100644 --- a/src/secp256k1/Makefile.am +++ b/src/secp256k1/Makefile.am @@ -13,14 +13,14 @@ noinst_HEADERS += src/group.h noinst_HEADERS += src/group_impl.h noinst_HEADERS += src/num_gmp.h noinst_HEADERS += src/num_gmp_impl.h -noinst_HEADERS += src/ecdh.h -noinst_HEADERS += src/ecdh_impl.h noinst_HEADERS += src/ecdsa.h noinst_HEADERS += src/ecdsa_impl.h noinst_HEADERS += src/eckey.h noinst_HEADERS += src/eckey_impl.h noinst_HEADERS += src/ecmult.h noinst_HEADERS += src/ecmult_impl.h +noinst_HEADERS += src/ecmult_const.h +noinst_HEADERS += src/ecmult_const_impl.h noinst_HEADERS += src/ecmult_gen.h noinst_HEADERS += src/ecmult_gen_impl.h noinst_HEADERS += src/num.h @@ -40,56 +40,73 @@ noinst_HEADERS += src/hash_impl.h noinst_HEADERS += src/field.h noinst_HEADERS += src/field_impl.h noinst_HEADERS += src/bench.h -noinst_HEADERS += src/borromean.h -noinst_HEADERS += src/borromean_impl.h -noinst_HEADERS += src/rangeproof.h -noinst_HEADERS += src/rangeproof_impl.h -noinst_HEADERS += src/schnorr.h -noinst_HEADERS += src/schnorr_impl.h pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libsecp256k1.pc libsecp256k1_la_SOURCES = src/secp256k1.c -libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include $(SECP_INCLUDES) +libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) libsecp256k1_la_LIBADD = $(SECP_LIBS) noinst_PROGRAMS = if USE_BENCHMARK -noinst_PROGRAMS += bench_verify bench_recover bench_sign bench_rangeproof bench_internal bench_ecdh bench_schnorr_verify +noinst_PROGRAMS += bench_verify bench_recover bench_sign bench_internal bench_verify_SOURCES = src/bench_verify.c bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) bench_verify_LDFLAGS = -static -bench_schnorr_verify_SOURCES = src/bench_schnorr_verify.c -bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_schnorr_verify_LDFLAGS = -static bench_recover_SOURCES = src/bench_recover.c bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) bench_recover_LDFLAGS = -static bench_sign_SOURCES = src/bench_sign.c bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) bench_sign_LDFLAGS = -static -bench_rangeproof_SOURCES = src/bench_rangeproof.c -bench_rangeproof_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_rangeproof_LDFLAGS = -static bench_internal_SOURCES = src/bench_internal.c bench_internal_LDADD = $(SECP_LIBS) bench_internal_LDFLAGS = -static bench_internal_CPPFLAGS = $(SECP_INCLUDES) -bench_ecdh_SOURCES = src/bench_ecdh.c -bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_ecdh_LDFLAGS = -static -bench_ecdh_CPPFLAGS = $(SECP_INCLUDES) endif if USE_TESTS noinst_PROGRAMS += tests tests_SOURCES = src/tests.c -tests_CPPFLAGS = -DVERIFY $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) +tests_CPPFLAGS = -DVERIFY -I$(top_srcdir)/src $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) tests_LDFLAGS = -static TESTS = tests endif -EXTRA_DIST = autogen.sh +if USE_ECMULT_STATIC_PRECOMPUTATION +CPPFLAGS_FOR_BUILD +=-I$(top_srcdir)/ +CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function + +gen_context_OBJECTS = gen_context.o +gen_context_BIN = gen_context$(BUILD_EXEEXT) +gen_%.o: src/gen_%.c + $(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@ + +$(gen_context_BIN): $(gen_context_OBJECTS) + $(CC_FOR_BUILD) $^ -o $@ + +$(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h +$(tests_OBJECTS): src/ecmult_static_context.h + +src/ecmult_static_context.h: $(gen_context_BIN) + ./$(gen_context_BIN) + +CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h +endif + +EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h + +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_RANGEPROOF +include src/modules/rangeproof/Makefile.am.include +endif diff --git a/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 b/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 new file mode 100644 index 0000000000..77fd346a79 --- /dev/null +++ b/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 @@ -0,0 +1,125 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_CC_FOR_BUILD +# +# DESCRIPTION +# +# This macro searches for a C compiler that generates native executables, +# that is a C compiler that surely is not a cross-compiler. This can be +# useful if you have to generate source code at compile-time like for +# example GCC does. +# +# The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything +# needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD). +# The value of these variables can be overridden by the user by specifying +# a compiler with an environment variable (like you do for standard CC). +# +# It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object +# file extensions for the build platform, and GCC_FOR_BUILD to `yes' if +# the compiler we found is GCC. All these variables but GCC_FOR_BUILD are +# substituted in the Makefile. +# +# LICENSE +# +# Copyright (c) 2008 Paolo Bonzini +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +AU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD]) +AC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_CPP])dnl +AC_REQUIRE([AC_EXEEXT])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl + +dnl Use the standard macros, but make them use other variable names +dnl +pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl +pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl +pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl +pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl +pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl +pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl +pushdef([ac_cv_objext], ac_cv_build_objext)dnl +pushdef([ac_exeext], ac_build_exeext)dnl +pushdef([ac_objext], ac_build_objext)dnl +pushdef([CC], CC_FOR_BUILD)dnl +pushdef([CPP], CPP_FOR_BUILD)dnl +pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl +pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl +pushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl +pushdef([host], build)dnl +pushdef([host_alias], build_alias)dnl +pushdef([host_cpu], build_cpu)dnl +pushdef([host_vendor], build_vendor)dnl +pushdef([host_os], build_os)dnl +pushdef([ac_cv_host], ac_cv_build)dnl +pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl +pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl +pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl +pushdef([ac_cv_host_os], ac_cv_build_os)dnl +pushdef([ac_cpp], ac_build_cpp)dnl +pushdef([ac_compile], ac_build_compile)dnl +pushdef([ac_link], ac_build_link)dnl + +save_cross_compiling=$cross_compiling +save_ac_tool_prefix=$ac_tool_prefix +cross_compiling=no +ac_tool_prefix= + +AC_PROG_CC +AC_PROG_CPP +AC_EXEEXT + +ac_tool_prefix=$save_ac_tool_prefix +cross_compiling=$save_cross_compiling + +dnl Restore the old definitions +dnl +popdef([ac_link])dnl +popdef([ac_compile])dnl +popdef([ac_cpp])dnl +popdef([ac_cv_host_os])dnl +popdef([ac_cv_host_vendor])dnl +popdef([ac_cv_host_cpu])dnl +popdef([ac_cv_host_alias])dnl +popdef([ac_cv_host])dnl +popdef([host_os])dnl +popdef([host_vendor])dnl +popdef([host_cpu])dnl +popdef([host_alias])dnl +popdef([host])dnl +popdef([LDFLAGS])dnl +popdef([CPPFLAGS])dnl +popdef([CFLAGS])dnl +popdef([CPP])dnl +popdef([CC])dnl +popdef([ac_objext])dnl +popdef([ac_exeext])dnl +popdef([ac_cv_objext])dnl +popdef([ac_cv_exeext])dnl +popdef([ac_cv_prog_cc_g])dnl +popdef([ac_cv_prog_cc_cross])dnl +popdef([ac_cv_prog_cc_works])dnl +popdef([ac_cv_prog_gcc])dnl +popdef([ac_cv_prog_CPP])dnl + +dnl Finally, set Makefile variables +dnl +BUILD_EXEEXT=$ac_build_exeext +BUILD_OBJEXT=$ac_build_objext +AC_SUBST(BUILD_EXEEXT)dnl +AC_SUBST(BUILD_OBJEXT)dnl +AC_SUBST([CFLAGS_FOR_BUILD])dnl +AC_SUBST([CPPFLAGS_FOR_BUILD])dnl +AC_SUBST([LDFLAGS_FOR_BUILD])dnl +]) diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac index b94e85473b..e1c32aaca0 100644 --- a/src/secp256k1/configure.ac +++ b/src/secp256k1/configure.ac @@ -17,11 +17,14 @@ PKG_PROG_PKG_CONFIG AC_PATH_TOOL(AR, ar) AC_PATH_TOOL(RANLIB, ranlib) AC_PATH_TOOL(STRIP, strip) +AX_PROG_CC_FOR_BUILD if test "x$CFLAGS" = "x"; then CFLAGS="-O3 -g" fi +AM_PROG_CC_C_O + AC_PROG_CC_C89 if test x"$ac_cv_prog_cc_c89" = x"no"; then AC_MSG_ERROR([c89 compiler support required]) @@ -95,6 +98,26 @@ AC_ARG_ENABLE(endomorphism, AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]), [use_endomorphism=$enableval], [use_endomorphism=no]) + +AC_ARG_ENABLE(ecmult_static_precomputation, + AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]), + [use_ecmult_static_precomputation=$enableval], + [use_ecmult_static_precomputation=yes]) + +AC_ARG_ENABLE(module_ecdh, + AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (default is no)]), + [enable_module_ecdh=$enableval], + [enable_module_ecdh=no]) + +AC_ARG_ENABLE(module_schnorr, + AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (default is no)]), + [enable_module_schnorr=$enableval], + [enable_module_schnorr=no]) + +AC_ARG_ENABLE(module_rangeproof, + AS_HELP_STRING([--enable-module-rangeproof],[enable Pedersen / zero-knowledge range proofs module (default is no)]), + [enable_module_rangeproof=$enableval], + [enable_module_rangeproof=no]) AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], [Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) @@ -122,6 +145,7 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() { __builtin_clzll(1);}]])], [ AC_MSG_RESULT([no]) ]) + if test x"$req_asm" = x"auto"; then SECP_64BIT_ASM_CHECK if test x"$has_64bit_asm" = x"yes"; then @@ -157,7 +181,6 @@ if test x"$req_field" = x"auto"; then set_field=64bit fi fi - if test x"$set_field" = x; then set_field=32bit fi @@ -206,6 +229,11 @@ else fi if test x"$req_bignum" = x"auto"; then + SECP_GMP_CHECK + if test x"$has_gmp" = x"yes"; then + set_bignum=gmp + fi + if test x"$set_bignum" = x; then set_bignum=no fi @@ -307,6 +335,22 @@ 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 + AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table]) +fi + +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_rangeproof" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_RANGEPROOF, 1, [Define this symbol to enable the Pedersen / zero knowledge range proof module]) +fi + AC_C_BIGENDIAN() AC_MSG_NOTICE([Using assembly optimizations: $set_asm]) @@ -315,6 +359,10 @@ 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 range proof module: $enable_module_rangeproof]) + AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) AC_CONFIG_FILES([Makefile libsecp256k1.pc]) AC_SUBST(SECP_INCLUDES) @@ -323,6 +371,10 @@ AC_SUBST(SECP_TEST_LIBS) AC_SUBST(SECP_TEST_INCLUDES) AM_CONDITIONAL([USE_TESTS], [test x"$use_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([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_RANGEPROOF], [test x"$enable_module_rangeproof" = x"yes"]) dnl make sure nothing new is exported so that we don't break the cache PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h index fc67cf6647..1b8361e00e 100644 --- a/src/secp256k1/include/secp256k1.h +++ b/src/secp256k1/include/secp256k1.h @@ -5,8 +5,6 @@ extern "C" { # endif -#include - # if !defined(SECP256K1_GNUC_PREREQ) # if defined(__GNUC__)&&defined(__GNUC_MINOR__) # define SECP256K1_GNUC_PREREQ(_maj,_min) \ @@ -52,8 +50,6 @@ typedef struct secp256k1_context_struct secp256k1_context_t; /** Flags to pass to secp256k1_context_create. */ # define SECP256K1_CONTEXT_VERIFY (1 << 0) # define SECP256K1_CONTEXT_SIGN (1 << 1) -# define SECP256K1_CONTEXT_COMMIT (1 << 7) -# define SECP256K1_CONTEXT_RANGEPROOF (1 << 8) /** Create a secp256k1 context object. * Returns: a newly created context object. @@ -78,31 +74,186 @@ void secp256k1_context_destroy( secp256k1_context_t* ctx ) SECP256K1_ARG_NONNULL(1); +/** Set a callback function to be called when an illegal argument is passed to + * an API call. The philosophy is that these shouldn't be dealt with through a + * specific return value, as calling code should not have branches to deal with + * the case that this code itself is broken. + * On the other hand, during debug stage, one would want to be informed about + * such mistakes, and the default (crashing) may be inadvisable. + * When this callback is triggered, the API function called is guaranteed not + * to cause a crash, though its return value and output arguments are + * undefined. + */ +void secp256k1_context_set_illegal_callback( + secp256k1_context_t* ctx, + void (*fun)(const char* message, void* data), + void* data +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Set a callback function to be called when an internal consistency check + * fails. The default is crashing. + * This can only trigger in case of a hardware failure, miscompilation, + * memory corruption, serious bug in the library, or other error would can + * otherwise result in undefined behaviour. It will not trigger due to mere + * incorrect usage of the API (see secp256k1_context_set_illegal_callback + * for that). After this callback returns, anything may happen, including + * crashing. + */ +void secp256k1_context_set_error_callback( + secp256k1_context_t* ctx, + void (*fun)(const char* message, void* data), + void* data +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Data type to hold a parsed and valid public key. + This data type should be considered opaque to the user, and only created + through API functions. It is not guaranteed to be compatible between + different implementations. If you need to convert to a format suitable + for storage or transmission, use secp256k1_ec_pubkey_serialize and + secp256k1_ec_pubkey_parse. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_pubkey_t; + +/** Parse a variable-length public key into the pubkey object. + * Returns: 1 if the public key was fully valid. + * 0 if the public key could not be parsed or is invalid. + * In: ctx: a secp256k1 context object. + * input: pointer to a serialized public key + * inputlen: length of the array pointed to by input + * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a + * parsed version of input. If not, its value is undefined. + * This function supports parsing compressed (33 bytes, header byte 0x02 or + * 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header + * byte 0x06 or 0x07) format public keys. + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse( + const secp256k1_context_t* ctx, + secp256k1_pubkey_t* pubkey, + const unsigned char *input, + int inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a pubkey object into a serialized byte sequence. + * Returns: 1 always. + * In: ctx: a secp256k1 context object. + * pubkey: a pointer to a secp256k1_pubkey_t containing an initialized + * public key. + * compressed: whether to serialize in compressed format. + * Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if + * compressed==1) byte array to place the serialized key in. + * outputlen: a pointer to an integer which will contain the serialized + * size. + */ +int secp256k1_ec_pubkey_serialize( + const secp256k1_context_t* ctx, + unsigned char *output, + int *outputlen, + const secp256k1_pubkey_t* pubkey, + int compressed +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Data type to hold a parsed ECDSA signature, optionally supporting pubkey + * recovery. + This data type should be considered opaque to the user, and only created + through API functions. It is not guaranteed to be compatible between + different implementations. If you need to convert to a format suitable + for storage or transmission, use secp256k1_ecdsa_signature_serialize_* and + secp256k1_ecdsa_signature_parse_* functions. */ +typedef struct { + unsigned char data[65]; +} secp256k1_ecdsa_signature_t; + +/** Parse a DER ECDSA signature. + * Returns: 1 when the signature could be parsed, 0 otherwise. + * In: ctx: a secp256k1 context object + * input: a pointer to the signature to be parsed + * inputlen: the length of the array pointed to be input + * Out: sig: a pointer to a signature object + * + * Note that this function also supports some violations of DER. + * + * The resulting signature object will not support pubkey recovery. + */ +int secp256k1_ecdsa_signature_parse_der( + const secp256k1_context_t* ctx, + secp256k1_ecdsa_signature_t* sig, + const unsigned char *input, + int inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse a compact ECDSA signature (64 bytes + recovery id). + * Returns: 1 when the signature could be parsed, 0 otherwise + * In: ctx: a secp256k1 context object + * input64: a pointer to a 64-byte compact signature + * recid: the recovery id (0, 1, 2 or 3, or -1 for unknown) + * Out: sig: a pointer to a signature object + * + * If recid is not -1, the resulting signature object will support pubkey + * recovery. + */ +int secp256k1_ecdsa_signature_parse_compact( + const secp256k1_context_t* ctx, + secp256k1_ecdsa_signature_t* sig, + const unsigned char *input64, + int recid +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an ECDSA signature in DER format. + * Returns: 1 if enough space was available to serialize, 0 otherwise + * In: ctx: a secp256k1 context object + * sig: a pointer to an initialized signature object + * Out: output: a pointer to an array to store the DER serialization + * In/Out: outputlen: a pointer to a length integer. Initially, this integer + * should be set to the length of output. After the call + * it will be set to the length of the serialization (even + * if 0 was returned). + */ +int secp256k1_ecdsa_signature_serialize_der( + const secp256k1_context_t* ctx, + unsigned char *output, + int *outputlen, + const secp256k1_ecdsa_signature_t* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Serialize an ECDSA signature in compact format (64 bytes + recovery id). + * Returns: 1 + * In: ctx: a secp256k1 context object + * sig: a pointer to an initialized signature object (cannot be NULL) + * Out: output64: a pointer to a 64-byte array of the compact signature (cannot be NULL) + * recid: a pointer to an integer to hold the recovery id (can be NULL). + * + * If recid is not NULL, the signature must support pubkey recovery. + */ +int secp256k1_ecdsa_signature_serialize_compact( + const secp256k1_context_t* ctx, + unsigned char *output64, + int *recid, + const secp256k1_ecdsa_signature_t* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); + /** Verify an ECDSA signature. * Returns: 1: correct signature - * 0: incorrect signature - * -1: invalid public key - * -2: invalid signature + * 0: incorrect or unparseable signature * In: ctx: a secp256k1 context object, initialized for verification. * msg32: the 32-byte message hash being verified (cannot be NULL) * sig: the signature being verified (cannot be NULL) - * siglen: the length of the signature - * pubkey: the public key to verify with (cannot be NULL) - * pubkeylen: the length of pubkey + * pubkey: pointer to an initialized public key to verify with (cannot be NULL) */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( const secp256k1_context_t* ctx, const unsigned char *msg32, - const unsigned char *sig, - int siglen, - const unsigned char *pubkey, - int pubkeylen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); + const secp256k1_ecdsa_signature_t *sig, + const secp256k1_pubkey_t *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** A pointer to a function to deterministically generate a nonce. * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. * In: msg32: the 32-byte message hash being verified (will not be NULL) * key32: pointer to a 32-byte secret key (will not be NULL) + * algo16: pointer to a 16-byte array describing the signature + * algorithm (will be NULL for ECDSA for compatibility). * attempt: how many iterations we have tried to find a nonce. * This will almost always be 0, but different attempt values * are required to result in a different nonce. @@ -115,6 +266,7 @@ typedef int (*secp256k1_nonce_function_t)( unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, + const unsigned char *algo16, unsigned int attempt, const void *data ); @@ -128,19 +280,17 @@ extern const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979; /** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ extern const secp256k1_nonce_function_t secp256k1_nonce_function_default; - /** Create an ECDSA signature. * Returns: 1: signature created - * 0: the nonce generation function failed, the private key was invalid, or there is not - * enough space in the signature (as indicated by siglen). + * 0: the nonce generation function failed, or the private key was invalid. * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) * 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) * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) - * In/Out: siglen: pointer to an int with the length of sig, which will be updated - * to contain the actual signature length (<=72). + * + * The resulting signature will support pubkey recovery. * * The sig always has an s value in the lower half of the range (From 0x1 * to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, @@ -171,73 +321,26 @@ extern const secp256k1_nonce_function_t secp256k1_nonce_function_default; int secp256k1_ecdsa_sign( const secp256k1_context_t* ctx, const unsigned char *msg32, - unsigned char *sig, - int *siglen, + secp256k1_ecdsa_signature_t *sig, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void *ndata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -/** Create a compact ECDSA signature (64 byte + recovery id). - * Returns: 1: signature created - * 0: the nonce generation function failed, or the secret key was invalid. - * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * 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) - * Out: sig: pointer to a 64-byte array where the signature will be placed (cannot be NULL) - * In case 0 is returned, the returned signature length will be zero. - * recid: pointer to an int, which will be updated to contain the recovery id (can be NULL) - */ -int secp256k1_ecdsa_sign_compact( - const secp256k1_context_t* ctx, - const unsigned char *msg32, - unsigned char *sig64, - const unsigned char *seckey, - secp256k1_nonce_function_t noncefp, - const void *ndata, - int *recid ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); -/** Recover an ECDSA public key from a compact signature. +/** Recover an ECDSA public key from a signature. * Returns: 1: public key successfully recovered (which guarantees a correct signature). * 0: otherwise. * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) * msg32: the 32-byte message hash assumed to be signed (cannot be NULL) - * sig64: signature as 64 byte array (cannot be NULL) - * compressed: whether to recover a compressed or uncompressed pubkey - * recid: the recovery id (0-3, as returned by ecdsa_sign_compact) - * Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey (cannot be NULL) - * pubkeylen: pointer to an int that will contain the pubkey length (cannot be NULL) + * sig64: pointer to initialized signature that supports pubkey recovery (cannot be NULL) + * Out: pubkey: pointer to the recoved public key (cannot be NULL) */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover_compact( +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover( const secp256k1_context_t* ctx, const unsigned char *msg32, - const unsigned char *sig64, - unsigned char *pubkey, - int *pubkeylen, - int compressed, - int recid -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - - -/** Do an ellitic curve scalar multiplication in constant time. - * Returns: 1: exponentiation was successful - * -1: scalar was zero (cannot serialize output point) - * -2: scalar overflow - * -3: invalid input point - * In: scalar: a 32-byte scalar with which to multiple the point - * In/Out: point: pointer to 33 or 65 byte array containing an EC point - * which will be updated in place - * pointlen: length of the point array, which will be updated by - * the multiplication - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_point_multiply( - unsigned char *point, - int *pointlen, - const unsigned char *scalar -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + const secp256k1_ecdsa_signature_t *sig, + secp256k1_pubkey_t *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Verify an ECDSA secret key. * Returns: 1: secret key is valid @@ -250,51 +353,17 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify( const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); -/** Just validate a public key. - * Returns: 1: public key is valid - * 0: public key is invalid - * In: ctx: pointer to a context object (cannot be NULL) - * pubkey: pointer to a 33-byte or 65-byte public key (cannot be NULL). - * pubkeylen: length of pubkey - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_verify( - const secp256k1_context_t* ctx, - const unsigned char *pubkey, - int pubkeylen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - /** Compute the public key for a secret key. * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * compressed: whether the computed public key should be compressed * seckey: pointer to a 32-byte private key (cannot be NULL) - * Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed) - * area to store the public key (cannot be NULL) - * pubkeylen: pointer to int that will be updated to contains the pubkey's - * length (cannot be NULL) + * Out: pubkey: pointer to the created public key (cannot be NULL) * Returns: 1: secret was valid, public key stores * 0: secret was invalid, try again */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( const secp256k1_context_t* ctx, - unsigned char *pubkey, - int *pubkeylen, - const unsigned char *seckey, - int compressed -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Decompress a public key. - * In: ctx: pointer to a context object (cannot be NULL) - * In/Out: pubkey: pointer to a 65-byte array to put the decompressed public key. - * It must contain a 33-byte or 65-byte public key already (cannot be NULL) - * pubkeylen: pointer to the size of the public key pointed to by pubkey (cannot be NULL) - * It will be updated to reflect the new size. - * Returns: 0: pubkey was invalid - * 1: pubkey was valid, and was replaced with its decompressed version - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_decompress( - const secp256k1_context_t* ctx, - unsigned char *pubkey, - int *pubkeylen + secp256k1_pubkey_t *pubkey, + const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Export a private key in DER format. @@ -328,10 +397,9 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( const secp256k1_context_t* ctx, - unsigned char *pubkey, - int pubkeylen, + secp256k1_pubkey_t *pubkey, const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Tweak a private key by multiplying it with tweak. */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( @@ -345,10 +413,9 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( const secp256k1_context_t* ctx, - unsigned char *pubkey, - int pubkeylen, + secp256k1_pubkey_t *pubkey, const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Updates the context randomization. * Returns: 1: randomization successfully updated @@ -361,172 +428,23 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( const unsigned char *seed32 ) SECP256K1_ARG_NONNULL(1); -int secp256k1_schnorr_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata); -int secp256k1_schnorr_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig64, const unsigned char *pubkey, int pubkeylen); -int secp256k1_schnorr_verify_batch(const secp256k1_context_t* ctx, int n, const unsigned char *msg32, const unsigned char **sig64, const unsigned char **pubkey, const int *pubkeylen); - -/** Generate a pedersen commitment. - * Returns 1: commitment successfully created. - * 0: error - * In: ctx: pointer to a context object, initialized for signing and commitment (cannot be NULL) - * blind: pointer to a 32-byte blinding factor (cannot be NULL) - * value: unsigned 64-bit integer value to commit to. - * Out: commit: pointer to a 33-byte array for the commitment (cannot be NULL) - * - * Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA. +/** Add a number of public keys together. + * Returns: 1: the sum of the public keys is valid. + * 0: the sum of the public keys is not valid. + * In: ctx: pointer to a context object + * out: pointer to pubkey for placing the resulting public key + * (cannot be NULL) + * n: the number of public keys to add together (must be at least 1) + * ins: pointer to array of pointers to public keys (cannot be NULL) + * Use secp256k1_ec_pubkey_compress and secp256k1_ec_pubkey_decompress if the + * uncompressed format is needed. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit( +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( const secp256k1_context_t* ctx, - unsigned char *commit, - unsigned char *blind, - uint64_t value -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Computes the sum of multiple positive and negative blinding factors. - * Returns 1: sum successfully computed. - * 0: error - * In: ctx: pointer to a context object (cannot be NULL) - * blinds: pointer to pointers to 32-byte character arrays for blinding factors. (cannot be NULL) - * n: number of factors pointed to by blinds. - * nneg: how many of the initial factors should be treated with a positive sign. - * Out: blind_out: pointer to a 32-byte array for the sum (cannot be NULL) - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum( - const secp256k1_context_t* ctx, - unsigned char *blind_out, - const unsigned char * const *blinds, + secp256k1_pubkey_t *out, int n, - int npositive -)SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Verify a tally of pedersen commitments - * Returns 1: commitments successfully sum to zero. - * 0: Commitments do not sum to zero or other error. - * In: ctx: pointer to a context object, initialized for commitment (cannot be NULL) - * commits: pointer to pointers to 33-byte character arrays for the commitments. (cannot be NULL) - * pcnt: number of commitments pointed to by commits. - * ncommits: pointer to pointers to 33-byte character arrays for negative commitments. (cannot be NULL) - * ncnt: number of commitments pointed to by ncommits. - * excess: signed 64bit amount to add to the total to bring it to zero, can be negative. - * - * This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) - excess*H == 0. - * - * A pedersen commitment is xG + vH where G and H are generators for the secp256k1 group and x is a blinding factor, - * while v is the committed value. For a collection of commitments to sum to zero both their blinding factors and - * values must sum to zero. - * - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally( - const secp256k1_context_t* ctx, - const unsigned char * const *commits, - int pcnt, - const unsigned char * const *ncommits, - int ncnt, - int64_t excess -)SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); - -/** Verify a proof that a committed value is within a range. - * Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs. - * 0: Proof failed or other error. - * In: ctx: pointer to a context object, initialized for range-proof and commitment (cannot be NULL) - * commit: the 33-byte commitment being proved. (cannot be NULL) - * proof: pointer to character array with the proof. (cannot be NULL) - * plen: length of proof in bytes. - * Out: min_value: pointer to a unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL) - * max_value: pointer to a unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL) - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify( - const secp256k1_context_t* ctx, - uint64_t *min_value, - uint64_t *max_value, - const unsigned char *commit, - const unsigned char *proof, - int plen -)SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -/** Verify a range proof proof and rewind the proof to recover information sent by its author. - * Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs, and the value and blinding were recovered. - * 0: Proof failed, rewind failed, or other error. - * In: ctx: pointer to a context object, initialized for range-proof and commitment (cannot be NULL) - * commit: the 33-byte commitment being proved. (cannot be NULL) - * proof: pointer to character array with the proof. (cannot be NULL) - * plen: length of proof in bytes. - * nonce: secret nonce used by the prover (cannot be NULL) - * Out: blind_out: blinding factor used for the commitment - * value_out: pointer to an unsigned int64 which has the exact value of the commitment. - * message_out: pointer to a 4096 byte character array to receive message data from the proof author. - * min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL) - * max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL) - * In/Out: outlen: length of message data written to message_out. - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind( - const secp256k1_context_t* ctx, - unsigned char *blind_out, - uint64_t *value_out, - unsigned char *message_out, - int *outlen, - const unsigned char *nonce, - uint64_t *min_value, - uint64_t *max_value, - const unsigned char *commit, - const unsigned char *proof, - int plen -)SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(9) SECP256K1_ARG_NONNULL(10); - -/** Author a proof that a committed value is within a range. - * Returns 1: Proof successfully created. - * 0: Error - * In: ctx: pointer to a context object, initialized for range-proof, signing, and commitment (cannot be NULL) - * proof: pointer to array to receive the proof, can be up to 5134 bytes. (cannot be NULL) - * min_value: constructs a proof where the verifer can tell the minimum value is at least the specified amount. - * commit: 33-byte array with the commitment being proved. - * blind: 32-byte blinding factor used by commit. - * nonce: secret nonce used to initialize the proof (value can be engineered out of the proof if this secret is known.) - * exp: Base-10 exponent. Digits below this position will be made public, but the proof will be made smaller. Allowed range is -1 to 18. - * min_bits: Number of bits of the value to keep private. - * value: Actual value of the commitment. - * In/out: plen: point to an integer with the size of the proof buffer and the size of the constructed proof. - * - * If min_value or exp is non-zero then the value must be on the range [0, 2^63) to prevent the proof range from spanning past 2^64. - * - * If exp is -1 the value is revealed by the proof (e.g. it proves that the proof is a blinding of a specific value, without revealing the blinding key.) - * - * This can randomly fail with probability around one in 2^100. If this happens, buy a lottery ticket and retry with a different nonce or blinding. - * - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign( - const secp256k1_context_t* ctx, - unsigned char *proof, - int *plen, - uint64_t min_value, - const unsigned char *commit, - const unsigned char *blind, - const unsigned char *nonce, - int exp, - int min_bits, - uint64_t value -)SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7); - -/** Extract some basic information from a range-proof. - * Returns 1: Information successfully extracted. - * 0: Decode failed. - * In: ctx: pointer to a context object - * proof: pointer to character array with the proof. - * plen: length of proof in bytes. - * Out: exp: Exponent used in the proof (-1 means the value isn't private). - * mantissa: Number of bits covered by the proof. - * min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL) - * max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL) - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_info( - const secp256k1_context_t* ctx, - int *exp, - int *mantissa, - uint64_t *min_value, - uint64_t *max_value, - const unsigned char *proof, - int plen -)SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + const secp256k1_pubkey_t * const * ins +) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); # ifdef __cplusplus } diff --git a/src/secp256k1/include/secp256k1_ecdh.h b/src/secp256k1/include/secp256k1_ecdh.h new file mode 100644 index 0000000000..671c393fae --- /dev/null +++ b/src/secp256k1/include/secp256k1_ecdh.h @@ -0,0 +1,30 @@ +#ifndef _SECP256K1_ECDH_ +# define _SECP256K1_ECDH_ + +# include "secp256k1.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/** Compute an EC Diffie-Hellman secret in constant time + * Returns: 1: exponentiation was successful + * 0: scalar was invalid (zero or overflow) + * In: ctx: pointer to a context object (cannot be NULL) + * point: pointer to a public point + * scalar: a 32-byte scalar with which to multiply the point + * Out: result: a 32-byte array which will be populated by an ECDH + * secret computed from the point and scalar + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh( + const secp256k1_context_t* ctx, + unsigned char *result, + const secp256k1_pubkey_t *point, + const unsigned char *scalar +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/secp256k1/include/secp256k1_rangeproof.h b/src/secp256k1/include/secp256k1_rangeproof.h new file mode 100644 index 0000000000..02d66fcc15 --- /dev/null +++ b/src/secp256k1/include/secp256k1_rangeproof.h @@ -0,0 +1,186 @@ +#ifndef _SECP256K1_RANGEPROOF_ +# define _SECP256K1_RANGEPROOF_ + +# include "secp256k1.h" + +# ifdef __cplusplus +extern "C" { +# endif + +#include + +/** Initialize a context for usage with Pedersen commitments. */ +int secp256k1_pedersen_context_initialize(secp256k1_context_t* ctx); + +/** Generate a pedersen commitment. + * Returns 1: commitment successfully created. + * 0: error + * In: ctx: pointer to a context object, initialized for signing and Pedersen commitment (cannot be NULL) + * blind: pointer to a 32-byte blinding factor (cannot be NULL) + * value: unsigned 64-bit integer value to commit to. + * Out: commit: pointer to a 33-byte array for the commitment (cannot be NULL) + * + * Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA. + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit( + const secp256k1_context_t* ctx, + unsigned char *commit, + unsigned char *blind, + uint64_t value +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Computes the sum of multiple positive and negative blinding factors. + * Returns 1: sum successfully computed. + * 0: error + * In: ctx: pointer to a context object (cannot be NULL) + * blinds: pointer to pointers to 32-byte character arrays for blinding factors. (cannot be NULL) + * n: number of factors pointed to by blinds. + * nneg: how many of the initial factors should be treated with a positive sign. + * Out: blind_out: pointer to a 32-byte array for the sum (cannot be NULL) + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum( + const secp256k1_context_t* ctx, + unsigned char *blind_out, + const unsigned char * const *blinds, + int n, + int npositive +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Verify a tally of pedersen commitments + * Returns 1: commitments successfully sum to zero. + * 0: Commitments do not sum to zero or other error. + * In: ctx: pointer to a context object, initialized for Pedersen commitment (cannot be NULL) + * commits: pointer to pointers to 33-byte character arrays for the commitments. (cannot be NULL if pcnt is non-zero) + * pcnt: number of commitments pointed to by commits. + * ncommits: pointer to pointers to 33-byte character arrays for negative commitments. (cannot be NULL if ncnt is non-zero) + * ncnt: number of commitments pointed to by ncommits. + * excess: signed 64bit amount to add to the total to bring it to zero, can be negative. + * + * This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) - excess*H == 0. + * + * A pedersen commitment is xG + vH where G and H are generators for the secp256k1 group and x is a blinding factor, + * while v is the committed value. For a collection of commitments to sum to zero both their blinding factors and + * values must sum to zero. + * + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally( + const secp256k1_context_t* ctx, + const unsigned char * const *commits, + int pcnt, + const unsigned char * const *ncommits, + int ncnt, + int64_t excess +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); + +/** Initialize a context for usage with Pedersen commitments. */ +int secp256k1_rangeproof_context_initialize(secp256k1_context_t* ctx); + +/** Verify a proof that a committed value is within a range. + * Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs. + * 0: Proof failed or other error. + * In: ctx: pointer to a context object, initialized for range-proof and commitment (cannot be NULL) + * commit: the 33-byte commitment being proved. (cannot be NULL) + * proof: pointer to character array with the proof. (cannot be NULL) + * plen: length of proof in bytes. + * Out: min_value: pointer to a unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL) + * max_value: pointer to a unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL) + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify( + const secp256k1_context_t* ctx, + uint64_t *min_value, + uint64_t *max_value, + const unsigned char *commit, + const unsigned char *proof, + int plen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + +/** Verify a range proof proof and rewind the proof to recover information sent by its author. + * Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs, and the value and blinding were recovered. + * 0: Proof failed, rewind failed, or other error. + * In: ctx: pointer to a context object, initialized for range-proof and Pedersen commitment (cannot be NULL) + * commit: the 33-byte commitment being proved. (cannot be NULL) + * proof: pointer to character array with the proof. (cannot be NULL) + * plen: length of proof in bytes. + * nonce: 32-byte secret nonce used by the prover (cannot be NULL) + * In/Out: blind_out: storage for the 32-byte blinding factor used for the commitment + * value_out: pointer to an unsigned int64 which has the exact value of the commitment. + * message_out: pointer to a 4096 byte character array to receive message data from the proof author. + * outlen: length of message data written to message_out. + * min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL) + * max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL) + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind( + const secp256k1_context_t* ctx, + unsigned char *blind_out, + uint64_t *value_out, + unsigned char *message_out, + int *outlen, + const unsigned char *nonce, + uint64_t *min_value, + uint64_t *max_value, + const unsigned char *commit, + const unsigned char *proof, + int plen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(9) SECP256K1_ARG_NONNULL(10); + +/** Author a proof that a committed value is within a range. + * Returns 1: Proof successfully created. + * 0: Error + * In: ctx: pointer to a context object, initialized for range-proof, signing, and Pedersen commitment (cannot be NULL) + * proof: pointer to array to receive the proof, can be up to 5134 bytes. (cannot be NULL) + * min_value: constructs a proof where the verifer can tell the minimum value is at least the specified amount. + * commit: 33-byte array with the commitment being proved. + * blind: 32-byte blinding factor used by commit. + * nonce: 32-byte secret nonce used to initialize the proof (value can be reverse-engineered out of the proof if this secret is known.) + * exp: Base-10 exponent. Digits below above will be made public, but the proof will be made smaller. Allowed range is -1 to 18. + * (-1 is a special case that makes the value public. 0 is the most private.) + * min_bits: Number of bits of the value to keep private. (0 = auto/minimal, - 64). + * value: Actual value of the commitment. + * In/out: plen: point to an integer with the size of the proof buffer and the size of the constructed proof. + * + * If min_value or exp is non-zero then the value must be on the range [0, 2^63) to prevent the proof range from spanning past 2^64. + * + * If exp is -1 the value is revealed by the proof (e.g. it proves that the proof is a blinding of a specific value, without revealing the blinding key.) + * + * This can randomly fail with probability around one in 2^100. If this happens, buy a lottery ticket and retry with a different nonce or blinding. + * + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign( + const secp256k1_context_t* ctx, + unsigned char *proof, + int *plen, + uint64_t min_value, + const unsigned char *commit, + const unsigned char *blind, + const unsigned char *nonce, + int exp, + int min_bits, + uint64_t value +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7); + +/** Extract some basic information from a range-proof. + * Returns 1: Information successfully extracted. + * 0: Decode failed. + * In: ctx: pointer to a context object + * proof: pointer to character array with the proof. + * plen: length of proof in bytes. + * Out: exp: Exponent used in the proof (-1 means the value isn't private). + * mantissa: Number of bits covered by the proof. + * min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL) + * max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL) + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_info( + const secp256k1_context_t* ctx, + int *exp, + int *mantissa, + uint64_t *min_value, + uint64_t *max_value, + const unsigned char *proof, + int plen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/secp256k1/include/secp256k1_schnorr.h b/src/secp256k1/include/secp256k1_schnorr.h new file mode 100644 index 0000000000..ff7b977f40 --- /dev/null +++ b/src/secp256k1/include/secp256k1_schnorr.h @@ -0,0 +1,173 @@ +#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. + * In: ctx: pointer to a context object, initialized for signing + * (cannot be NULL) + * 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) + * Out: sig64: pointer to a 64-byte array where the signature will be + * placed (cannot be NULL) + */ +int secp256k1_schnorr_sign( + const secp256k1_context_t* ctx, + const unsigned char *msg32, + unsigned char *sig64, + const unsigned char *seckey, + secp256k1_nonce_function_t 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 + * In: ctx: a secp256k1 context object, initialized for verification. + * msg32: the 32-byte message hash being verified (cannot be NULL) + * sig64: the 64-byte signature being verified (cannot be NULL) + * pubkey: the public key to verify with (cannot be NULL) + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify( + const secp256k1_context_t* ctx, + const unsigned char *msg32, + const unsigned char *sig64, + const secp256k1_pubkey_t *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. + * In: ctx: pointer to a context object, initialized for + * verification (cannot be NULL) + * msg32: the 32-byte message hash assumed to be signed (cannot + * be NULL) + * sig64: signature as 64 byte array (cannot be NULL) + * Out: pubkey: pointer to a pubkey to set to the recovered public key + * (cannot be NULL). + */ +int secp256k1_schnorr_recover( + const secp256k1_context_t* ctx, + const unsigned char *msg32, + const unsigned char *sig64, + secp256k1_pubkey_t *pubkey +) 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) + * In: ctx: pointer to a context object, initialized for signing + * (cannot be NULL) + * 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) + * Out: pubnonce: public side of the nonce (cannot be NULL) + * privnonce32: private side of the nonce (32 byte) (cannot be NULL) + * + * Do not use the output as a private/public key pair for signing/validation. + */ +int secp256k1_schnorr_generate_nonce_pair( + const secp256k1_context_t* ctx, + const unsigned char *msg32, + const unsigned char *sec32, + secp256k1_nonce_function_t noncefp, + const void* noncedata, + secp256k1_pubkey_t *pubnonce, + unsigned char *privnonce32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7); + +/** 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 succesfully. + * 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. + * In: ctx: pointer to context object, initialized for signing (cannot + * be NULL) + * msg32: pointer to 32-byte message to sign + * sec32: pointer to 32-byte private key + * secnonce32: pointer to 32-byte array containing our nonce + * pubnonce_others: pointer to pubkey containing the sum of the other's + * nonces (see secp256k1_ec_pubkey_combine) + * Out: sig64: pointer to 64-byte array to put partial signature in + * + * 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_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_sign( + const secp256k1_context_t* ctx, + const unsigned char *msg32, + unsigned char *sig64, + const unsigned char *sec32, + const unsigned char *secnonce32, + const secp256k1_pubkey_t *pubnonce_others +) 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 succesfully 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 + * In: ctx: pointer to a context object + * sig64: pointer to a 64-byte array to place the combined signature + * (cannot be NULL) + * n: the number of signatures to combine (at least 1) + * Out: sig64sin: pointer to an array of n pointers to 64-byte input + * signatures + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_combine( + const secp256k1_context_t* ctx, + unsigned char *sig64, + int n, + const unsigned char * const * sig64sin +) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/secp256k1/src/basic-config.h b/src/secp256k1/src/basic-config.h new file mode 100644 index 0000000000..c4c16eb7ca --- /dev/null +++ b/src/secp256k1/src/basic-config.h @@ -0,0 +1,32 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_BASIC_CONFIG_ +#define _SECP256K1_BASIC_CONFIG_ + +#ifdef USE_BASIC_CONFIG + +#undef USE_ASM_X86_64 +#undef USE_ENDOMORPHISM +#undef USE_FIELD_10X26 +#undef USE_FIELD_5X52 +#undef USE_FIELD_INV_BUILTIN +#undef USE_FIELD_INV_NUM +#undef USE_NUM_GMP +#undef USE_NUM_NONE +#undef USE_SCALAR_4X64 +#undef USE_SCALAR_8X32 +#undef USE_SCALAR_INV_BUILTIN +#undef USE_SCALAR_INV_NUM + +#define USE_NUM_NONE 1 +#define USE_FIELD_INV_BUILTIN 1 +#define USE_SCALAR_INV_BUILTIN 1 +#define USE_FIELD_10X26 1 +#define USE_SCALAR_8X32 1 + +#endif // USE_BASIC_CONFIG +#endif // _SECP256K1_BASIC_CONFIG_ diff --git a/src/secp256k1/src/bench_ecdh.c b/src/secp256k1/src/bench_ecdh.c index dc69da2b1e..e28035a26a 100644 --- a/src/secp256k1/src/bench_ecdh.c +++ b/src/secp256k1/src/bench_ecdh.c @@ -7,18 +7,19 @@ #include #include "include/secp256k1.h" +#include "include/secp256k1_ecdh.h" #include "util.h" #include "bench.h" typedef struct { - unsigned char point[33]; - int pointlen; + secp256k1_context_t *ctx; + secp256k1_pubkey_t point; unsigned char scalar[32]; -} bench_multiply_t; +} bench_ecdh_t; -static void bench_multiply_setup(void* arg) { +static void bench_ecdh_setup(void* arg) { int i; - bench_multiply_t *data = (bench_multiply_t*)arg; + bench_ecdh_t *data = (bench_ecdh_t*)arg; const unsigned char point[] = { 0x03, 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, @@ -27,23 +28,24 @@ static void bench_multiply_setup(void* arg) { 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f }; + data->ctx = secp256k1_context_create(0); for (i = 0; i < 32; i++) data->scalar[i] = i + 1; - data->pointlen = sizeof(point); - memcpy(data->point, point, data->pointlen); + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1); } -static void bench_multiply(void* arg) { +static void bench_ecdh(void* arg) { int i; - bench_multiply_t *data = (bench_multiply_t*)arg; + unsigned char res[32]; + bench_ecdh_t *data = (bench_ecdh_t*)arg; for (i = 0; i < 20000; i++) { - CHECK(secp256k1_point_multiply(data->point, &data->pointlen, data->scalar) == 1); + CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1); } } int main(void) { - bench_multiply_t data; + bench_ecdh_t data; - run_benchmark("ecdh_mult", bench_multiply, bench_multiply_setup, NULL, &data, 10, 20000); + run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000); return 0; } diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c index bbbc7c3fc7..1a06e9441a 100644 --- a/src/secp256k1/src/bench_internal.c +++ b/src/secp256k1/src/bench_internal.c @@ -13,6 +13,7 @@ #include "field_impl.h" #include "group_impl.h" #include "scalar_impl.h" +#include "ecmult_const_impl.h" #include "ecmult_impl.h" #include "bench.h" @@ -21,7 +22,7 @@ typedef struct { secp256k1_fe_t fe_x, fe_y; secp256k1_ge_t ge_x, ge_y; secp256k1_gej_t gej_x, gej_y; - unsigned char data[32]; + unsigned char data[64]; int wnaf[256]; } bench_inv_t; @@ -51,6 +52,7 @@ void bench_setup(void* arg) { secp256k1_gej_set_ge(&data->gej_x, &data->ge_x); secp256k1_gej_set_ge(&data->gej_y, &data->ge_y); memcpy(data->data, init_x, 32); + memcpy(data->data + 32, init_y, 32); } void bench_scalar_add(void* arg) { @@ -96,7 +98,7 @@ void bench_scalar_split(void* arg) { for (i = 0; i < 20000; i++) { secp256k1_scalar_t l, r; - secp256k1_scalar_split_lambda_var(&l, &r, &data->scalar_x); + secp256k1_scalar_split_lambda(&l, &r, &data->scalar_x); secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); } } @@ -229,7 +231,17 @@ void bench_ecmult_wnaf(void* arg) { bench_inv_t *data = (bench_inv_t*)arg; for (i = 0; i < 20000; i++) { - secp256k1_ecmult_wnaf(data->wnaf, &data->scalar_x, WINDOW_A); + secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_wnaf_const(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A); secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); } } @@ -265,7 +277,7 @@ void bench_rfc6979_hmac_sha256(void* arg) { secp256k1_rfc6979_hmac_sha256_t rng; for (i = 0; i < 20000; i++) { - secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 32, data->data, 32, NULL, 0); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64); secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32); } } @@ -309,6 +321,7 @@ int main(int argc, char **argv) { if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000); if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, 20000); diff --git a/src/secp256k1/src/bench_rangeproof.c b/src/secp256k1/src/bench_rangeproof.c index 22f29b9cdf..c4e49c3e47 100644 --- a/src/secp256k1/src/bench_rangeproof.c +++ b/src/secp256k1/src/bench_rangeproof.c @@ -6,7 +6,7 @@ #include -#include "include/secp256k1.h" +#include "include/secp256k1_rangeproof.h" #include "util.h" #include "bench.h" @@ -52,11 +52,13 @@ static void bench_rangeproof(void* arg) { int main(void) { bench_rangeproof_t data; - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_COMMIT | SECP256K1_CONTEXT_RANGEPROOF); + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_pedersen_context_initialize(data.ctx); + secp256k1_rangeproof_context_initialize(data.ctx); data.min_bits = 32; - run_benchmark("rangeproof_verif_bit", bench_rangeproof, bench_rangeproof_setup, NULL, &data, 10, 1000 * data.min_bits); + run_benchmark("rangeproof_verify_bit", bench_rangeproof, bench_rangeproof_setup, NULL, &data, 10, 1000 * data.min_bits); secp256k1_context_destroy(data.ctx); return 0; diff --git a/src/secp256k1/src/bench_recover.c b/src/secp256k1/src/bench_recover.c index 56faed11a0..1b198ec346 100644 --- a/src/secp256k1/src/bench_recover.c +++ b/src/secp256k1/src/bench_recover.c @@ -17,16 +17,20 @@ typedef struct { void bench_recover(void* arg) { int i; bench_recover_t *data = (bench_recover_t*)arg; - unsigned char pubkey[33]; + secp256k1_pubkey_t pubkey; + unsigned char pubkeyc[33]; for (i = 0; i < 20000; i++) { int j; int pubkeylen = 33; - CHECK(secp256k1_ecdsa_recover_compact(data->ctx, data->msg, data->sig, pubkey, &pubkeylen, 1, i % 2)); + secp256k1_ecdsa_signature_t sig; + CHECK(secp256k1_ecdsa_signature_parse_compact(data->ctx, &sig, data->sig, i % 2)); + CHECK(secp256k1_ecdsa_recover(data->ctx, data->msg, &sig, &pubkey)); + CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, 1)); for (j = 0; j < 32; j++) { data->sig[j + 32] = data->msg[j]; /* Move former message to S. */ data->msg[j] = data->sig[j]; /* Move former R to message. */ - data->sig[j] = pubkey[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ + data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ } } } diff --git a/src/secp256k1/src/bench_schnorr_verify.c b/src/secp256k1/src/bench_schnorr_verify.c index 71af58ee44..274b6e02db 100644 --- a/src/secp256k1/src/bench_schnorr_verify.c +++ b/src/secp256k1/src/bench_schnorr_verify.c @@ -8,6 +8,7 @@ #include #include "include/secp256k1.h" +#include "include/secp256k1_schnorr.h" #include "util.h" #include "bench.h" @@ -31,10 +32,12 @@ static void benchmark_schnorr_init(void* arg) { for (i = 0; i < 32; i++) data->msg[i] = 1 + i; for (k = 0; k < data->numsigs; k++) { + secp256k1_pubkey_t pubkey; for (i = 0; i < 32; i++) data->sigs[k].key[i] = 33 + i + k; secp256k1_schnorr_sign(data->ctx, data->msg, data->sigs[k].sig, data->sigs[k].key, NULL, NULL); data->sigs[k].pubkeylen = 33; - CHECK(secp256k1_ec_pubkey_create(data->ctx, data->sigs[k].pubkey, &data->sigs[k].pubkeylen, data->sigs[k].key, 1)); + CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->sigs[k].key)); + CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->sigs[k].pubkey, &data->sigs[k].pubkeylen, &pubkey, 1)); } } @@ -43,29 +46,10 @@ static void benchmark_schnorr_verify(void* arg) { benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg; for (i = 0; i < 20000 / data->numsigs; i++) { + secp256k1_pubkey_t pubkey; data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF); - CHECK(secp256k1_schnorr_verify(data->ctx, data->msg, data->sigs[0].sig, data->sigs[0].pubkey, data->sigs[0].pubkeylen) == ((i & 0xFF) == 0)); - data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF); - } -} - -static void benchmark_schnorr_verify_batch(void* arg) { - int i, k; - benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg; - - const unsigned char *sig_ptr[64]; - const unsigned char *pubkey_ptr[64]; - int pubkeylen[64]; - - for (k = 0; k < data->numsigs; k++) { - sig_ptr[k] = &data->sigs[k].sig[0]; - pubkey_ptr[k] = &data->sigs[k].pubkey[0]; - pubkeylen[k] = data->sigs[k].pubkeylen; - } - - for (i = 0; i < 20000 / data->numsigs; i++) { - data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF); - CHECK(secp256k1_schnorr_verify_batch(data->ctx, data->numsigs, data->msg, sig_ptr, pubkey_ptr, pubkeylen) == ((i & 0xFF) == 0)); + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->sigs[0].pubkey, data->sigs[0].pubkeylen)); + CHECK(secp256k1_schnorr_verify(data->ctx, data->msg, data->sigs[0].sig, &pubkey) == ((i & 0xFF) == 0)); data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF); } } @@ -79,17 +63,6 @@ int main(void) { data.numsigs = 1; run_benchmark("schnorr_verify", benchmark_schnorr_verify, benchmark_schnorr_init, NULL, &data, 10, 20000); - run_benchmark("schnorr_verify_batch1", benchmark_schnorr_verify_batch, benchmark_schnorr_init, NULL, &data, 10, 20000); - data.numsigs = 2; - run_benchmark("schnorr_verify_batch2", benchmark_schnorr_verify_batch, benchmark_schnorr_init, NULL, &data, 10, 20000); - data.numsigs = 4; - run_benchmark("schnorr_verify_batch4", benchmark_schnorr_verify_batch, benchmark_schnorr_init, NULL, &data, 10, 20000); - data.numsigs = 8; - run_benchmark("schnorr_verify_batch8", benchmark_schnorr_verify_batch, benchmark_schnorr_init, NULL, &data, 10, 20000); - data.numsigs = 16; - run_benchmark("schnorr_verify_batch16", benchmark_schnorr_verify_batch, benchmark_schnorr_init, NULL, &data, 10, 20000); - data.numsigs = 32; - run_benchmark("schnorr_verify_batch32", benchmark_schnorr_verify_batch, benchmark_schnorr_init, NULL, &data, 10, 20000); secp256k1_context_destroy(data.ctx); return 0; diff --git a/src/secp256k1/src/bench_sign.c b/src/secp256k1/src/bench_sign.c index 072a37af51..e625da07a4 100644 --- a/src/secp256k1/src/bench_sign.c +++ b/src/secp256k1/src/bench_sign.c @@ -30,7 +30,9 @@ static void bench_sign(void* arg) { for (i = 0; i < 20000; i++) { int j; int recid = 0; - CHECK(secp256k1_ecdsa_sign_compact(data->ctx, data->msg, sig, data->key, NULL, NULL, &recid)); + secp256k1_ecdsa_signature_t signature; + CHECK(secp256k1_ecdsa_sign(data->ctx, data->msg, &signature, data->key, NULL, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_compact(data->ctx, sig, &recid, &signature)); for (j = 0; j < 32; j++) { data->msg[j] = sig[j]; /* Move former R to message. */ data->key[j] = sig[j + 32]; /* Move former S to key. */ diff --git a/src/secp256k1/src/bench_verify.c b/src/secp256k1/src/bench_verify.c index c8c82752ce..b8c5bdf58f 100644 --- a/src/secp256k1/src/bench_verify.c +++ b/src/secp256k1/src/bench_verify.c @@ -26,10 +26,14 @@ static void benchmark_verify(void* arg) { benchmark_verify_t* data = (benchmark_verify_t*)arg; for (i = 0; i < 20000; i++) { + secp256k1_pubkey_t pubkey; + secp256k1_ecdsa_signature_t sig; data->sig[data->siglen - 1] ^= (i & 0xFF); data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); - CHECK(secp256k1_ecdsa_verify(data->ctx, data->msg, data->sig, data->siglen, data->pubkey, data->pubkeylen) == (i == 0)); + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1); + CHECK(secp256k1_ecdsa_verify(data->ctx, data->msg, &sig, &pubkey) == (i == 0)); data->sig[data->siglen - 1] ^= (i & 0xFF); data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); @@ -38,6 +42,8 @@ static void benchmark_verify(void* arg) { int main(void) { int i; + secp256k1_pubkey_t pubkey; + secp256k1_ecdsa_signature_t sig; benchmark_verify_t data; data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); @@ -45,9 +51,10 @@ int main(void) { for (i = 0; i < 32; i++) data.msg[i] = 1 + i; for (i = 0; i < 32; i++) data.key[i] = 33 + i; data.siglen = 72; - secp256k1_ecdsa_sign(data.ctx, data.msg, data.sig, &data.siglen, data.key, NULL, NULL); - data.pubkeylen = 33; - CHECK(secp256k1_ec_pubkey_create(data.ctx, data.pubkey, &data.pubkeylen, data.key, 1)); + CHECK(secp256k1_ecdsa_sign(data.ctx, data.msg, &sig, data.key, NULL, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig)); + CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key)); + CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, 1) == 1); run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000); diff --git a/src/secp256k1/src/ecdh_impl.h b/src/secp256k1/src/ecdh_impl.h deleted file mode 100644 index 5e32536242..0000000000 --- a/src/secp256k1/src/ecdh_impl.h +++ /dev/null @@ -1,107 +0,0 @@ -/********************************************************************** - * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_ECDH_IMPL_ -#define _SECP256K1_ECDH_IMPL_ - -#include "scalar.h" -#include "group.h" -#include "ecdh.h" -#include "ecmult_impl.h" - -/** Convert a number to WNAF notation. The number becomes represented by sum(2^{wi} * wnaf[i], i=0..return_val) - * with the following guarantees: - * - each wnaf[i] an odd integer between -(1 << w) and (1 << w) - * - each wnaf[i] is nonzero - * - the number of words set is returned; this is always (256 + w - 1) / w - * - * Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar - * Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.) - * CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003 - * - * Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335 - */ -static int secp256k1_ecdh_wnaf(int *wnaf, const secp256k1_scalar_t *a, int w) { - secp256k1_scalar_t s = *a; - /* Negate to force oddness */ - int global_sign = secp256k1_scalar_wnaf_force_odd(&s); - - int bit = 0; - /* 1 2 3 */ - int u_last = secp256k1_scalar_shr_int(&s, w); - int u; - /* 4 */ - while (bit * w < 256) { - int sign; - int even; - - /* 4.1 4.4 */ - u = secp256k1_scalar_shr_int(&s, w); - /* 4.2 */ - even = ((u & 1) == 0); - sign = 2 * (u_last > 0) - 1; - u += sign * even; - u_last -= sign * even * (1 << w); - - /* 4.3, adapted for global sign change */ - wnaf[bit++] = u_last * global_sign; - - u_last = u; - } - wnaf[bit] = u * global_sign; - return bit; -} - - -static void secp256k1_ecdh_point_multiply(secp256k1_gej_t *r, const secp256k1_ge_t *a, const secp256k1_scalar_t *scalar) { - secp256k1_ge_t pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_ge_t tmpa; - secp256k1_fe_t Z; - - int wnaf[256]; - int n_words; - - int i; - int is_zero = secp256k1_scalar_is_zero(scalar); - secp256k1_scalar_t sc = *scalar; - /* the wNAF ladder cannot handle zero, so bump this to one .. we will - * correct the result after the fact */ - sc.d[0] += is_zero; - - /* build wnaf representation for q. */ - n_words = secp256k1_ecdh_wnaf(wnaf, &sc, WINDOW_A - 1); - - /* Calculate odd multiples of a. - * All multiples are brought to the same Z 'denominator', which is stored - * in Z. Due to secp256k1' isomorphism we can do all operations pretending - * that the Z coordinate was 1, use affine addition formulae, and correct - * the Z coordinate of the result once at the end. - */ - secp256k1_gej_set_ge(r, a); - secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r); - secp256k1_gej_set_infinity(r); - - for (i = n_words; i >= 0; i--) { - int n; - int j; - for (j = 0; j < WINDOW_A - 1; ++j) { - secp256k1_gej_double_var(r, r, NULL); - } - n = wnaf[i]; - VERIFY_CHECK(n != 0); - ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); - secp256k1_gej_add_ge(r, r, &tmpa); - } - - if (!r->infinity) { - secp256k1_fe_mul(&r->z, &r->z, &Z); - } - - /* correct for zero */ - r->infinity |= is_zero; -} - -#endif diff --git a/src/secp256k1/src/ecdsa.h b/src/secp256k1/src/ecdsa.h index 4ef78e8afb..c361728e57 100644 --- a/src/secp256k1/src/ecdsa.h +++ b/src/secp256k1/src/ecdsa.h @@ -11,14 +11,10 @@ #include "group.h" #include "ecmult.h" -typedef struct { - secp256k1_scalar_t r, s; -} secp256k1_ecdsa_sig_t; - -static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size); -static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a); -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message); -static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid); -static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid); +static int secp256k1_ecdsa_sig_parse(secp256k1_scalar_t *r, secp256k1_scalar_t *s, const unsigned char *sig, int size); +static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_scalar_t *r, const secp256k1_scalar_t *s); +static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_scalar_t* r, const secp256k1_scalar_t* s, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message); +static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_scalar_t* r, secp256k1_scalar_t* s, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid); +static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_scalar_t* r, const secp256k1_scalar_t* s, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid); #endif diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h index ed1d228189..c0c44fa182 100644 --- a/src/secp256k1/src/ecdsa_impl.h +++ b/src/secp256k1/src/ecdsa_impl.h @@ -46,7 +46,7 @@ static const secp256k1_fe_t secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_C 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL ); -static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) { +static int secp256k1_ecdsa_sig_parse(secp256k1_scalar_t *rr, secp256k1_scalar_t *rs, const unsigned char *sig, int size) { unsigned char ra[32] = {0}, sa[32] = {0}; const unsigned char *rp; const unsigned char *sp; @@ -98,26 +98,27 @@ static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned ch memcpy(ra + 32 - lenr, rp, lenr); memcpy(sa + 32 - lens, sp, lens); overflow = 0; - secp256k1_scalar_set_b32(&r->r, ra, &overflow); + secp256k1_scalar_set_b32(rr, ra, &overflow); if (overflow) { return 0; } - secp256k1_scalar_set_b32(&r->s, sa, &overflow); + secp256k1_scalar_set_b32(rs, sa, &overflow); if (overflow) { return 0; } return 1; } -static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) { +static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_scalar_t* ar, const secp256k1_scalar_t* as) { unsigned char r[33] = {0}, s[33] = {0}; unsigned char *rp = r, *sp = s; int lenR = 33, lenS = 33; - secp256k1_scalar_get_b32(&r[1], &a->r); - secp256k1_scalar_get_b32(&s[1], &a->s); + secp256k1_scalar_get_b32(&r[1], ar); + secp256k1_scalar_get_b32(&s[1], as); while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; } while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; } if (*size < 6+lenS+lenR) { + *size = 6 + lenS + lenR; return 0; } *size = 6 + lenS + lenR; @@ -132,26 +133,26 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se return 1; } -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) { +static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_scalar_t *sigr, const secp256k1_scalar_t *sigs, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) { unsigned char c[32]; secp256k1_scalar_t sn, u1, u2; secp256k1_fe_t xr; secp256k1_gej_t pubkeyj; secp256k1_gej_t pr; - if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) { + if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { return 0; } - secp256k1_scalar_inverse_var(&sn, &sig->s); + secp256k1_scalar_inverse_var(&sn, sigs); secp256k1_scalar_mul(&u1, &sn, message); - secp256k1_scalar_mul(&u2, &sn, &sig->r); + secp256k1_scalar_mul(&u2, &sn, sigr); secp256k1_gej_set_ge(&pubkeyj, pubkey); secp256k1_ecmult(ctx, &pr, &pubkeyj, &u2, &u1); if (secp256k1_gej_is_infinity(&pr)) { return 0; } - secp256k1_scalar_get_b32(c, &sig->r); + secp256k1_scalar_get_b32(c, sigr); secp256k1_fe_set_b32(&xr, c); /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) @@ -186,7 +187,7 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, con return 0; } -static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) { +static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_scalar_t *sigr, const secp256k1_scalar_t* sigs, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) { unsigned char brx[32]; secp256k1_fe_t fx; secp256k1_ge_t x; @@ -194,11 +195,11 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, co secp256k1_scalar_t rn, u1, u2; secp256k1_gej_t qj; - if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) { + if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { return 0; } - secp256k1_scalar_get_b32(brx, &sig->r); + secp256k1_scalar_get_b32(brx, sigr); VERIFY_CHECK(secp256k1_fe_set_b32(&fx, brx)); /* brx comes from a scalar, so is less than the order; certainly less than p */ if (recid & 2) { if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) { @@ -210,16 +211,16 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, co return 0; } secp256k1_gej_set_ge(&xj, &x); - secp256k1_scalar_inverse_var(&rn, &sig->r); + secp256k1_scalar_inverse_var(&rn, sigr); secp256k1_scalar_mul(&u1, &rn, message); secp256k1_scalar_negate(&u1, &u1); - secp256k1_scalar_mul(&u2, &rn, &sig->s); + secp256k1_scalar_mul(&u2, &rn, sigs); secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1); secp256k1_ge_set_gej_var(pubkey, &qj); return !secp256k1_gej_is_infinity(&qj); } -static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid) { +static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_scalar_t *sigr, secp256k1_scalar_t *sigs, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid) { unsigned char b[32]; secp256k1_gej_t rp; secp256k1_ge_t r; @@ -231,8 +232,8 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, s secp256k1_fe_normalize(&r.x); secp256k1_fe_normalize(&r.y); secp256k1_fe_get_b32(b, &r.x); - secp256k1_scalar_set_b32(&sig->r, b, &overflow); - if (secp256k1_scalar_is_zero(&sig->r)) { + secp256k1_scalar_set_b32(sigr, b, &overflow); + if (secp256k1_scalar_is_zero(sigr)) { /* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature. */ secp256k1_gej_clear(&rp); secp256k1_ge_clear(&r); @@ -241,18 +242,18 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, s if (recid) { *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); } - secp256k1_scalar_mul(&n, &sig->r, seckey); + secp256k1_scalar_mul(&n, sigr, seckey); secp256k1_scalar_add(&n, &n, message); - secp256k1_scalar_inverse(&sig->s, nonce); - secp256k1_scalar_mul(&sig->s, &sig->s, &n); + secp256k1_scalar_inverse(sigs, nonce); + secp256k1_scalar_mul(sigs, sigs, &n); secp256k1_scalar_clear(&n); secp256k1_gej_clear(&rp); secp256k1_ge_clear(&r); - if (secp256k1_scalar_is_zero(&sig->s)) { + if (secp256k1_scalar_is_zero(sigs)) { return 0; } - if (secp256k1_scalar_is_high(&sig->s)) { - secp256k1_scalar_negate(&sig->s, &sig->s); + if (secp256k1_scalar_is_high(sigs)) { + secp256k1_scalar_negate(sigs, sigs); if (recid) { *recid ^= 1; } diff --git a/src/secp256k1/src/ecmult.h b/src/secp256k1/src/ecmult.h index d38bacc4ba..f112cd9ec1 100644 --- a/src/secp256k1/src/ecmult.h +++ b/src/secp256k1/src/ecmult.h @@ -10,8 +10,6 @@ #include "num.h" #include "group.h" -#define SECP256K1_ECMULT_MAX_POINTS 64 - typedef struct { /* For accelerating the computation of a*P + b*G: */ secp256k1_ge_storage_t (*pre_g)[]; /* odd multiples of the generator */ @@ -21,16 +19,13 @@ typedef struct { } secp256k1_ecmult_context_t; static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx); -static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx); +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx, const callback_t *cb); static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, - const secp256k1_ecmult_context_t *src); + const secp256k1_ecmult_context_t *src, const callback_t *cb); static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx); static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx); /** Double multiply: R = na*A + ng*G */ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng); -/** Multiply-and-add multiple points: R = na[0] * a[0] + na[1] * a[1] + ... + na[points-1] * a[points-1] + ng * G. */ -static void secp256k1_ecmult_points(const secp256k1_ecmult_context_t *ctx, int points, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng); - #endif diff --git a/src/secp256k1/src/ecdh.h b/src/secp256k1/src/ecmult_const.h similarity index 59% rename from src/secp256k1/src/ecdh.h rename to src/secp256k1/src/ecmult_const.h index 1ae3e7e232..e8ff1feb8c 100644 --- a/src/secp256k1/src/ecdh.h +++ b/src/secp256k1/src/ecmult_const.h @@ -1,15 +1,15 @@ /********************************************************************** - * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * + * 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_ECDH_ -#define _SECP256K1_ECDH_ +#ifndef _SECP256K1_ECMULT_CONST_ +#define _SECP256K1_ECMULT_CONST_ #include "scalar.h" #include "group.h" -static void secp256k1_ecdh_point_multiply(secp256k1_gej_t *r, const secp256k1_ge_t *a, const secp256k1_scalar_t *q); +static void secp256k1_ecmult_const(secp256k1_gej_t *r, const secp256k1_ge_t *a, const secp256k1_scalar_t *q); #endif diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h new file mode 100644 index 0000000000..62406a242b --- /dev/null +++ b/src/secp256k1/src/ecmult_const_impl.h @@ -0,0 +1,258 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECMULT_CONST_IMPL_ +#define _SECP256K1_ECMULT_CONST_IMPL_ + +#include "scalar.h" +#include "group.h" +#include "ecmult_const.h" +#include "ecmult_impl.h" + +#ifdef USE_ENDOMORPHISM + #define WNAF_BITS 128 +#else + #define WNAF_BITS 256 +#endif +#define WNAF_SIZE(w) ((WNAF_BITS + (w) - 1) / (w)) + +/* This is like `ECMULT_TABLE_GET_GE` but is constant time */ +#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \ + int m; \ + int abs_n = (n) * (((n) > 0) * 2 - 1); \ + int idx_n = abs_n / 2; \ + secp256k1_fe_t neg_y; \ + VERIFY_CHECK(((n) & 1) == 1); \ + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ + VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \ + VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \ + for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \ + /* This loop is used to avoid secret data in array indices. See + * the comment in ecmult_gen_impl.h for rationale. */ \ + secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \ + secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \ + } \ + (r)->infinity = 0; \ + secp256k1_fe_negate(&neg_y, &(r)->y, 1); \ + secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \ +} while(0) + + +/** Convert a number to WNAF notation. The number becomes represented by sum(2^{wi} * wnaf[i], i=0..return_val) + * with the following guarantees: + * - each wnaf[i] an odd integer between -(1 << w) and (1 << w) + * - each wnaf[i] is nonzero + * - the number of words set is returned; this is always (WNAF_BITS + w - 1) / w + * + * Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar + * Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.) + * CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003 + * + * Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335 + */ +static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar_t s, int w) { + int global_sign = 1; + int skew = 0; + int word = 0; + /* 1 2 3 */ + int u_last; + int u; + +#ifdef USE_ENDOMORPHISM + /* If we are using the endomorphism, we cannot handle even numbers by negating + * them, since we are working with 128-bit numbers whose negations would be 256 + * bits, eliminating the performance advantage. Instead we use a technique from + * Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even) + * or 2 (for odd) to the number we are encoding, then compensating after the + * multiplication. */ + /* Negative 128-bit numbers will be negated, since otherwise they are 256-bit */ + int flip = secp256k1_scalar_is_high(&s); + /* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */ + int bit = flip ^ (s.d[0] & 1); + /* We check for negative one, since adding 2 to it will cause an overflow */ + secp256k1_scalar_t neg_s; + int not_neg_one; + secp256k1_scalar_negate(&neg_s, &s); + not_neg_one = !secp256k1_scalar_is_one(&neg_s); + secp256k1_scalar_cadd_bit(&s, bit, not_neg_one); + /* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects + * that we added two to it and flipped it. In fact for -1 these operations are + * identical. We only flipped, but since skewing is required (in the sense that + * the skew must be 1 or 2, never zero) and flipping is not, we need to change + * our flags to claim that we only skewed. */ + global_sign = secp256k1_scalar_cond_negate(&s, flip); + global_sign *= not_neg_one * 2 - 1; + skew = 1 << bit; +#else + /* Otherwise, we just negate to force oddness */ + int is_even = secp256k1_scalar_is_even(&s); + global_sign = secp256k1_scalar_cond_negate(&s, is_even); +#endif + + /* 4 */ + u_last = secp256k1_scalar_shr_int(&s, w); + while (word * w < WNAF_BITS) { + int sign; + int even; + + /* 4.1 4.4 */ + u = secp256k1_scalar_shr_int(&s, w); + /* 4.2 */ + even = ((u & 1) == 0); + sign = 2 * (u_last > 0) - 1; + u += sign * even; + u_last -= sign * even * (1 << w); + + /* 4.3, adapted for global sign change */ + wnaf[word++] = u_last * global_sign; + + u_last = u; + } + wnaf[word] = u * global_sign; + + VERIFY_CHECK(secp256k1_scalar_is_zero(&s)); + VERIFY_CHECK(word == WNAF_SIZE(w)); + return skew; +} + + +static void secp256k1_ecmult_const(secp256k1_gej_t *r, const secp256k1_ge_t *a, const secp256k1_scalar_t *scalar) { + secp256k1_ge_t pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_ge_t tmpa; + secp256k1_fe_t Z; + +#ifdef USE_ENDOMORPHISM + secp256k1_ge_t pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; + int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; + int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)]; + int skew_1; + int skew_lam; + secp256k1_scalar_t q_1, q_lam; +#else + int wnaf[1 + WNAF_SIZE(WINDOW_A - 1)]; +#endif + + int i; + secp256k1_scalar_t sc = *scalar; + + /* build wnaf representation for q. */ +#ifdef USE_ENDOMORPHISM + /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ + secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc); + /* no need for zero correction when using endomorphism since even + * numbers have one added to them anyway */ + skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1); + skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1); +#else + int is_zero = secp256k1_scalar_is_zero(scalar); + /* the wNAF ladder cannot handle zero, so bump this to one .. we will + * correct the result after the fact */ + sc.d[0] += is_zero; + VERIFY_CHECK(!secp256k1_scalar_is_zero(&sc)); + + secp256k1_wnaf_const(wnaf, sc, WINDOW_A - 1); +#endif + + /* Calculate odd multiples of a. + * All multiples are brought to the same Z 'denominator', which is stored + * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + */ + secp256k1_gej_set_ge(r, a); + secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r); + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_fe_normalize_weak(&pre_a[i].y); + } +#ifdef USE_ENDOMORPHISM + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); + } +#endif + + /* first loop iteration (separated out so we can directly set r, rather + * than having it start at infinity, get doubled several times, then have + * its new value added to it) */ +#ifdef USE_ENDOMORPHISM + i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); + secp256k1_gej_set_ge(r, &tmpa); + + i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A); + secp256k1_gej_add_ge(r, r, &tmpa); +#else + i = wnaf[WNAF_SIZE(WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); + secp256k1_gej_set_ge(r, &tmpa); +#endif + /* remaining loop iterations */ + for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) { + int n; + int j; + for (j = 0; j < WINDOW_A - 1; ++j) { + secp256k1_gej_double_nonzero(r, r, NULL); + } +#ifdef USE_ENDOMORPHISM + n = wnaf_1[i]; + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + VERIFY_CHECK(n != 0); + secp256k1_gej_add_ge(r, r, &tmpa); + + n = wnaf_lam[i]; + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); + VERIFY_CHECK(n != 0); + secp256k1_gej_add_ge(r, r, &tmpa); +#else + n = wnaf[i]; + VERIFY_CHECK(n != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + secp256k1_gej_add_ge(r, r, &tmpa); +#endif + } + + secp256k1_fe_mul(&r->z, &r->z, &Z); + +#ifdef USE_ENDOMORPHISM + { + /* Correct for wNAF skew */ + secp256k1_ge_t correction = *a; + secp256k1_ge_storage_t correction_1_stor; + secp256k1_ge_storage_t correction_lam_stor; + secp256k1_ge_storage_t a2_stor; + secp256k1_gej_t tmpj; + secp256k1_gej_set_ge(&tmpj, &correction); + secp256k1_gej_double_var(&tmpj, &tmpj, NULL); + secp256k1_ge_set_gej(&correction, &tmpj); + secp256k1_ge_to_storage(&correction_1_stor, a); + secp256k1_ge_to_storage(&correction_lam_stor, a); + secp256k1_ge_to_storage(&a2_stor, &correction); + + /* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */ + secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2); + secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2); + + /* Apply the correction */ + secp256k1_ge_from_storage(&correction, &correction_1_stor); + secp256k1_ge_neg(&correction, &correction); + secp256k1_gej_add_ge(r, r, &correction); + + secp256k1_ge_from_storage(&correction, &correction_lam_stor); + secp256k1_ge_neg(&correction, &correction); + secp256k1_ge_mul_lambda(&correction, &correction); + secp256k1_gej_add_ge(r, r, &correction); + } +#else + /* correct for zero */ + r->infinity |= is_zero; +#endif +} + +#endif diff --git a/src/secp256k1/src/ecmult_gen.h b/src/secp256k1/src/ecmult_gen.h index 01358a219c..a9419e4aa7 100644 --- a/src/secp256k1/src/ecmult_gen.h +++ b/src/secp256k1/src/ecmult_gen.h @@ -28,14 +28,10 @@ typedef struct { secp256k1_gej_t initial; } secp256k1_ecmult_gen_context_t; -typedef struct { - secp256k1_ge_storage_t (*prec)[16][16]; /* prec[j][i] = 16^j * i * G + U_i */ -} secp256k1_ecmult_gen2_context_t; - static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t* ctx); -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t* ctx); +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t* ctx, const callback_t* cb); static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst, - const secp256k1_ecmult_gen_context_t* src); + const secp256k1_ecmult_gen_context_t* src, const callback_t* cb); static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t* ctx); static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx); @@ -44,19 +40,4 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t* ctx, secp static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, const unsigned char *seed32); -static void secp256k1_ecmult_gen2_context_init(secp256k1_ecmult_gen2_context_t* ctx); -static void secp256k1_ecmult_gen2_context_build(secp256k1_ecmult_gen2_context_t* ctx); -static void secp256k1_ecmult_gen2_context_clone(secp256k1_ecmult_gen2_context_t *dst, - const secp256k1_ecmult_gen2_context_t* src); -static void secp256k1_ecmult_gen2_context_clear(secp256k1_ecmult_gen2_context_t* ctx); - -static int secp256k1_ecmult_gen2_context_is_built(const secp256k1_ecmult_gen2_context_t* ctx); - -/** Multiply a small number with the generator: r = gn*G2 */ -static void secp256k1_ecmult_gen2_small(const secp256k1_ecmult_gen2_context_t *ctx, secp256k1_gej_t *r, uint64_t gn); - -/* sec * G + value * G2. */ -static void secp256k1_ecmult_gen_gen2(const secp256k1_ecmult_gen_context_t *ecmult_gen_ctx, - const secp256k1_ecmult_gen2_context_t *cmult_gen2_ctx, secp256k1_gej_t *rj, const secp256k1_scalar_t *sec, uint64_t value); - #endif diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h index 3cd17be306..2397abf351 100644 --- a/src/secp256k1/src/ecmult_gen_impl.h +++ b/src/secp256k1/src/ecmult_gen_impl.h @@ -11,26 +11,26 @@ #include "group.h" #include "ecmult_gen.h" #include "hash_impl.h" - +#ifdef USE_ECMULT_STATIC_PRECOMPUTATION +#include "ecmult_static_context.h" +#endif static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t *ctx) { ctx->prec = NULL; } -static void secp256k1_ecmult_gen2_context_init(secp256k1_ecmult_gen2_context_t *ctx) { - ctx->prec = NULL; -} - -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t *ctx) { +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t *ctx, const callback_t* cb) { +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION secp256k1_ge_t prec[1024]; secp256k1_gej_t gj; secp256k1_gej_t nums_gej; int i, j; +#endif if (ctx->prec != NULL) { return; } - - ctx->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*ctx->prec)); +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + ctx->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec)); /* get the generator */ secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); @@ -72,119 +72,50 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t *c secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL); } } - secp256k1_ge_set_all_gej_var(1024, prec, precj); + secp256k1_ge_set_all_gej_var(1024, prec, precj, cb); } for (j = 0; j < 64; j++) { for (i = 0; i < 16; i++) { secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]); } } +#else + (void)cb; + ctx->prec = (secp256k1_ge_storage_t (*)[64][16])secp256k1_ecmult_static_context; +#endif secp256k1_ecmult_gen_blind(ctx, NULL); } -static void secp256k1_ecmult_gen2_context_build(secp256k1_ecmult_gen2_context_t *ctx) { - secp256k1_ge_t prec[256]; - secp256k1_gej_t gj; - secp256k1_gej_t nums_gej; - int i, j; - - if (ctx->prec != NULL) { - return; - } - - ctx->prec = (secp256k1_ge_storage_t (*)[16][16])checked_malloc(sizeof(*ctx->prec)); - - /* get the generator */ - secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g2); - - /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */ - { - static const unsigned char nums_b32[33] = "The scalar for this x is unknown"; - secp256k1_fe_t nums_x; - secp256k1_ge_t nums_ge; - VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32)); - VERIFY_CHECK(secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0)); - secp256k1_gej_set_ge(&nums_gej, &nums_ge); - /* Add G to make the bits in x uniformly distributed. */ - secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g2, NULL); - } - - /* compute prec. */ - { - secp256k1_gej_t precj[256]; /* Jacobian versions of prec. */ - secp256k1_gej_t gbase; - secp256k1_gej_t numsbase; - gbase = gj; /* 16^j * G */ - numsbase = nums_gej; /* 2^j * nums. */ - for (j = 0; j < 16; j++) { - /* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */ - precj[j*16] = numsbase; - for (i = 1; i < 16; i++) { - secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL); - } - /* Multiply gbase by 16. */ - for (i = 0; i < 4; i++) { - secp256k1_gej_double_var(&gbase, &gbase, NULL); - } - /* Multiply numbase by 2. */ - secp256k1_gej_double_var(&numsbase, &numsbase, NULL); - if (j == 14) { - /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */ - secp256k1_gej_neg(&numsbase, &numsbase); - secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL); - } - } - secp256k1_ge_set_all_gej_var(256, prec, precj); - } - for (j = 0; j < 16; j++) { - for (i = 0; i < 16; i++) { - secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]); - } - } -} - static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx) { return ctx->prec != NULL; } -static int secp256k1_ecmult_gen2_context_is_built(const secp256k1_ecmult_gen2_context_t* ctx) { - return ctx->prec != NULL; -} - static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst, - const secp256k1_ecmult_gen_context_t *src) { + const secp256k1_ecmult_gen_context_t *src, const callback_t* cb) { if (src->prec == NULL) { dst->prec = NULL; } else { - dst->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*dst->prec)); +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + dst->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(cb, sizeof(*dst->prec)); memcpy(dst->prec, src->prec, sizeof(*dst->prec)); +#else + (void)cb; + dst->prec = src->prec; +#endif dst->initial = src->initial; dst->blind = src->blind; } } -static void secp256k1_ecmult_gen2_context_clone(secp256k1_ecmult_gen2_context_t *dst, - const secp256k1_ecmult_gen2_context_t *src) { - if (src->prec == NULL) { - dst->prec = NULL; - } else { - dst->prec = (secp256k1_ge_storage_t (*)[16][16])checked_malloc(sizeof(*dst->prec)); - memcpy(dst->prec, src->prec, sizeof(*dst->prec)); - } -} - static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t *ctx) { +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION free(ctx->prec); +#endif secp256k1_scalar_clear(&ctx->blind); secp256k1_gej_clear(&ctx->initial); ctx->prec = NULL; } -static void secp256k1_ecmult_gen2_context_clear(secp256k1_ecmult_gen2_context_t *ctx) { - free(ctx->prec); - ctx->prec = NULL; -} - static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *gn) { secp256k1_ge_t add; secp256k1_ge_storage_t adds; @@ -227,6 +158,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, cons unsigned char nonce32[32]; secp256k1_rfc6979_hmac_sha256_t rng; int retry; + unsigned char keydata[64] = {0}; if (!seed32) { /* When seed is NULL, reset the initial point and blinding value. */ secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g); @@ -239,7 +171,12 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, cons * and guards against weak or adversarial seeds. This is a simpler and safer interface than * asking the caller for blinding values directly and expecting them to retry on failure. */ - secp256k1_rfc6979_hmac_sha256_initialize(&rng, seed32 ? seed32 : nonce32, 32, nonce32, 32, NULL, 0); + memcpy(keydata, nonce32, 32); + if (seed32) { + memcpy(keydata + 32, seed32, 32); + } + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32); + memset(keydata, 0, sizeof(keydata)); /* Retry for out of range results to achieve uniformity. */ do { secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); @@ -265,36 +202,4 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, cons secp256k1_gej_clear(&gb); } -/* Version of secp256k1_ecmult_gen using the second generator and working only on numbers in the range [0 .. 2^64). */ -static void secp256k1_ecmult_gen2_small(const secp256k1_ecmult_gen2_context_t *ctx, secp256k1_gej_t *r, uint64_t gn) { - secp256k1_ge_t add; - secp256k1_ge_storage_t adds; - int bits; - int i, j; - memset(&adds, 0, sizeof(adds)); - secp256k1_gej_set_infinity(r); - add.infinity = 0; - for (j = 0; j < 16; j++) { - bits = (gn >> (j * 4)) & 15; - for (i = 0; i < 16; i++) { - secp256k1_ge_storage_cmov(&adds, &(*ctx->prec)[j][i], i == bits); - } - secp256k1_ge_from_storage(&add, &adds); - secp256k1_gej_add_ge(r, r, &add); - } - bits = 0; - secp256k1_ge_clear(&add); -} - -/* sec * G + value * G2. */ -SECP256K1_INLINE static void secp256k1_ecmult_gen_gen2(const secp256k1_ecmult_gen_context_t *ecmult_gen_ctx, - const secp256k1_ecmult_gen2_context_t *cmult_gen2_ctx, secp256k1_gej_t *rj, const secp256k1_scalar_t *sec, uint64_t value) { - secp256k1_gej_t vj; - secp256k1_ecmult_gen(ecmult_gen_ctx, rj, sec); - secp256k1_ecmult_gen2_small(cmult_gen2_ctx, &vj, value); - /* FIXME: constant time. */ - secp256k1_gej_add_var(rj, rj, &vj, NULL); - secp256k1_gej_clear(&vj); -} - #endif diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h index 4c8b982574..d6da22073c 100644 --- a/src/secp256k1/src/ecmult_impl.h +++ b/src/secp256k1/src/ecmult_impl.h @@ -67,49 +67,13 @@ static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej_t *prej, s secp256k1_fe_mul(&prej[n-1].z, &prej[n-1].z, &d.z); } -/** Fill a table 'prej' with a concatenation of precomputed off multiples of the - * points in a. Prej will contain the values - * [1*a[0],3*a[0],...,(2*n-1)*a[0],1*a[1],3*a[1],...,(2*n-1)*a[k-1]], so it - * needs space for k * n values. zr[0] will contain prej[0].z / a[0].z. The - * other zr[i] values = prej[i].z / prej[i-1].z. */ -static void secp256k1_ecmult_points_odd_multiples_table(int k, int n, secp256k1_gej_t *prej, secp256k1_fe_t *zr, const secp256k1_gej_t *a) { - int j; - for (j = 0; j < k; j++) { - secp256k1_gej_t aa; - secp256k1_fe_t z2, z3; - if (j != 0) { - /* Make the Z coordinate of each input a known multiple of the - * last prej output of the previous input point. */ - secp256k1_fe_sqr(&z2, &prej[n * j - 1].z); - secp256k1_fe_mul(&z3, &z2, &prej[n * j - 1].z); - secp256k1_fe_mul(&aa.x, &a[j].x, &z2); - secp256k1_fe_mul(&aa.y, &a[j].y, &z3); - secp256k1_fe_mul(&aa.z, &a[j].z, &prej[n * j - 1].z); - aa.infinity = 0; - } else { - aa = a[0]; - } - secp256k1_ecmult_odd_multiples_table(n, &prej[n * j], &zr[n * j], &aa); - if (j != 0) { - /* Correct the first Z ratio output of this point, by multiplying it - * with the current point's input Z coordinate, chaining them - * together */ - secp256k1_fe_mul(zr + n * j, zr + n * j, &a[j].z); - } - } -} - /** Fill a table 'pre' with precomputed odd multiples of a. * - * There are 3 versions of this function: + * There are two versions of this function: * - secp256k1_ecmult_odd_multiples_table_globalz_windowa which brings its * resulting point set to a single constant Z denominator, stores the X and Y * coordinates as ge_storage points in pre, and stores the global Z in rz. * It only operates on tables sized for WINDOW_A wnaf multiples. - * - secp256k1_ecmult_points_odd_multiples_table_globalz_windowa which is - * identical to secp256k1_ecmult_odd_multiples_table_globalz_windowa, but - * works on several input points at once, and brings them all to a single - * global Z. * - secp256k1_ecmult_odd_multiples_table_storage_var, which converts its * resulting point set to actually affine points, and stores those in pre. * It operates on tables of any size, but uses heap-allocated temporaries. @@ -128,20 +92,10 @@ static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge_t secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr); } -static void secp256k1_ecmult_points_odd_multiples_table_globalz_windowa(int k, secp256k1_ge_t *pre, secp256k1_fe_t *globalz, const secp256k1_gej_t *a) { - secp256k1_gej_t prej[SECP256K1_ECMULT_MAX_POINTS * ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_fe_t zr[SECP256K1_ECMULT_MAX_POINTS * ECMULT_TABLE_SIZE(WINDOW_A)]; - - /* Compute the odd multiples of all inputs in Jacobian form. */ - secp256k1_ecmult_points_odd_multiples_table(k, ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a); - /* Bring them to the same Z denominator. */ - secp256k1_ge_globalz_set_table_gej(k * ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr); -} - -static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge_storage_t *pre, const secp256k1_gej_t *a) { - secp256k1_gej_t *prej = checked_malloc(sizeof(secp256k1_gej_t) * n); - secp256k1_ge_t *prea = checked_malloc(sizeof(secp256k1_ge_t) * n); - secp256k1_fe_t *zr = checked_malloc(sizeof(secp256k1_fe_t) * n); +static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge_storage_t *pre, const secp256k1_gej_t *a, const callback_t *cb) { + secp256k1_gej_t *prej = (secp256k1_gej_t*)checked_malloc(cb, sizeof(secp256k1_gej_t) * n); + secp256k1_ge_t *prea = (secp256k1_ge_t*)checked_malloc(cb, sizeof(secp256k1_ge_t) * n); + secp256k1_fe_t *zr = (secp256k1_fe_t*)checked_malloc(cb, sizeof(secp256k1_fe_t) * n); int i; /* Compute the odd multiples in Jacobian form. */ @@ -190,7 +144,7 @@ static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx) { #endif } -static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx) { +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx, const callback_t *cb) { secp256k1_gej_t gj; if (ctx->pre_g != NULL) { @@ -200,35 +154,35 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx) { /* get the generator */ secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); - ctx->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + ctx->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(cb, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); /* precompute the tables with odd multiples */ - secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj); + secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj, cb); #ifdef USE_ENDOMORPHISM { secp256k1_gej_t g_128j; int i; - ctx->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + ctx->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(cb, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); /* calculate 2^128*generator */ g_128j = gj; for (i = 0; i < 128; i++) { secp256k1_gej_double_var(&g_128j, &g_128j, NULL); } - secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j); + secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j, cb); } #endif } static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, - const secp256k1_ecmult_context_t *src) { + const secp256k1_ecmult_context_t *src, const callback_t *cb) { if (src->pre_g == NULL) { dst->pre_g = NULL; } else { size_t size = sizeof((*dst->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); - dst->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(size); + dst->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(cb, size); memcpy(dst->pre_g, src->pre_g, size); } #ifdef USE_ENDOMORPHISM @@ -236,7 +190,7 @@ static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, dst->pre_g_128 = NULL; } else { size_t size = sizeof((*dst->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); - dst->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(size); + dst->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(cb, size); memcpy(dst->pre_g_128, src->pre_g_128, size); } #endif @@ -259,43 +213,57 @@ static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx) { * - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1) * - two non-zero entries in wnaf are separated by at least w-1 zeroes. * - the number of set values in wnaf is returned. This number is at most 256, and at most one more - * - than the number of bits in the (absolute value) of the input. + * than the number of bits in the (absolute value) of the input. */ -static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_scalar_t *a, int w) { +static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar_t *a, int w) { secp256k1_scalar_t s = *a; - int set_bits = 0; + int last_set_bit = -1; int bit = 0; int sign = 1; + int carry = 0; + + VERIFY_CHECK(wnaf != NULL); + VERIFY_CHECK(0 <= len && len <= 256); + VERIFY_CHECK(a != NULL); + VERIFY_CHECK(2 <= w && w <= 31); + + memset(wnaf, 0, len * sizeof(wnaf[0])); if (secp256k1_scalar_get_bits(&s, 255, 1)) { secp256k1_scalar_negate(&s, &s); sign = -1; } - while (bit < 256) { + while (bit < len) { int now; int word; - if (secp256k1_scalar_get_bits(&s, bit, 1) == 0) { + if (secp256k1_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) { bit++; continue; } - while (set_bits < bit) { - wnaf[set_bits++] = 0; - } + now = w; - if (bit + now > 256) { - now = 256 - bit; - } - word = secp256k1_scalar_get_bits_var(&s, bit, now); - if (word & (1 << (w-1))) { - secp256k1_scalar_add_bit(&s, bit + w); - wnaf[set_bits++] = sign * (word - (1 << w)); - } else { - wnaf[set_bits++] = sign * word; + if (now > len - bit) { + now = len - bit; } + + word = secp256k1_scalar_get_bits_var(&s, bit, now) + carry; + + carry = (word >> (w-1)) & 1; + word -= carry << w; + + wnaf[bit] = sign * word; + last_set_bit = bit; + bit += now; } - return set_bits; +#ifdef VERIFY + CHECK(carry == 0); + while (bit < 256) { + CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0); + } +#endif + return last_set_bit + 1; } static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng) { @@ -318,7 +286,7 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge #else int wnaf_na[256]; int bits_na; - int wnaf_ng[257]; + int wnaf_ng[256]; int bits_ng; #endif int i; @@ -326,11 +294,11 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge #ifdef USE_ENDOMORPHISM /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ - secp256k1_scalar_split_lambda_var(&na_1, &na_lam, na); + secp256k1_scalar_split_lambda(&na_1, &na_lam, na); /* build wnaf representation for na_1 and na_lam. */ - bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A); - bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A); + bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, 130, &na_1, WINDOW_A); + bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, 130, &na_lam, WINDOW_A); VERIFY_CHECK(bits_na_1 <= 130); VERIFY_CHECK(bits_na_lam <= 130); bits = bits_na_1; @@ -339,7 +307,7 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge } #else /* build wnaf representation for na. */ - bits_na = secp256k1_ecmult_wnaf(wnaf_na, na, WINDOW_A); + bits_na = secp256k1_ecmult_wnaf(wnaf_na, 256, na, WINDOW_A); bits = bits_na; #endif @@ -364,8 +332,8 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge secp256k1_scalar_split_128(&ng_1, &ng_128, ng); /* Build wnaf representation for ng_1 and ng_128 */ - bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G); - bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G); + bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G); + bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G); if (bits_ng_1 > bits) { bits = bits_ng_1; } @@ -373,7 +341,7 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge bits = bits_ng_128; } #else - bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, ng, WINDOW_G); + bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G); if (bits_ng > bits) { bits = bits_ng; } @@ -418,121 +386,4 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge } } -static void secp256k1_ecmult_points(const secp256k1_ecmult_context_t *ctx, int points, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng) { - secp256k1_ge_t pre_a[SECP256K1_ECMULT_MAX_POINTS][ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_ge_t tmpa; - secp256k1_fe_t Z; -#ifdef USE_ENDOMORPHISM - secp256k1_ge_t pre_a_lam[SECP256K1_ECMULT_MAX_POINTS][ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_scalar_t na_1[SECP256K1_ECMULT_MAX_POINTS], na_lam[SECP256K1_ECMULT_MAX_POINTS]; - /* Splitted G factors. */ - secp256k1_scalar_t ng_1, ng_128; - int wnaf_na_1[SECP256K1_ECMULT_MAX_POINTS][130]; - int wnaf_na_lam[SECP256K1_ECMULT_MAX_POINTS][130]; - int bits_na_1[SECP256K1_ECMULT_MAX_POINTS]; - int bits_na_lam[SECP256K1_ECMULT_MAX_POINTS]; - int wnaf_ng_1[129]; - int bits_ng_1; - int wnaf_ng_128[129]; - int bits_ng_128; -#else - int wnaf_na[SECP256K1_ECMULT_MAX_POINTS][256]; - int bits_na[SECP256K1_ECMULT_MAX_POINTS]; - int wnaf_ng[257]; - int bits_ng; -#endif - int i; - int bits = 0; - int k; - - VERIFY_CHECK(points >= 1); - VERIFY_CHECK(points <= SECP256K1_ECMULT_MAX_POINTS); - - for (k = 0; k < points; k++) { -#ifdef USE_ENDOMORPHISM - /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ - secp256k1_scalar_split_lambda_var(&na_1[k], &na_lam[k], &na[k]); - - /* build wnaf representation for na_1 and na_lam. */ - bits_na_1[k] = secp256k1_ecmult_wnaf(wnaf_na_1[k], &na_1[k], WINDOW_A); - bits_na_lam[k] = secp256k1_ecmult_wnaf(wnaf_na_lam[k], &na_lam[k], WINDOW_A); - VERIFY_CHECK(bits_na_1[k] <= 130); - VERIFY_CHECK(bits_na_lam[k] <= 130); - if (bits_na_1[k] > bits) bits = bits_na_1[k]; - if (bits_na_lam[k] > bits) bits = bits_na_lam[k]; -#else - /* build wnaf representation for na. */ - bits_na[k] = secp256k1_ecmult_wnaf(wnaf_na[k], &na[k], WINDOW_A); - if (bits_na[k] > bits) bits = bits_na[k]; -#endif - } - - /* calculate odd multiples of all a's */ - secp256k1_ecmult_points_odd_multiples_table_globalz_windowa(points, &pre_a[0][0], &Z, a); - -#ifdef USE_ENDOMORPHISM - for (k = 0; k < points; k++) { - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - secp256k1_ge_mul_lambda(&pre_a_lam[k][i], &pre_a[k][i]); - } - } -#endif - -#ifdef USE_ENDOMORPHISM - /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ - secp256k1_scalar_split_128(&ng_1, &ng_128, ng); - - /* Build wnaf representation for ng_1 and ng_128 */ - bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G); - bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G); - if (bits_ng_1 > bits) bits = bits_ng_1; - if (bits_ng_128 > bits) bits = bits_ng_128; -#else - bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, ng, WINDOW_G); - if (bits_ng > bits) bits = bits_ng; -#endif - - secp256k1_gej_set_infinity(r); - - for (i = bits-1; i >= 0; i--) { - int n; - secp256k1_gej_double_var(r, r, NULL); -#ifdef USE_ENDOMORPHISM - for (k = 0; k < points; k++) { - if (i < bits_na_1[k] && (n = wnaf_na_1[k][i])) { - ECMULT_TABLE_GET_GE(&tmpa, pre_a[k], n, WINDOW_A); - secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); - } - if (i < bits_na_lam[k] && (n = wnaf_na_lam[k][i])) { - ECMULT_TABLE_GET_GE(&tmpa, pre_a_lam[k], n, WINDOW_A); - secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); - } - } - if (i < bits_ng_1 && (n = wnaf_ng_1[i])) { - ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); - secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); - } - if (i < bits_ng_128 && (n = wnaf_ng_128[i])) { - ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g_128, n, WINDOW_G); - secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); - } -#else - for (k = 0; k < points; k++) { - if (i < bits_na[k] && (n = wnaf_na[k][i])) { - ECMULT_TABLE_GET_GE(&tmpa, pre_a[k], n, WINDOW_A); - secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); - } - } - if (i < bits_ng && (n = wnaf_ng[i])) { - ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); - secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); - } -#endif - } - - if (!r->infinity) { - secp256k1_fe_mul(&r->z, &r->z, &Z); - } -} - #endif diff --git a/src/secp256k1/src/field_10x26.h b/src/secp256k1/src/field_10x26.h index 44bce6525d..cc4c74af3b 100644 --- a/src/secp256k1/src/field_10x26.h +++ b/src/secp256k1/src/field_10x26.h @@ -21,15 +21,15 @@ typedef struct { /* Unpacks a constant into a overlapping multi-limbed FE element. */ #define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ (d0) & 0x3FFFFFFUL, \ - ((d0) >> 26) | ((d1) & 0xFFFFFUL) << 6, \ - ((d1) >> 20) | ((d2) & 0x3FFFUL) << 12, \ - ((d2) >> 14) | ((d3) & 0xFFUL) << 18, \ - ((d3) >> 8) | ((d4) & 0x3) << 24, \ - ((d4) >> 2) & 0x3FFFFFFUL, \ - ((d4) >> 28) | ((d5) & 0x3FFFFFUL) << 4, \ - ((d5) >> 22) | ((d6) & 0xFFFF) << 10, \ - ((d6) >> 16) | ((d7) & 0x3FF) << 16, \ - ((d7) >> 10) \ + (((uint32_t)d0) >> 26) | ((uint32_t)(d1) & 0xFFFFFUL) << 6, \ + (((uint32_t)d1) >> 20) | ((uint32_t)(d2) & 0x3FFFUL) << 12, \ + (((uint32_t)d2) >> 14) | ((uint32_t)(d3) & 0xFFUL) << 18, \ + (((uint32_t)d3) >> 8) | ((uint32_t)(d4) & 0x3UL) << 24, \ + (((uint32_t)d4) >> 2) & 0x3FFFFFFUL, \ + (((uint32_t)d4) >> 28) | ((uint32_t)(d5) & 0x3FFFFFUL) << 4, \ + (((uint32_t)d5) >> 22) | ((uint32_t)(d6) & 0xFFFFUL) << 10, \ + (((uint32_t)d6) >> 16) | ((uint32_t)(d7) & 0x3FFUL) << 16, \ + (((uint32_t)d7) >> 10) \ } #ifdef VERIFY @@ -43,5 +43,5 @@ typedef struct { } secp256k1_fe_storage_t; #define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }} - +#define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0] #endif diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h index 871b91f912..0fc0b8633a 100644 --- a/src/secp256k1/src/field_10x26_impl.h +++ b/src/secp256k1/src/field_10x26_impl.h @@ -1083,8 +1083,10 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); #ifdef VERIFY - r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1); - r->normalized = (r->normalized & mask0) | (a->normalized & mask1); + if (a->magnitude > r->magnitude) { + r->magnitude = a->magnitude; + } + r->normalized &= a->normalized; #endif } diff --git a/src/secp256k1/src/field_5x52.h b/src/secp256k1/src/field_5x52.h index 4513d36f49..8b24da7023 100644 --- a/src/secp256k1/src/field_5x52.h +++ b/src/secp256k1/src/field_5x52.h @@ -21,10 +21,10 @@ typedef struct { /* Unpacks a constant into a overlapping multi-limbed FE element. */ #define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ (d0) | ((uint64_t)(d1) & 0xFFFFFUL) << 32, \ - ((d1) >> 20) | ((uint64_t)(d2)) << 12 | ((uint64_t)(d3) & 0xFFUL) << 44, \ - ((d3) >> 8) | ((uint64_t)(d4) & 0xFFFFFFFUL) << 24, \ - ((d4) >> 28) | ((uint64_t)(d5)) << 4 | ((uint64_t)(d6) & 0xFFFFUL) << 36, \ - ((d6) >> 16) | ((uint64_t)(d7)) << 16 \ + ((uint64_t)(d1) >> 20) | ((uint64_t)(d2)) << 12 | ((uint64_t)(d3) & 0xFFUL) << 44, \ + ((uint64_t)(d3) >> 8) | ((uint64_t)(d4) & 0xFFFFFFFUL) << 24, \ + ((uint64_t)(d4) >> 28) | ((uint64_t)(d5)) << 4 | ((uint64_t)(d6) & 0xFFFFUL) << 36, \ + ((uint64_t)(d6) >> 16) | ((uint64_t)(d7)) << 16 \ } #ifdef VERIFY diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h index bda4c3dfc2..768e7c9a0a 100644 --- a/src/secp256k1/src/field_5x52_impl.h +++ b/src/secp256k1/src/field_5x52_impl.h @@ -414,8 +414,10 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); #ifdef VERIFY - r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1); - r->normalized = (r->normalized & mask0) | (a->normalized & mask1); + if (a->magnitude > r->magnitude) { + r->magnitude = a->magnitude; + } + r->normalized &= a->normalized; #endif } diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h index e6ec11e8f2..6ccbf21ddd 100644 --- a/src/secp256k1/src/field_impl.h +++ b/src/secp256k1/src/field_impl.h @@ -212,6 +212,10 @@ static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { secp256k1_fe_inv(r, a); #elif defined(USE_FIELD_INV_NUM) secp256k1_num_t n, m; + static const secp256k1_fe_t negone = SECP256K1_FE_CONST( + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFC2E + ); /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ static const unsigned char prime[32] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, @@ -228,6 +232,10 @@ static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { secp256k1_num_mod_inverse(&n, &n, &m); secp256k1_num_get_bin(b, 32, &n); VERIFY_CHECK(secp256k1_fe_set_b32(r, b)); + /* Verify the result is the (unique) valid inverse using non-GMP code. */ + secp256k1_fe_mul(&c, &c, r); + secp256k1_fe_add(&c, &negone); + CHECK(secp256k1_fe_normalizes_to_zero_var(&c)); #else #error "Please select field inverse implementation" #endif diff --git a/src/secp256k1/src/gen_context.c b/src/secp256k1/src/gen_context.c new file mode 100644 index 0000000000..e5c987d644 --- /dev/null +++ b/src/secp256k1/src/gen_context.c @@ -0,0 +1,74 @@ +/********************************************************************** + * Copyright (c) 2013, 2014, 2015 Thomas Daede, Cory Fields * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#define USE_BASIC_CONFIG 1 + +#include "basic-config.h" +#include "include/secp256k1.h" +#include "field_impl.h" +#include "scalar_impl.h" +#include "group_impl.h" +#include "ecmult_gen_impl.h" + +static void default_error_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); + abort(); +} + +static const callback_t default_error_callback = { + default_error_callback_fn, + NULL +}; + +int main(int argc, char **argv) { + secp256k1_ecmult_gen_context_t ctx; + int inner; + int outer; + FILE* fp; + + (void)argc; + (void)argv; + + fp = fopen("src/ecmult_static_context.h","w"); + if (fp == NULL) { + fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n"); + return -1; + } + + fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); + fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); + fprintf(fp, "#include \"group.h\"\n"); + fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n"); + fprintf(fp, "static const secp256k1_ge_storage_t secp256k1_ecmult_static_context[64][16] = {\n"); + + secp256k1_ecmult_gen_context_init(&ctx); + secp256k1_ecmult_gen_context_build(&ctx, &default_error_callback); + for(outer = 0; outer != 64; outer++) { + fprintf(fp,"{\n"); + for(inner = 0; inner != 16; inner++) { + fprintf(fp," SC(%uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu)", SECP256K1_GE_STORAGE_CONST_GET((*ctx.prec)[outer][inner])); + if (inner != 15) { + fprintf(fp,",\n"); + } else { + fprintf(fp,"\n"); + } + } + if (outer != 63) { + fprintf(fp,"},\n"); + } else { + fprintf(fp,"}\n"); + } + } + fprintf(fp,"};\n"); + secp256k1_ecmult_gen_context_clear(&ctx); + + fprintf(fp, "#undef SC\n"); + fprintf(fp, "#endif\n"); + fclose(fp); + + return 0; +} diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h index 1d9ef9d2aa..48398918e2 100644 --- a/src/secp256k1/src/group.h +++ b/src/secp256k1/src/group.h @@ -38,6 +38,8 @@ typedef struct { #define SECP256K1_GE_STORAGE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_STORAGE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_STORAGE_CONST((i),(j),(k),(l),(m),(n),(o),(p))} +#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y) + /** Set a group element equal to the point at infinity */ static void secp256k1_ge_set_infinity(secp256k1_ge_t *r); @@ -60,7 +62,7 @@ static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a); static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *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_t *r, const secp256k1_gej_t *a); +static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const secp256k1_gej_t *a, const callback_t *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 @@ -92,6 +94,10 @@ static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a); /** Check whether a group element is the point at infinity. */ static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a); +/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). + * a may not be zero. Constant time. */ +static void secp256k1_gej_double_nonzero(secp256k1_gej_t *r, const secp256k1_gej_t *a, secp256k1_fe_t *rzr); + /** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). */ static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, secp256k1_fe_t *rzr); diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h index c980373494..165eba2a52 100644 --- a/src/secp256k1/src/group_impl.h +++ b/src/secp256k1/src/group_impl.h @@ -23,19 +23,6 @@ static const secp256k1_ge_t secp256k1_ge_const_g = SECP256K1_GE_CONST( 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL ); -/** Alternative generator for secp256k1. - * This is the sha256 of 'g' after DER encoding (without compression), - * which happens to be a point on the curve. - * sage: G2 = EllipticCurve ([F (0), F (7)]).lift_x(int(hashlib.sha256('0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'.decode('hex')).hexdigest(),16)) - * sage: '%x %x'%G2.xy() - */ -static const secp256k1_ge_t secp256k1_ge_const_g2 = SECP256K1_GE_CONST( - 0x50929b74UL, 0xc1a04954UL, 0xb78b4b60UL, 0x35e97a5eUL, - 0x078a5a0fUL, 0x28ec96d5UL, 0x47bfee9aUL, 0xce803ac0UL, - 0x31d3c686UL, 0x3973926eUL, 0x049e637cUL, 0xb1b5f40aUL, - 0x36dac28aUL, 0xf1766968UL, 0xc30c2313UL, 0xf3a38904UL -); - static void secp256k1_ge_set_gej_zinv(secp256k1_ge_t *r, const secp256k1_gej_t *a, const secp256k1_fe_t *zi) { secp256k1_fe_t zi2; secp256k1_fe_t zi3; @@ -95,19 +82,19 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge_t *r, secp256k1_gej_t *a) { r->y = a->y; } -static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const secp256k1_gej_t *a) { +static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const secp256k1_gej_t *a, const callback_t *cb) { secp256k1_fe_t *az; secp256k1_fe_t *azi; size_t i; size_t count = 0; - az = (secp256k1_fe_t *)checked_malloc(sizeof(secp256k1_fe_t) * len); + az = (secp256k1_fe_t *)checked_malloc(cb, sizeof(secp256k1_fe_t) * len); for (i = 0; i < len; i++) { if (!a[i].infinity) { az[count++] = a[i].z; } } - azi = (secp256k1_fe_t *)checked_malloc(sizeof(secp256k1_fe_t) * count); + azi = (secp256k1_fe_t *)checked_malloc(cb, sizeof(secp256k1_fe_t) * count); secp256k1_fe_inv_all_var(count, azi, az); free(az); @@ -314,6 +301,11 @@ static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t * secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */ } +static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej_t *r, const secp256k1_gej_t *a, secp256k1_fe_t *rzr) { + VERIFY_CHECK(!secp256k1_gej_is_infinity(a)); + secp256k1_gej_double_var(r, a, rzr); +} + static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b, secp256k1_fe_t *rzr) { /* Operations: 12 mul, 4 sqr, 2 normalize, 12 mul_int/add/negate */ secp256k1_fe_t z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; @@ -474,10 +466,11 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej_t *r, const secp256k1_gej_t static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) { - /* Operations: 7 mul, 5 sqr, 5 normalize, 17 mul_int/add/negate/cmov */ + /* Operations: 7 mul, 5 sqr, 4 normalize, 21 mul_int/add/negate/cmov */ static const secp256k1_fe_t fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_fe_t zz, u1, u2, s1, s2, z, t, m, n, q, rr; - int infinity; + secp256k1_fe_t zz, u1, u2, s1, s2, t, tt, m, n, q, rr; + secp256k1_fe_t m_alt, rr_alt; + int infinity, degenerate; VERIFY_CHECK(!b->infinity); VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); @@ -501,6 +494,34 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c * Y3 = 4*(R*(3*Q-2*R^2)-M^4) * Z3 = 2*M*Z * (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.) + * + * This formula has the benefit of being the same for both addition + * of distinct points and doubling. However, it breaks down in the + * case that either point is infinity, or that y1 = -y2. We handle + * these cases in the following ways: + * + * - If b is infinity we simply bail by means of a VERIFY_CHECK. + * + * - If a is infinity, we detect this, and at the end of the + * computation replace the result (which will be meaningless, + * but we compute to be constant-time) with b.x : b.y : 1. + * + * - If a = -b, we have y1 = -y2, which is a degenerate case. + * But here the answer is infinity, so we simply set the + * infinity flag of the result, overriding the computed values + * without even needing to cmov. + * + * - If y1 = -y2 but x1 != x2, which does occur thanks to certain + * properties of our curve (specifically, 1 has nontrivial cube + * roots in our field, and the curve equation has no x coefficient) + * then the answer is not infinity but also not given by the above + * equation. In this case, we cmov in place an alternate expression + * for lambda. Specifically (y1 - y2)/(x1 - x2). Where both these + * expressions for lambda are defined, they are equal, and can be + * obtained from each other by multiplication by (y1 + y2)/(y1 + y2) + * then substitution of x^3 + 7 for y^2 (using the curve equation). + * For all pairs of nonzero points (a, b) at least one is defined, + * so this covers everything. */ secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */ @@ -509,36 +530,57 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c s1 = a->y; secp256k1_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */ secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z2^2 (1) */ secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ - z = a->z; /* z = Z = Z1*Z2 (8) */ t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (2) */ m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (2) */ - secp256k1_fe_sqr(&n, &m); /* n = M^2 (1) */ - secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*M^2 (1) */ - secp256k1_fe_sqr(&n, &n); /* n = M^4 (1) */ secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */ - secp256k1_fe_mul(&t, &u1, &u2); secp256k1_fe_negate(&t, &t, 1); /* t = -U1*U2 (2) */ - secp256k1_fe_add(&rr, &t); /* rr = R = T^2-U1*U2 (3) */ - secp256k1_fe_sqr(&t, &rr); /* t = R^2 (1) */ - secp256k1_fe_mul(&r->z, &m, &z); /* r->z = M*Z (1) */ - infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity); - secp256k1_fe_mul_int(&r->z, 2 * (1 - a->infinity)); /* r->z = Z3 = 2*M*Z (2) */ - r->x = t; /* r->x = R^2 (1) */ - secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */ - secp256k1_fe_add(&r->x, &q); /* r->x = R^2-Q (3) */ - secp256k1_fe_normalize(&r->x); - secp256k1_fe_mul_int(&q, 3); /* q = -3*Q (6) */ - secp256k1_fe_mul_int(&t, 2); /* t = 2*R^2 (2) */ - secp256k1_fe_add(&t, &q); /* t = 2*R^2-3*Q (8) */ - secp256k1_fe_mul(&t, &t, &rr); /* t = R*(2*R^2-3*Q) (1) */ - secp256k1_fe_add(&t, &n); /* t = R*(2*R^2-3*Q)+M^4 (2) */ - secp256k1_fe_negate(&r->y, &t, 2); /* r->y = R*(3*Q-2*R^2)-M^4 (3) */ - secp256k1_fe_normalize_weak(&r->y); - secp256k1_fe_mul_int(&r->x, 4 * (1 - a->infinity)); /* r->x = X3 = 4*(R^2-Q) */ - secp256k1_fe_mul_int(&r->y, 4 * (1 - a->infinity)); /* r->y = Y3 = 4*R*(3*Q-2*R^2)-4*M^4 (4) */ + secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */ + secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */ + secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */ + /** If lambda = R/M = 0/0 we have a problem (except in the "trivial" + * case that Z = z1z2 = 0, and this is special-cased later on). */ + degenerate = secp256k1_fe_normalizes_to_zero(&m) & + secp256k1_fe_normalizes_to_zero(&rr); + /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2. + * This means either x1 == beta*x2 or beta*x1 == x2, where beta is + * a nontrivial cube root of one. In either case, an alternate + * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2), + * so we set R/M equal to this. */ + rr_alt = s1; + secp256k1_fe_mul_int(&rr_alt, 2); /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */ + secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 */ - /** In case a->infinity == 1, the above code results in r->x, r->y, and r->z all equal to 0. - * Replace r with b->x, b->y, 1 in that case. - */ + secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); + secp256k1_fe_cmov(&m_alt, &m, !degenerate); + /* Now Ralt / Malt = lambda and is guaranteed not to be 0/0. + * From here on out Ralt and Malt represent the numerator + * and denominator of lambda; R and M represent the explicit + * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */ + secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */ + secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*Malt^2 (1) */ + /* These two lines use the observation that either M == Malt or M == 0, + * so M^3 * Malt is either Malt^4 (which is computed by squaring), or + * zero (which is "computed" by cmov). So the cost is one squaring + * versus two multiplications. */ + secp256k1_fe_sqr(&n, &n); + secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */ + secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */ + secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Malt*Z (1) */ + infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity); + secp256k1_fe_mul_int(&r->z, 2); /* r->z = Z3 = 2*Malt*Z (2) */ + secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */ + secp256k1_fe_add(&t, &q); /* t = Ralt^2-Q (3) */ + secp256k1_fe_normalize_weak(&t); + r->x = t; /* r->x = Ralt^2-Q (1) */ + secp256k1_fe_mul_int(&t, 2); /* t = 2*x3 (2) */ + secp256k1_fe_add(&t, &q); /* t = 2*x3 - Q: (4) */ + secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*x3 - Q) (1) */ + secp256k1_fe_add(&t, &n); /* t = Ralt*(2*x3 - Q) + M^3*Malt (3) */ + secp256k1_fe_negate(&r->y, &t, 3); /* r->y = Ralt*(Q - 2x3) - M^3*Malt (4) */ + secp256k1_fe_normalize_weak(&r->y); + secp256k1_fe_mul_int(&r->x, 4); /* r->x = X3 = 4*(Ralt^2-Q) */ + secp256k1_fe_mul_int(&r->y, 4); /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */ + + /** In case a->infinity == 1, replace r with (b->x, b->y, 1). */ secp256k1_fe_cmov(&r->x, &b->x, a->infinity); secp256k1_fe_cmov(&r->y, &b->y, a->infinity); secp256k1_fe_cmov(&r->z, &fe_1, a->infinity); diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h index 843423d7f7..0ff01e63fa 100644 --- a/src/secp256k1/src/hash.h +++ b/src/secp256k1/src/hash.h @@ -34,7 +34,7 @@ typedef struct { int retry; } secp256k1_rfc6979_hmac_sha256_t; -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen, const unsigned char *msg, size_t msglen, const unsigned char *rnd, size_t rndlen); +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen); static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen); static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng); diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h index 9828827bcd..ae55df6d8a 100644 --- a/src/secp256k1/src/hash_impl.h +++ b/src/secp256k1/src/hash_impl.h @@ -202,7 +202,7 @@ static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsign } -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen, const unsigned char *msg, size_t msglen, const unsigned char *rnd, size_t rndlen) { +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen) { secp256k1_hmac_sha256_t hmac; static const unsigned char zero[1] = {0x00}; static const unsigned char one[1] = {0x01}; @@ -215,11 +215,6 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_write(&hmac, zero, 1); secp256k1_hmac_sha256_write(&hmac, key, keylen); - secp256k1_hmac_sha256_write(&hmac, msg, msglen); - if (rnd && rndlen) { - /* RFC6979 3.6 "Additional data". */ - secp256k1_hmac_sha256_write(&hmac, rnd, rndlen); - } secp256k1_hmac_sha256_finalize(&hmac, rng->k); secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); @@ -230,11 +225,6 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_write(&hmac, one, 1); secp256k1_hmac_sha256_write(&hmac, key, keylen); - secp256k1_hmac_sha256_write(&hmac, msg, msglen); - if (rnd && rndlen) { - /* RFC6979 3.6 "Additional data". */ - secp256k1_hmac_sha256_write(&hmac, rnd, rndlen); - } secp256k1_hmac_sha256_finalize(&hmac, rng->k); secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); diff --git a/src/secp256k1/src/modules/ecdh/Makefile.am.include b/src/secp256k1/src/modules/ecdh/Makefile.am.include new file mode 100644 index 0000000000..8ef3aff92f --- /dev/null +++ b/src/secp256k1/src/modules/ecdh/Makefile.am.include @@ -0,0 +1,9 @@ +include_HEADERS += include/secp256k1_ecdh.h +noinst_HEADERS += src/modules/ecdh/main_impl.h +noinst_HEADERS += src/modules/ecdh/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_ecdh +bench_ecdh_SOURCES = src/bench_ecdh.c +bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) +bench_ecdh_LDFLAGS = -static +endif diff --git a/src/secp256k1/src/modules/ecdh/main_impl.h b/src/secp256k1/src/modules/ecdh/main_impl.h new file mode 100644 index 0000000000..064cf6e577 --- /dev/null +++ b/src/secp256k1/src/modules/ecdh/main_impl.h @@ -0,0 +1,53 @@ +/********************************************************************** + * 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_MODULE_ECDH_MAIN_ +#define _SECP256K1_MODULE_ECDH_MAIN_ + +#include "ecmult_const_impl.h" + +int secp256k1_ecdh(const secp256k1_context_t* ctx, unsigned char *result, const secp256k1_pubkey_t *point, const unsigned char *scalar) { + int ret = 0; + int overflow = 0; + secp256k1_gej_t res; + secp256k1_ge_t pt; + secp256k1_scalar_t s; + ARG_CHECK(result != NULL); + ARG_CHECK(point != NULL); + ARG_CHECK(scalar != NULL); + (void)ctx; + + secp256k1_pubkey_load(ctx, &pt, point); + secp256k1_scalar_set_b32(&s, scalar, &overflow); + if (overflow || secp256k1_scalar_is_zero(&s)) { + ret = 0; + } else { + unsigned char x[32]; + unsigned char y[1]; + secp256k1_sha256_t sha; + + secp256k1_ecmult_const(&res, &pt, &s); + secp256k1_ge_set_gej(&pt, &res); + /* Compute a hash of the point in compressed form + * Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not + * expect its output to be secret and has a timing sidechannel. */ + secp256k1_fe_normalize(&pt.x); + secp256k1_fe_normalize(&pt.y); + secp256k1_fe_get_b32(x, &pt.x); + y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y); + + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, y, sizeof(y)); + secp256k1_sha256_write(&sha, x, sizeof(x)); + secp256k1_sha256_finalize(&sha, result); + ret = 1; + } + + secp256k1_scalar_clear(&s); + return ret; +} + +#endif diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h new file mode 100644 index 0000000000..271eb28aaa --- /dev/null +++ b/src/secp256k1/src/modules/ecdh/tests_impl.h @@ -0,0 +1,75 @@ +/********************************************************************** + * 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_MODULE_ECDH_TESTS_ +#define _SECP256K1_MODULE_ECDH_TESTS_ + +void test_ecdh_generator_basepoint(void) { + unsigned char s_one[32] = { 0 }; + secp256k1_pubkey_t point[2]; + int i; + + s_one[31] = 1; + /* Check against pubkey creation when the basepoint is the generator */ + for (i = 0; i < 100; ++i) { + secp256k1_sha256_t sha; + unsigned char s_b32[32]; + unsigned char output_ecdh[32]; + unsigned char output_ser[32]; + unsigned char point_ser[33]; + int point_ser_len = sizeof(point_ser); + secp256k1_scalar_t s; + + random_scalar_order(&s); + secp256k1_scalar_get_b32(s_b32, &s); + + /* compute using ECDH function */ + CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1); + CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1); + /* compute "explicitly" */ + CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], 1) == 1); + CHECK(point_ser_len == sizeof(point_ser)); + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, point_ser, point_ser_len); + secp256k1_sha256_finalize(&sha, output_ser); + /* compare */ + CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0); + } +} + +void test_bad_scalar(void) { + unsigned char s_zero[32] = { 0 }; + unsigned char s_overflow[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 + }; + unsigned char s_rand[32] = { 0 }; + unsigned char output[32]; + secp256k1_scalar_t rand; + secp256k1_pubkey_t point; + + /* Create random point */ + random_scalar_order(&rand); + secp256k1_scalar_get_b32(s_rand, &rand); + CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1); + + /* Try to multiply it by bad values */ + CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0); + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0); + /* ...and a good one */ + s_overflow[31] -= 1; + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1); +} + +void run_ecdh_tests(void) { + test_ecdh_generator_basepoint(); + test_bad_scalar(); +} + +#endif diff --git a/src/secp256k1/src/modules/rangeproof/Makefile.am.include b/src/secp256k1/src/modules/rangeproof/Makefile.am.include new file mode 100644 index 0000000000..ff8b8d3803 --- /dev/null +++ b/src/secp256k1/src/modules/rangeproof/Makefile.am.include @@ -0,0 +1,15 @@ +include_HEADERS += include/secp256k1_rangeproof.h +noinst_HEADERS += src/modules/rangeproof/main_impl.h +noinst_HEADERS += src/modules/rangeproof/pedersen.h +noinst_HEADERS += src/modules/rangeproof/pedersen_impl.h +noinst_HEADERS += src/modules/rangeproof/borromean.h +noinst_HEADERS += src/modules/rangeproof/borromean_impl.h +noinst_HEADERS += src/modules/rangeproof/rangeproof.h +noinst_HEADERS += src/modules/rangeproof/rangeproof_impl.h +noinst_HEADERS += src/modules/rangeproof/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_rangeproof +bench_rangeproof_SOURCES = src/bench_rangeproof.c +bench_rangeproof_LDADD = libsecp256k1.la $(SECP_LIBS) +bench_rangeproof_LDFLAGS = -static +endif diff --git a/src/secp256k1/src/borromean.h b/src/secp256k1/src/modules/rangeproof/borromean.h similarity index 100% rename from src/secp256k1/src/borromean.h rename to src/secp256k1/src/modules/rangeproof/borromean.h diff --git a/src/secp256k1/src/borromean_impl.h b/src/secp256k1/src/modules/rangeproof/borromean_impl.h similarity index 96% rename from src/secp256k1/src/borromean_impl.h rename to src/secp256k1/src/modules/rangeproof/borromean_impl.h index 58fa2e0144..0c4f1c9525 100644 --- a/src/secp256k1/src/borromean_impl.h +++ b/src/secp256k1/src/modules/rangeproof/borromean_impl.h @@ -15,6 +15,7 @@ #include "ecmult_gen.h" #include "borromean.h" +#include #ifdef WORDS_BIGENDIAN #define BE32(x) (x) @@ -41,7 +42,7 @@ SECP256K1_INLINE static void secp256k1_borromean_hash(unsigned char *hash, const * Verifies nrings concurrent ring signatures all sharing a challenge value. * Signature is one s value per pubkey and a hash. * Verification equation: - * | m = H(P_{0..}||message) (Message contains a pubkey commitment) + * | m = H(P_{0..}||message) (Message must contain pubkeys or a pubkey commitment) * | For each ring i: * | | en = to_scalar(H(e0||m||i||0)) * | | For each pubkey j: @@ -73,7 +74,7 @@ int secp256k1_borromean_verify(const secp256k1_ecmult_context_t* ecmult_ctx, sec count = 0; secp256k1_sha256_initialize(&sha256_e0); for (i = 0; i < nrings; i++) { - DEBUG_CHECK(INT_MAX - count > rsizes[i]); + VERIFY_CHECK(INT_MAX - count > rsizes[i]); secp256k1_borromean_hash(tmp, m, mlen, e0, 32, i, 0); secp256k1_scalar_set_b32(&ens, tmp, &overflow); for (j = 0; j < rsizes[i]; j++) { @@ -132,7 +133,7 @@ int secp256k1_borromean_sign(const secp256k1_ecmult_context_t* ecmult_ctx, const secp256k1_sha256_initialize(&sha256_e0); count = 0; for (i = 0; i < nrings; i++) { - DEBUG_CHECK(INT_MAX - count > rsizes[i]); + VERIFY_CHECK(INT_MAX - count > rsizes[i]); secp256k1_ecmult_gen(ecmult_gen_ctx, &rgej, &k[i]); secp256k1_ge_set_gej(&rge, &rgej); if (secp256k1_gej_is_infinity(&rgej)) { @@ -163,7 +164,7 @@ int secp256k1_borromean_sign(const secp256k1_ecmult_context_t* ecmult_ctx, const secp256k1_sha256_finalize(&sha256_e0, e0); count = 0; for (i = 0; i < nrings; i++) { - DEBUG_CHECK(INT_MAX - count > rsizes[i]); + VERIFY_CHECK(INT_MAX - count > rsizes[i]); secp256k1_borromean_hash(tmp, m, mlen, e0, 32, i, 0); secp256k1_scalar_set_b32(&ens, tmp, &overflow); if (overflow || secp256k1_scalar_is_zero(&ens)) { diff --git a/src/secp256k1/src/modules/rangeproof/main_impl.h b/src/secp256k1/src/modules/rangeproof/main_impl.h new file mode 100644 index 0000000000..7abdc98c96 --- /dev/null +++ b/src/secp256k1/src/modules/rangeproof/main_impl.h @@ -0,0 +1,176 @@ +/********************************************************************** + * Copyright (c) 2014-2015 Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_RANGEPROOF_MAIN +#define SECP256K1_MODULE_RANGEPROOF_MAIN + +#include "modules/rangeproof/pedersen_impl.h" +#include "modules/rangeproof/borromean_impl.h" +#include "modules/rangeproof/rangeproof_impl.h" + +void secp256k1_pedersen_context_initialize(secp256k1_context_t* ctx) { + secp256k1_pedersen_context_build(&ctx->pedersen_ctx, &ctx->error_callback); +} + +/* Generates a pedersen commitment: *commit = blind * G + value * G2. The commitment is 33 bytes, the blinding factor is 32 bytes.*/ +int secp256k1_pedersen_commit(const secp256k1_context_t* ctx, unsigned char *commit, unsigned char *blind, uint64_t value) { + secp256k1_gej_t rj; + secp256k1_ge_t r; + secp256k1_scalar_t sec; + int sz; + int overflow; + int ret = 0; + ARG_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(secp256k1_pedersen_context_is_built(&ctx->pedersen_ctx)); + ARG_CHECK(commit != NULL); + ARG_CHECK(blind != NULL); + secp256k1_scalar_set_b32(&sec, blind, &overflow); + if (!overflow) { + secp256k1_pedersen_ecmult(&ctx->ecmult_gen_ctx, &ctx->pedersen_ctx, &rj, &sec, value); + if (!secp256k1_gej_is_infinity(&rj)) { + secp256k1_ge_set_gej(&r, &rj); + sz = 33; + ret = secp256k1_eckey_pubkey_serialize(&r, commit, &sz, 1); + } + secp256k1_gej_clear(&rj); + secp256k1_ge_clear(&r); + } + secp256k1_scalar_clear(&sec); + return ret; +} + +/** Takes a list of n pointers to 32 byte blinding values, the first negs of which are treated with positive sign and the rest + * negative, then calculates an additional blinding value that adds to zero. + */ +int secp256k1_pedersen_blind_sum(const secp256k1_context_t* ctx, unsigned char *blind_out, const unsigned char * const *blinds, int n, int npositive) { + secp256k1_scalar_t acc; + secp256k1_scalar_t x; + int i; + int overflow; + ARG_CHECK(ctx != NULL); + ARG_CHECK(blind_out != NULL); + ARG_CHECK(blinds != NULL); + secp256k1_scalar_set_int(&acc, 0); + for (i = 0; i < n; i++) { + secp256k1_scalar_set_b32(&x, blinds[i], &overflow); + if (overflow) { + return 0; + } + if (i >= npositive) { + secp256k1_scalar_negate(&x, &x); + } + secp256k1_scalar_add(&acc, &acc, &x); + } + secp256k1_scalar_get_b32(blind_out, &acc); + secp256k1_scalar_clear(&acc); + secp256k1_scalar_clear(&x); + return 1; +} + +/* Takes two list of 33-byte commitments and sums the first set and subtracts the second and verifies that they sum to excess. */ +int secp256k1_pedersen_verify_tally(const secp256k1_context_t* ctx, const unsigned char * const *commits, int pcnt, + const unsigned char * const *ncommits, int ncnt, int64_t excess) { + secp256k1_gej_t accj; + secp256k1_ge_t add; + int i; + ARG_CHECK(ctx != NULL); + ARG_CHECK(!pcnt || (commits != NULL)); + ARG_CHECK(!ncnt || (ncommits != NULL)); + ARG_CHECK(secp256k1_pedersen_context_is_built(&ctx->pedersen_ctx)); + secp256k1_gej_set_infinity(&accj); + if (excess) { + uint64_t ex; + int neg; + /* Take the absolute value, and negate the result if the input was negative. */ + neg = secp256k1_sign_and_abs64(&ex, excess); + secp256k1_pedersen_ecmult_small(&ctx->pedersen_ctx, &accj, ex); + if (neg) { + secp256k1_gej_neg(&accj, &accj); + } + } + for (i = 0; i < ncnt; i++) { + if (!secp256k1_eckey_pubkey_parse(&add, ncommits[i], 33)) { + return 0; + } + secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL); + } + secp256k1_gej_neg(&accj, &accj); + for (i = 0; i < pcnt; i++) { + if (!secp256k1_eckey_pubkey_parse(&add, commits[i], 33)) { + return 0; + } + secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL); + } + return secp256k1_gej_is_infinity(&accj); +} + +void secp256k1_rangeproof_context_initialize(secp256k1_context_t* ctx) { + secp256k1_rangeproof_context_build(&ctx->rangeproof_ctx, &ctx->error_callback); +} + +int secp256k1_rangeproof_info(const secp256k1_context_t* ctx, int *exp, int *mantissa, + uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, int plen) { + int offset; + uint64_t scale; + ARG_CHECK(exp != NULL); + ARG_CHECK(mantissa != NULL); + ARG_CHECK(min_value != NULL); + ARG_CHECK(max_value != NULL); + offset = 0; + scale = 1; + (void)ctx; + return secp256k1_rangeproof_getheader_impl(&offset, exp, mantissa, &scale, min_value, max_value, proof, plen); +} + +int secp256k1_rangeproof_rewind(const secp256k1_context_t* ctx, + unsigned char *blind_out, uint64_t *value_out, unsigned char *message_out, int *outlen, const unsigned char *nonce, + uint64_t *min_value, uint64_t *max_value, + const unsigned char *commit, const unsigned char *proof, int plen) { + ARG_CHECK(ctx != NULL); + ARG_CHECK(commit != NULL); + ARG_CHECK(proof != NULL); + ARG_CHECK(min_value != NULL); + ARG_CHECK(max_value != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(secp256k1_pedersen_context_is_built(&ctx->pedersen_ctx)); + ARG_CHECK(secp256k1_rangeproof_context_is_built(&ctx->rangeproof_ctx)); + return secp256k1_rangeproof_verify_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, &ctx->pedersen_ctx, &ctx->rangeproof_ctx, + blind_out, value_out, message_out, outlen, nonce, min_value, max_value, commit, proof, plen); +} + +int secp256k1_rangeproof_verify(const secp256k1_context_t* ctx, uint64_t *min_value, uint64_t *max_value, + const unsigned char *commit, const unsigned char *proof, int plen) { + ARG_CHECK(ctx != NULL); + ARG_CHECK(commit != NULL); + ARG_CHECK(proof != NULL); + ARG_CHECK(min_value != NULL); + ARG_CHECK(max_value != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(secp256k1_pedersen_context_is_built(&ctx->pedersen_ctx)); + ARG_CHECK(secp256k1_rangeproof_context_is_built(&ctx->rangeproof_ctx)); + return secp256k1_rangeproof_verify_impl(&ctx->ecmult_ctx, NULL, &ctx->pedersen_ctx, &ctx->rangeproof_ctx, + NULL, NULL, NULL, NULL, NULL, min_value, max_value, commit, proof, plen); +} + +int secp256k1_rangeproof_sign(const secp256k1_context_t* ctx, unsigned char *proof, int *plen, uint64_t min_value, + const unsigned char *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value){ + ARG_CHECK(ctx != NULL); + ARG_CHECK(proof != NULL); + ARG_CHECK(plen != NULL); + ARG_CHECK(commit != NULL); + ARG_CHECK(blind != NULL); + ARG_CHECK(nonce != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(secp256k1_pedersen_context_is_built(&ctx->pedersen_ctx)); + ARG_CHECK(secp256k1_rangeproof_context_is_built(&ctx->rangeproof_ctx)); + return secp256k1_rangeproof_sign_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, &ctx->pedersen_ctx, &ctx->rangeproof_ctx, + proof, plen, min_value, commit, blind, nonce, exp, min_bits, value); +} + +#endif diff --git a/src/secp256k1/src/modules/rangeproof/pedersen.h b/src/secp256k1/src/modules/rangeproof/pedersen.h new file mode 100644 index 0000000000..382d823b4f --- /dev/null +++ b/src/secp256k1/src/modules/rangeproof/pedersen.h @@ -0,0 +1,34 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_PEDERSEN_H_ +#define _SECP256K1_PEDERSEN_H_ + +#include "group.h" +#include "scalar.h" + +#include + +typedef struct { + secp256k1_ge_storage_t (*prec)[16][16]; /* prec[j][i] = 16^j * i * G + U_i */ +} secp256k1_pedersen_context_t; + +static void secp256k1_pedersen_context_init(secp256k1_pedersen_context_t* ctx); +static void secp256k1_pedersen_context_build(secp256k1_pedersen_context_t* ctx, const callback_t* cb); +static void secp256k1_pedersen_context_clone(secp256k1_pedersen_context_t *dst, + const secp256k1_pedersen_context_t* src, const callback_t* cb); +static void secp256k1_pedersen_context_clear(secp256k1_pedersen_context_t* ctx); + +static int secp256k1_pedersen_context_is_built(const secp256k1_pedersen_context_t* ctx); + +/** Multiply a small number with the generator: r = gn*G2 */ +static void secp256k1_pedersen_ecmult_small(const secp256k1_pedersen_context_t *ctx, secp256k1_gej_t *r, uint64_t gn); + +/* sec * G + value * G2. */ +static void secp256k1_pedersen_ecmult(const secp256k1_ecmult_gen_context_t *ecmult_gen_ctx, + const secp256k1_pedersen_context_t *pedersen_ctx, secp256k1_gej_t *rj, const secp256k1_scalar_t *sec, uint64_t value); + +#endif diff --git a/src/secp256k1/src/modules/rangeproof/pedersen_impl.h b/src/secp256k1/src/modules/rangeproof/pedersen_impl.h new file mode 100644 index 0000000000..e0915f4e73 --- /dev/null +++ b/src/secp256k1/src/modules/rangeproof/pedersen_impl.h @@ -0,0 +1,139 @@ +/*********************************************************************** + * Copyright (c) 2015 Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php. * + ***********************************************************************/ + +#ifndef _SECP256K1_PEDERSEN_IMPL_H_ +#define _SECP256K1_PEDERSEN_IMPL_H_ + +/** Alternative generator for secp256k1. + * This is the sha256 of 'g' after DER encoding (without compression), + * which happens to be a point on the curve. + * sage: G2 = EllipticCurve ([F (0), F (7)]).lift_x(int(hashlib.sha256('0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'.decode('hex')).hexdigest(),16)) + * sage: '%x %x'%G2.xy() + */ +static const secp256k1_ge_t secp256k1_ge_const_g2 = SECP256K1_GE_CONST( + 0x50929b74UL, 0xc1a04954UL, 0xb78b4b60UL, 0x35e97a5eUL, + 0x078a5a0fUL, 0x28ec96d5UL, 0x47bfee9aUL, 0xce803ac0UL, + 0x31d3c686UL, 0x3973926eUL, 0x049e637cUL, 0xb1b5f40aUL, + 0x36dac28aUL, 0xf1766968UL, 0xc30c2313UL, 0xf3a38904UL +); + +static void secp256k1_pedersen_context_init(secp256k1_pedersen_context_t *ctx) { + ctx->prec = NULL; +} + +static void secp256k1_pedersen_context_build(secp256k1_pedersen_context_t *ctx, const callback_t *cb) { + secp256k1_ge_t prec[256]; + secp256k1_gej_t gj; + secp256k1_gej_t nums_gej; + int i, j; + + if (ctx->prec != NULL) { + return; + } + + ctx->prec = (secp256k1_ge_storage_t (*)[16][16])checked_malloc(cb, sizeof(*ctx->prec)); + + /* get the generator */ + secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g2); + + /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */ + { + static const unsigned char nums_b32[33] = "The scalar for this x is unknown"; + secp256k1_fe_t nums_x; + secp256k1_ge_t nums_ge; + VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32)); + VERIFY_CHECK(secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0)); + secp256k1_gej_set_ge(&nums_gej, &nums_ge); + /* Add G to make the bits in x uniformly distributed. */ + secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g2, NULL); + } + + /* compute prec. */ + { + secp256k1_gej_t precj[256]; /* Jacobian versions of prec. */ + secp256k1_gej_t gbase; + secp256k1_gej_t numsbase; + gbase = gj; /* 16^j * G */ + numsbase = nums_gej; /* 2^j * nums. */ + for (j = 0; j < 16; j++) { + /* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */ + precj[j*16] = numsbase; + for (i = 1; i < 16; i++) { + secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL); + } + /* Multiply gbase by 16. */ + for (i = 0; i < 4; i++) { + secp256k1_gej_double_var(&gbase, &gbase, NULL); + } + /* Multiply numbase by 2. */ + secp256k1_gej_double_var(&numsbase, &numsbase, NULL); + if (j == 14) { + /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */ + secp256k1_gej_neg(&numsbase, &numsbase); + secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL); + } + } + secp256k1_ge_set_all_gej_var(256, prec, precj, cb); + } + for (j = 0; j < 16; j++) { + for (i = 0; i < 16; i++) { + secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]); + } + } +} + +static int secp256k1_pedersen_context_is_built(const secp256k1_pedersen_context_t* ctx) { + return ctx->prec != NULL; +} + +static void secp256k1_pedersen_context_clone(secp256k1_pedersen_context_t *dst, + const secp256k1_pedersen_context_t *src, const callback_t *cb) { + if (src->prec == NULL) { + dst->prec = NULL; + } else { + dst->prec = (secp256k1_ge_storage_t (*)[16][16])checked_malloc(cb, sizeof(*dst->prec)); + memcpy(dst->prec, src->prec, sizeof(*dst->prec)); + } +} + +static void secp256k1_pedersen_context_clear(secp256k1_pedersen_context_t *ctx) { + free(ctx->prec); + ctx->prec = NULL; +} + +/* Version of secp256k1_ecmult_gen using the second generator and working only on numbers in the range [0 .. 2^64). */ +static void secp256k1_pedersen_ecmult_small(const secp256k1_pedersen_context_t *ctx, secp256k1_gej_t *r, uint64_t gn) { + secp256k1_ge_t add; + secp256k1_ge_storage_t adds; + int bits; + int i, j; + memset(&adds, 0, sizeof(adds)); + secp256k1_gej_set_infinity(r); + add.infinity = 0; + for (j = 0; j < 16; j++) { + bits = (gn >> (j * 4)) & 15; + for (i = 0; i < 16; i++) { + secp256k1_ge_storage_cmov(&adds, &(*ctx->prec)[j][i], i == bits); + } + secp256k1_ge_from_storage(&add, &adds); + secp256k1_gej_add_ge(r, r, &add); + } + bits = 0; + secp256k1_ge_clear(&add); +} + +/* sec * G + value * G2. */ +SECP256K1_INLINE static void secp256k1_pedersen_ecmult(const secp256k1_ecmult_gen_context_t *ecmult_gen_ctx, + const secp256k1_pedersen_context_t *pedersen_ctx, secp256k1_gej_t *rj, const secp256k1_scalar_t *sec, uint64_t value) { + secp256k1_gej_t vj; + secp256k1_ecmult_gen(ecmult_gen_ctx, rj, sec); + secp256k1_pedersen_ecmult_small(pedersen_ctx, &vj, value); + /* FIXME: constant time. */ + secp256k1_gej_add_var(rj, rj, &vj, NULL); + secp256k1_gej_clear(&vj); +} + +#endif diff --git a/src/secp256k1/src/rangeproof.h b/src/secp256k1/src/modules/rangeproof/rangeproof.h similarity index 83% rename from src/secp256k1/src/rangeproof.h rename to src/secp256k1/src/modules/rangeproof/rangeproof.h index 6f34e94432..5a3e1871e3 100644 --- a/src/secp256k1/src/rangeproof.h +++ b/src/secp256k1/src/modules/rangeproof/rangeproof.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_RANGEPROOF__ -#define _SECP256K1_RANGEPROOF__ +#ifndef _SECP256K1_RANGEPROOF_H_ +#define _SECP256K1_RANGEPROOF_H_ #include "scalar.h" #include "group.h" @@ -16,15 +16,15 @@ typedef struct { static void secp256k1_rangeproof_context_init(secp256k1_rangeproof_context_t* ctx); -static void secp256k1_rangeproof_context_build(secp256k1_rangeproof_context_t* ctx); +static void secp256k1_rangeproof_context_build(secp256k1_rangeproof_context_t* ctx, const callback_t* cb); static void secp256k1_rangeproof_context_clone(secp256k1_rangeproof_context_t *dst, - const secp256k1_rangeproof_context_t* src); + const secp256k1_rangeproof_context_t* src, const callback_t* cb); static void secp256k1_rangeproof_context_clear(secp256k1_rangeproof_context_t* ctx); static int secp256k1_rangeproof_context_is_built(const secp256k1_rangeproof_context_t* ctx); static int secp256k1_rangeproof_verify_impl(const secp256k1_ecmult_context_t* ecmult_ctx, const secp256k1_ecmult_gen_context_t* ecmult_gen_ctx, - const secp256k1_ecmult_gen2_context_t* ecmult_gen2_ctx, const secp256k1_rangeproof_context_t* rangeproof_ctx, + const secp256k1_pedersen_context_t* pedersen_ctx, const secp256k1_rangeproof_context_t* rangeproof_ctx, unsigned char *blindout, uint64_t *value_out, unsigned char *message_out, int *outlen, const unsigned char *nonce, uint64_t *min_value, uint64_t *max_value, const unsigned char *commit, const unsigned char *proof, int plen); diff --git a/src/secp256k1/src/rangeproof_impl.h b/src/secp256k1/src/modules/rangeproof/rangeproof_impl.h similarity index 95% rename from src/secp256k1/src/rangeproof_impl.h rename to src/secp256k1/src/modules/rangeproof/rangeproof_impl.h index 6a3b609321..8917d2becc 100644 --- a/src/secp256k1/src/rangeproof_impl.h +++ b/src/secp256k1/src/modules/rangeproof/rangeproof_impl.h @@ -12,6 +12,9 @@ #include "rangeproof.h" #include "hash_impl.h" +#include "modules/rangeproof/pedersen.h" +#include "modules/rangeproof/borromean.h" + static const int secp256k1_rangeproof_offsets[20] = { 0, 96, 189, 276, 360, 438, 510, 579, 642, 699, 753, 801, 843, 882, 915, 942, 966, 984, @@ -22,7 +25,7 @@ static void secp256k1_rangeproof_context_init(secp256k1_rangeproof_context_t *ct ctx->prec = NULL; } -static void secp256k1_rangeproof_context_build(secp256k1_rangeproof_context_t *ctx) { +static void secp256k1_rangeproof_context_build(secp256k1_rangeproof_context_t *ctx, const callback_t* cb) { secp256k1_ge_t *prec; secp256k1_gej_t *precj; secp256k1_gej_t gj; @@ -33,11 +36,11 @@ static void secp256k1_rangeproof_context_build(secp256k1_rangeproof_context_t *c return; } - precj = (secp256k1_gej_t (*))checked_malloc(sizeof(*precj) * 1005); + precj = (secp256k1_gej_t (*))checked_malloc(cb, sizeof(*precj) * 1005); if (precj == NULL) { return; } - prec = (secp256k1_ge_t (*))checked_malloc(sizeof(*prec) * 1005); + prec = (secp256k1_ge_t (*))checked_malloc(cb, sizeof(*prec) * 1005); if (prec == NULL) { free(precj); return; @@ -73,11 +76,11 @@ static void secp256k1_rangeproof_context_build(secp256k1_rangeproof_context_t *c } } VERIFY_CHECK(pos == 1005); - secp256k1_ge_set_all_gej_var(1005, prec, precj); + secp256k1_ge_set_all_gej_var(1005, prec, precj, cb); free(precj); - ctx->prec = (secp256k1_ge_storage_t (*)[1005])checked_malloc(sizeof(*ctx->prec)); + ctx->prec = (secp256k1_ge_storage_t (*)[1005])checked_malloc(cb, sizeof(*ctx->prec)); if (ctx->prec == NULL) { free(prec); return; @@ -95,11 +98,11 @@ static int secp256k1_rangeproof_context_is_built(const secp256k1_rangeproof_cont } static void secp256k1_rangeproof_context_clone(secp256k1_rangeproof_context_t *dst, - const secp256k1_rangeproof_context_t *src) { + const secp256k1_rangeproof_context_t *src, const callback_t* cb) { if (src->prec == NULL) { dst->prec = NULL; } else { - dst->prec = (secp256k1_ge_storage_t (*)[1005])checked_malloc(sizeof(*dst->prec)); + dst->prec = (secp256k1_ge_storage_t (*)[1005])checked_malloc(cb, sizeof(*dst->prec)); memcpy(dst->prec, src->prec, sizeof(*dst->prec)); } } @@ -134,6 +137,7 @@ SECP256K1_INLINE static void secp256k1_rangeproof_pub_expand(const secp256k1_ran SECP256K1_INLINE static int secp256k1_rangeproof_genrand(secp256k1_scalar_t *sec, secp256k1_scalar_t *s, unsigned char *message, int *rsizes, int rings, const unsigned char *nonce, const unsigned char *commit, const unsigned char *proof, int len) { unsigned char tmp[32]; + unsigned char rngseed[32 + 33 + 10]; secp256k1_rfc6979_hmac_sha256_t rng; secp256k1_scalar_t acc; int overflow; @@ -142,7 +146,11 @@ SECP256K1_INLINE static int secp256k1_rangeproof_genrand(secp256k1_scalar_t *sec int j; int b; int npub; - secp256k1_rfc6979_hmac_sha256_initialize(&rng, nonce, 32, commit, 33, proof, len); + VERIFY_CHECK(len <= 10); + memcpy(rngseed, nonce, 32); + memcpy(rngseed + 32, commit, 33); + memcpy(rngseed + 65, proof, len); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, rngseed, 32 + 33 + len); secp256k1_scalar_clear(&acc); npub = 0; ret = 1; @@ -256,7 +264,7 @@ SECP256K1_INLINE static int secp256k1_range_proveparams(uint64_t *v, int *rings, /* strawman interface, writes proof in proof, a buffer of plen, proves with respect to min_value the range for commit which has the provided blinding factor and value. */ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmult_context_t* ecmult_ctx, - const secp256k1_ecmult_gen_context_t* ecmult_gen_ctx, const secp256k1_ecmult_gen2_context_t* ecmult_gen2_ctx, + const secp256k1_ecmult_gen_context_t* ecmult_gen_ctx, const secp256k1_pedersen_context_t* pedersen_ctx, const secp256k1_rangeproof_context_t* rangeproof_ctx, unsigned char *proof, int *plen, uint64_t min_value, const unsigned char *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value){ secp256k1_gej_t pubs[128]; /* Candidate digits for our proof, most inferred. */ @@ -349,7 +357,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul npub = 0; for (i = 0; i < rings; i++) { /*OPT: Use the precomputed gen2 basis?*/ - secp256k1_ecmult_gen_gen2(ecmult_gen_ctx, ecmult_gen2_ctx, &pubs[npub], &sec[i], ((uint64_t)secidx[i] * scale) << (i*2)); + secp256k1_pedersen_ecmult(ecmult_gen_ctx, pedersen_ctx, &pubs[npub], &sec[i], ((uint64_t)secidx[i] * scale) << (i*2)); if (secp256k1_gej_is_infinity(&pubs[npub])) { return 0; } @@ -588,7 +596,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_getheader_impl(int *offset, int /* Verifies range proof (len plen) for 33-byte commit, the min/max values proven are put in the min/max arguments; returns 0 on failure 1 on success.*/ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecmult_context_t* ecmult_ctx, const secp256k1_ecmult_gen_context_t* ecmult_gen_ctx, - const secp256k1_ecmult_gen2_context_t* ecmult_gen2_ctx, const secp256k1_rangeproof_context_t* rangeproof_ctx, + const secp256k1_pedersen_context_t* pedersen_ctx, const secp256k1_rangeproof_context_t* rangeproof_ctx, unsigned char *blindout, uint64_t *value_out, unsigned char *message_out, int *outlen, const unsigned char *nonce, uint64_t *min_value, uint64_t *max_value, const unsigned char *commit, const unsigned char *proof, int plen) { secp256k1_gej_t accj; @@ -651,7 +659,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm npub = 0; secp256k1_gej_set_infinity(&accj); if (*min_value) { - secp256k1_ecmult_gen2_small(ecmult_gen2_ctx, &accj, *min_value); + secp256k1_pedersen_ecmult_small(pedersen_ctx, &accj, *min_value); } for(i = 0; i < rings - 1; i++) { memcpy(&m[1], &proof[offset], 32); @@ -704,7 +712,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm /* Unwind apparently successful, see if the commitment can be reconstructed. */ /* FIXME: should check vv is in the mantissa's range. */ vv = (vv * scale) + *min_value; - secp256k1_ecmult_gen_gen2(ecmult_gen_ctx, ecmult_gen2_ctx, &accj, &blind, vv); + secp256k1_pedersen_ecmult(ecmult_gen_ctx, pedersen_ctx, &accj, &blind, vv); if (secp256k1_gej_is_infinity(&accj)) { return 0; } @@ -724,5 +732,4 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm return ret; } - #endif diff --git a/src/secp256k1/src/modules/rangeproof/tests_impl.h b/src/secp256k1/src/modules/rangeproof/tests_impl.h new file mode 100644 index 0000000000..c900c909fe --- /dev/null +++ b/src/secp256k1/src/modules/rangeproof/tests_impl.h @@ -0,0 +1,279 @@ +/********************************************************************** + * Copyright (c) 2015 Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_RANGEPROOF_TESTS +#define SECP256K1_MODULE_RANGEPROOF_TESTS + +void test_pedersen(void) { + unsigned char commits[33*19]; + const unsigned char *cptr[19]; + unsigned char blinds[32*19]; + const unsigned char *bptr[19]; + secp256k1_scalar_t s; + uint64_t values[19]; + int64_t totalv; + int i; + int inputs; + int outputs; + int total; + inputs = (secp256k1_rand32() & 7) + 1; + outputs = (secp256k1_rand32() & 7) + 2; + total = inputs + outputs; + for (i = 0; i < 19; i++) { + cptr[i] = &commits[i * 33]; + bptr[i] = &blinds[i * 32]; + } + totalv = 0; + for (i = 0; i < inputs; i++) { + values[i] = secp256k1_rands64(0, INT64_MAX - totalv); + totalv += values[i]; + } + if (secp256k1_rand32() & 1) { + for (i = 0; i < outputs; i++) { + int64_t max = INT64_MAX; + if (totalv < 0) { + max += totalv; + } + values[i + inputs] = secp256k1_rands64(0, max); + totalv -= values[i + inputs]; + } + } else { + for (i = 0; i < outputs - 1; i++) { + values[i + inputs] = secp256k1_rands64(0, totalv); + totalv -= values[i + inputs]; + } + values[total - 1] = totalv >> (secp256k1_rand32() & 1); + totalv -= values[total - 1]; + } + for (i = 0; i < total - 1; i++) { + random_scalar_order(&s); + secp256k1_scalar_get_b32(&blinds[i * 32], &s); + } + CHECK(secp256k1_pedersen_blind_sum(ctx, &blinds[(total - 1) * 32], bptr, total - 1, inputs)); + for (i = 0; i < total; i++) { + CHECK(secp256k1_pedersen_commit(ctx, &commits[i * 33], &blinds[i * 32], values[i])); + } + CHECK(secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs, totalv)); + CHECK(!secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs, totalv + 1)); + random_scalar_order(&s); + for (i = 0; i < 4; i++) { + secp256k1_scalar_get_b32(&blinds[i * 32], &s); + } + values[0] = INT64_MAX; + values[1] = 0; + values[2] = 1; + for (i = 0; i < 3; i++) { + CHECK(secp256k1_pedersen_commit(ctx, &commits[i * 33], &blinds[i * 32], values[i])); + } + CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[2], 1, -1)); + CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[2], 1, &cptr[1], 1, 1)); + CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1, 0)); + CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[1], 1, INT64_MAX)); + CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1, 0)); + CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[0], 1, -INT64_MAX)); +} + +void test_borromean(void) { + unsigned char e0[32]; + secp256k1_scalar_t s[64]; + secp256k1_gej_t pubs[64]; + secp256k1_scalar_t k[8]; + secp256k1_scalar_t sec[8]; + secp256k1_ge_t ge; + secp256k1_scalar_t one; + unsigned char m[32]; + int rsizes[8]; + int secidx[8]; + int nrings; + int i; + int j; + int c; + secp256k1_rand256_test(m); + nrings = 1 + (secp256k1_rand32()&7); + c = 0; + secp256k1_scalar_set_int(&one, 1); + if (secp256k1_rand32()&1) { + secp256k1_scalar_negate(&one, &one); + } + for (i = 0; i < nrings; i++) { + rsizes[i] = 1 + (secp256k1_rand32()&7); + secidx[i] = secp256k1_rand32() % rsizes[i]; + random_scalar_order(&sec[i]); + random_scalar_order(&k[i]); + if(secp256k1_rand32()&7) { + sec[i] = one; + } + if(secp256k1_rand32()&7) { + k[i] = one; + } + for (j = 0; j < rsizes[i]; j++) { + random_scalar_order(&s[c + j]); + if(secp256k1_rand32()&7) { + s[i] = one; + } + if (j == secidx[i]) { + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubs[c + j], &sec[i]); + } else { + random_group_element_test(&ge); + random_group_element_jacobian_test(&pubs[c + j],&ge); + } + } + c += rsizes[i]; + } + CHECK(secp256k1_borromean_sign(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, e0, s, pubs, k, sec, rsizes, secidx, nrings, m, 32)); + CHECK(secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32)); + i = secp256k1_rand32() % c; + secp256k1_scalar_negate(&s[i],&s[i]); + CHECK(!secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32)); + secp256k1_scalar_negate(&s[i],&s[i]); + secp256k1_scalar_set_int(&one, 1); + for(j = 0; j < 4; j++) { + i = secp256k1_rand32() % c; + if (secp256k1_rand32() & 1) { + secp256k1_gej_double_var(&pubs[i],&pubs[i], NULL); + } else { + secp256k1_scalar_add(&s[i],&s[i],&one); + } + CHECK(!secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32)); + } +} + +void test_rangeproof(void) { + const uint64_t testvs[11] = {0, 1, 5, 11, 65535, 65537, INT32_MAX, UINT32_MAX, INT64_MAX - 1, INT64_MAX, UINT64_MAX}; + unsigned char commit[33]; + unsigned char commit2[33]; + unsigned char proof[5134]; + unsigned char blind[32]; + unsigned char blindout[32]; + unsigned char message[4096]; + int mlen; + uint64_t v; + uint64_t vout; + uint64_t vmin; + uint64_t minv; + uint64_t maxv; + int len; + int i; + int j; + int k; + secp256k1_rand256(blind); + for (i = 0; i < 11; i++) { + v = testvs[i]; + CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v)); + for (vmin = 0; vmin < (i<9 && i > 0 ? 2 : 1); vmin++) { + len = 5134; + CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, commit, blind, commit, 0, 0, v)); + CHECK(len <= 5134); + mlen = 4096; + CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit, &minv, &maxv, commit, proof, len)); + for (j = 0; j < mlen; j++) { + CHECK(message[j] == 0); + } + CHECK(mlen <= 4096); + CHECK(memcmp(blindout, blind, 32) == 0); + CHECK(vout == v); + CHECK(minv <= v); + CHECK(maxv >= v); + len = 5134; + CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v, commit, blind, commit, -1, 64, v)); + CHECK(len <= 73); + CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit, &minv, &maxv, commit, proof, len)); + CHECK(memcmp(blindout, blind, 32) == 0); + CHECK(vout == v); + CHECK(minv == v); + CHECK(maxv == v); + } + } + secp256k1_rand256(blind); + v = INT64_MAX - 1; + CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v)); + for (i = 0; i < 19; i++) { + len = 5134; + CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, commit, blind, commit, i, 0, v)); + CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit, proof, len)); + CHECK(len <= 5134); + CHECK(minv <= v); + CHECK(maxv >= v); + } + secp256k1_rand256(blind); + { + /*Malleability test.*/ + v = secp256k1_rands64(0, 255); + CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v)); + len = 5134; + CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, commit, blind, commit, 0, 3, v)); + CHECK(len <= 5134); + for (i = 0; i < len*8; i++) { + proof[i >> 3] ^= 1 << (i & 7); + CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit, proof, len)); + proof[i >> 3] ^= 1 << (i & 7); + } + CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit, proof, len)); + CHECK(minv <= v); + CHECK(maxv >= v); + } + memcpy(commit2, commit, 33); + for (i = 0; i < 10 * count; i++) { + int exp; + int min_bits; + v = secp256k1_rands64(0, UINT64_MAX >> (secp256k1_rand32()&63)); + vmin = 0; + if ((v < INT64_MAX) && (secp256k1_rand32()&1)) { + vmin = secp256k1_rands64(0, v); + } + secp256k1_rand256(blind); + CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v)); + len = 5134; + exp = (int)secp256k1_rands64(0,18)-(int)secp256k1_rands64(0,18); + if (exp < 0) { + exp = -exp; + } + min_bits = (int)secp256k1_rands64(0,64)-(int)secp256k1_rands64(0,64); + if (min_bits < 0) { + min_bits = -min_bits; + } + CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, commit, blind, commit, exp, min_bits, v)); + CHECK(len <= 5134); + mlen = 4096; + CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit, &minv, &maxv, commit, proof, len)); + for (j = 0; j < mlen; j++) { + CHECK(message[j] == 0); + } + CHECK(mlen <= 4096); + CHECK(memcmp(blindout, blind, 32) == 0); + CHECK(vout == v); + CHECK(minv <= v); + CHECK(maxv >= v); + CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit, &minv, &maxv, commit, proof, len)); + memcpy(commit2, commit, 33); + } + for (j = 0; j < 10; j++) { + for (i = 0; i < 96; i++) { + secp256k1_rand256(&proof[i * 32]); + } + for (k = 0; k < 128; k++) { + len = k; + CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit2, proof, len)); + } + len = secp256k1_rands64(0, 3072); + CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit2, proof, len)); + } +} + +void run_rangeproof_tests(void) { + int i; + secp256k1_pedersen_context_initialize(ctx); + secp256k1_rangeproof_context_initialize(ctx); + for (i = 0; i < 10*count; i++) { + test_pedersen(); + } + for (i = 0; i < 10*count; i++) { + test_borromean(); + } + test_rangeproof(); +} + +#endif diff --git a/src/secp256k1/src/modules/schnorr/Makefile.am.include b/src/secp256k1/src/modules/schnorr/Makefile.am.include new file mode 100644 index 0000000000..bad4cb7c5b --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/Makefile.am.include @@ -0,0 +1,11 @@ +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) +bench_schnorr_verify_LDFLAGS = -static +endif diff --git a/src/secp256k1/src/modules/schnorr/main_impl.h b/src/secp256k1/src/modules/schnorr/main_impl.h new file mode 100644 index 0000000000..f5250bffd0 --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/main_impl.h @@ -0,0 +1,163 @@ +/********************************************************************** + * 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 "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[16] = "Schnorr+SHA256 "; + +int secp256k1_schnorr_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) { + secp256k1_scalar_t sec, non; + int ret = 0; + int overflow = 0; + unsigned int count = 0; + ARG_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, count, noncedata); + 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_t* ctx, const unsigned char *msg32, const unsigned char *sig64, const secp256k1_pubkey_t *pubkey) { + secp256k1_ge_t q; + ARG_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_t* ctx, const unsigned char *msg32, const unsigned char *sig64, secp256k1_pubkey_t *pubkey) { + secp256k1_ge_t q; + + ARG_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_t* ctx, const unsigned char *msg32, const unsigned char *sec32, secp256k1_nonce_function_t noncefp, const void* noncedata, secp256k1_pubkey_t *pubnonce, unsigned char *privnonce32) { + int count = 0; + int ret = 1; + secp256k1_gej_t Qj; + secp256k1_ge_t Q; + secp256k1_scalar_t sec; + + ARG_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, msg32, sec32, secp256k1_schnorr_algo16, count++, noncedata); + 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_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *sec32, const unsigned char *secnonce32, const secp256k1_pubkey_t *pubnonce_others) { + int overflow = 0; + secp256k1_scalar_t sec, non; + secp256k1_ge_t pubnon; + ARG_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_t* ctx, unsigned char *sig64, int n, const unsigned char * const *sig64sin) { + ARG_CHECK(sig64 != NULL); + ARG_CHECK(n >= 1); + ARG_CHECK(sig64sin != NULL); + return secp256k1_schnorr_sig_combine(sig64, n, sig64sin); +} + +#endif diff --git a/src/secp256k1/src/modules/schnorr/schnorr.h b/src/secp256k1/src/modules/schnorr/schnorr.h new file mode 100644 index 0000000000..34311ab0bc --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/schnorr.h @@ -0,0 +1,20 @@ +/*********************************************************************** + * 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_ +#define _SECP256K1_SCHNORR_ + +#include "scalar.h" +#include "group.h" + +typedef void (*secp256k1_schnorr_msghash_t)(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32); + +static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context_t* ctx, unsigned char *sig64, const secp256k1_scalar_t *key, const secp256k1_scalar_t *nonce, const secp256k1_ge_t *pubnonce, secp256k1_schnorr_msghash_t hash, const unsigned char *msg32); +static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context_t* ctx, const unsigned char *sig64, const secp256k1_ge_t *pubkey, secp256k1_schnorr_msghash_t hash, const unsigned char *msg32); +static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context_t* ctx, const unsigned char *sig64, secp256k1_ge_t *pubkey, secp256k1_schnorr_msghash_t hash, const unsigned char *msg32); +static int secp256k1_schnorr_sig_combine(unsigned char *sig64, int n, const unsigned char * const *sig64ins); + +#endif diff --git a/src/secp256k1/src/modules/schnorr/schnorr_impl.h b/src/secp256k1/src/modules/schnorr/schnorr_impl.h new file mode 100644 index 0000000000..e8e971fa93 --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/schnorr_impl.h @@ -0,0 +1,207 @@ +/*********************************************************************** + * 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 + +#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_t* ctx, unsigned char *sig64, const secp256k1_scalar_t *key, const secp256k1_scalar_t *nonce, const secp256k1_ge_t *pubnonce, secp256k1_schnorr_msghash_t hash, const unsigned char *msg32) { + secp256k1_gej_t Rj; + secp256k1_ge_t Ra; + unsigned char h32[32]; + secp256k1_scalar_t h, s; + int overflow; + secp256k1_scalar_t n; + + if (secp256k1_scalar_is_zero(key) || secp256k1_scalar_is_zero(nonce)) { + return 0; + } + n = *nonce; + + secp256k1_ecmult_gen(ctx, &Rj, &n); + if (pubnonce) { + 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_t* ctx, const unsigned char *sig64, const secp256k1_ge_t *pubkey, secp256k1_schnorr_msghash_t hash, const unsigned char *msg32) { + secp256k1_gej_t Qj, Rj; + secp256k1_ge_t Ra; + secp256k1_fe_t Rx; + secp256k1_scalar_t 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_t* ctx, const unsigned char *sig64, secp256k1_ge_t *pubkey, secp256k1_schnorr_msghash_t hash, const unsigned char *msg32) { + secp256k1_gej_t Qj, Rj; + secp256k1_ge_t Ra; + secp256k1_fe_t Rx; + secp256k1_scalar_t 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, int n, const unsigned char * const *sig64ins) { + secp256k1_scalar_t s = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + int i; + for (i = 0; i < n; i++) { + secp256k1_scalar_t 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 diff --git a/src/secp256k1/src/modules/schnorr/tests_impl.h b/src/secp256k1/src/modules/schnorr/tests_impl.h new file mode 100644 index 0000000000..402eb63b25 --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/tests_impl.h @@ -0,0 +1,173 @@ +/********************************************************************** + * 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 + +void test_schnorr_end_to_end(void) { + unsigned char privkey[32]; + unsigned char message[32]; + unsigned char schnorr_signature[64]; + secp256k1_pubkey_t pubkey, recpubkey; + + /* Generate a random key and message. */ + { + secp256k1_scalar_t 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, message, schnorr_signature, privkey, NULL, NULL) == 1); + CHECK(secp256k1_schnorr_verify(ctx, message, schnorr_signature, &pubkey) == 1); + CHECK(secp256k1_schnorr_recover(ctx, message, schnorr_signature, &recpubkey) == 1); + CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); + /* Destroy signature and verify again. */ + schnorr_signature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); + CHECK(secp256k1_schnorr_verify(ctx, message, schnorr_signature, &pubkey) == 0); + CHECK(secp256k1_schnorr_recover(ctx, message, schnorr_signature, &recpubkey) != 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_t pubkeyj[3]; + secp256k1_ge_t pubkey[3]; + secp256k1_scalar_t 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_rand32() % 64; + int mod = 1 + (secp256k1_rand32() % 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_t pub[5]; + unsigned char nonce[5][32]; + secp256k1_pubkey_t pubnonce[5]; + unsigned char sig[5][64]; + const unsigned char* sigs[5]; + unsigned char allsig[64]; + const secp256k1_pubkey_t* pubs[5]; + secp256k1_pubkey_t allpub; + int n, i; + int damage; + int ret = 0; + + damage = (secp256k1_rand32() % 2) ? (1 + (secp256k1_rand32() % 4)) : 0; + secp256k1_rand256_test(msg); + n = 2 + (secp256k1_rand32() % 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, msg, sec[i], NULL, NULL, &pubnonce[i], nonce[i])); + pubs[i] = &pub[i]; + } + if (damage == 1) { + nonce[secp256k1_rand32() % n][secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255); + } else if (damage == 2) { + sec[secp256k1_rand32() % n][secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255); + } + for (i = 0; i < n; i++) { + secp256k1_pubkey_t allpubnonce; + const secp256k1_pubkey_t *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, n - 1, pubnonces)); + ret |= (secp256k1_schnorr_partial_sign(ctx, msg, sig[i], sec[i], nonce[i], &allpubnonce) != 1) * 1; + sigs[i] = sig[i]; + } + if (damage == 3) { + sig[secp256k1_rand32() % n][secp256k1_rand32() % 64] ^= 1 + (secp256k1_rand32() % 255); + } + ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, n, pubs) != 1) * 2; + if ((ret & 1) == 0) { + ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, n, sigs) != 1) * 4; + } + if (damage == 4) { + allsig[secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255); + } + if ((ret & 7) == 0) { + ret |= (secp256k1_schnorr_verify(ctx, msg, allsig, &allpub) != 1) * 8; + } + CHECK((ret == 0) == (damage == 0)); +} + +void test_schnorr_recovery(void) { + unsigned char msg32[32]; + unsigned char sig64[64]; + secp256k1_ge_t 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 diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h index e9c230aed9..72e12b86fc 100644 --- a/src/secp256k1/src/scalar.h +++ b/src/secp256k1/src/scalar.h @@ -42,8 +42,8 @@ static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_ /** Add two scalars together (modulo the group order). Returns whether it overflowed. */ static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); -/** Add a power of two to a scalar. The result is not allowed to overflow. */ -static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit); +/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. */ +static void secp256k1_scalar_cadd_bit(secp256k1_scalar_t *r, unsigned int bit, int flag); /** Multiply two scalars (modulo the group order). */ static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); @@ -70,12 +70,15 @@ static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a); /** Check whether a scalar equals one. */ static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a); +/** Check whether a scalar, considered as an nonnegative integer, is even. */ +static int secp256k1_scalar_is_even(const secp256k1_scalar_t *a); + /** Check whether a scalar is higher than the group order divided by 2. */ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a); -/** Make a scalar odd, by negating it if necessary, in constant time. +/** Conditionally negate a number, in constant time. * Returns -1 if the number was negated, 1 otherwise */ -static int secp256k1_scalar_wnaf_force_odd(secp256k1_scalar_t *a); +static int secp256k1_scalar_cond_negate(secp256k1_scalar_t *a, int flag); #ifndef USE_NUM_NONE /** Convert a scalar to a number. */ @@ -92,7 +95,7 @@ static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scal /** Find r1 and r2 such that r1+r2*2^128 = a. */ static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a); /** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (see secp256k1_gej_mul_lambda). */ -static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a); +static void secp256k1_scalar_split_lambda(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a); #endif /** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h index c729869c75..09431e0df7 100644 --- a/src/secp256k1/src/scalar_4x64_impl.h +++ b/src/secp256k1/src/scalar_4x64_impl.h @@ -96,9 +96,10 @@ static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t return overflow; } -static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { +static void secp256k1_scalar_cadd_bit(secp256k1_scalar_t *r, unsigned int bit, int flag) { uint128_t t; VERIFY_CHECK(bit < 256); + bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); @@ -164,10 +165,10 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { return yes; } -static int secp256k1_scalar_wnaf_force_odd(secp256k1_scalar_t *r) { - /* If we are odd, mask = 0 and this is a no-op; - * if we are even, mask = 11...11 and this is identical to secp256k1_scalar_negate */ - uint64_t mask = (r->d[0] & 1) - 1; +static int secp256k1_scalar_cond_negate(secp256k1_scalar_t *r, int flag) { + /* If we are flag = 0, mask = 00...00 and this is a no-op; + * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ + uint64_t mask = !flag - 1; uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1; uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); r->d[0] = t & nonzero; t >>= 64; @@ -940,9 +941,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t * r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0; - if ((l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1) { - secp256k1_scalar_add_bit(r, 0); - } + secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); } #endif diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h index aa7cacc7ca..54923eb45f 100644 --- a/src/secp256k1/src/scalar_8x32_impl.h +++ b/src/secp256k1/src/scalar_8x32_impl.h @@ -136,9 +136,10 @@ static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t return overflow; } -static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { +static void secp256k1_scalar_cadd_bit(secp256k1_scalar_t *r, unsigned int bit, int flag) { uint64_t t; VERIFY_CHECK(bit < 256); + bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F)); r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F)); @@ -234,10 +235,10 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { return yes; } -static int secp256k1_scalar_wnaf_force_odd(secp256k1_scalar_t *r) { - /* If we are odd, mask = 0 and this is a no-op; - * if we are even, mask = 11...11 and this is identical to secp256k1_scalar_negate */ - uint64_t mask = (r->d[0] & 1) - 1; +static int secp256k1_scalar_cond_negate(secp256k1_scalar_t *r, int flag) { + /* If we are flag = 0, mask = 00...00 and this is a no-op; + * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ + uint32_t mask = !flag - 1; uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0); uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); r->d[0] = t & nonzero; t >>= 32; @@ -714,9 +715,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t * r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0; - if ((l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1) { - secp256k1_scalar_add_bit(r, 0); - } + secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); } #endif diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h index 33824983e4..425c0bfbda 100644 --- a/src/secp256k1/src/scalar_impl.h +++ b/src/secp256k1/src/scalar_impl.h @@ -234,18 +234,27 @@ static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scal secp256k1_scalar_mul(r, t, &x6); /* 111111 */ } +SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar_t *a) { + /* d[0] is present and is the lowest word for all representations */ + return !(a->d[0] & 1); +} + static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) { #if defined(USE_SCALAR_INV_BUILTIN) secp256k1_scalar_inverse(r, x); #elif defined(USE_SCALAR_INV_NUM) unsigned char b[32]; secp256k1_num_t n, m; - secp256k1_scalar_get_b32(b, x); + secp256k1_scalar_t t = *x; + secp256k1_scalar_get_b32(b, &t); secp256k1_num_set_bin(&n, b, 32); secp256k1_scalar_order_get_num(&m); secp256k1_num_mod_inverse(&n, &n, &m); secp256k1_num_get_bin(b, 32, &n); secp256k1_scalar_set_b32(r, b, NULL); + /* Verify that the inverse was computed correctly, without GMP code. */ + secp256k1_scalar_mul(&t, &t, r); + CHECK(secp256k1_scalar_is_one(&t)); #else #error "Please select scalar inverse implementation" #endif @@ -290,7 +299,7 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_ * The function below splits a in r1 and r2, such that r1 + lambda * r2 == a (mod order). */ -static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { +static void secp256k1_scalar_split_lambda(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { secp256k1_scalar_t c1, c2; static const secp256k1_scalar_t minus_lambda = SECP256K1_SCALAR_CONST( 0xAC9C52B3UL, 0x3FA3CF1FUL, 0x5AD9E3FDUL, 0x77ED9BA4UL, @@ -314,6 +323,7 @@ static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_ ); VERIFY_CHECK(r1 != a); VERIFY_CHECK(r2 != a); + /* these _var calls are constant time since the shift amount is constant */ secp256k1_scalar_mul_shift_var(&c1, a, &g1, 272); secp256k1_scalar_mul_shift_var(&c2, a, &g2, 272); secp256k1_scalar_mul(&c1, &c1, &minus_b1); diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c index 95f5fb9f99..fcbecedaf1 100644 --- a/src/secp256k1/src/secp256k1.c +++ b/src/secp256k1/src/secp256k1.c @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille, Gregory Maxwell * + * Copyright (c) 2013-2015 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ @@ -13,101 +13,305 @@ #include "field_impl.h" #include "scalar_impl.h" #include "group_impl.h" -#include "ecdsa_impl.h" -#include "ecdh_impl.h" #include "ecmult_impl.h" +#include "ecmult_const_impl.h" #include "ecmult_gen_impl.h" #include "ecdsa_impl.h" -#include "schnorr_impl.h" #include "eckey_impl.h" #include "hash_impl.h" -#include "borromean_impl.h" -#include "rangeproof_impl.h" + +#ifdef ENABLE_MODULE_RANGEPROOF +# include "modules/rangeproof/pedersen.h" +# include "modules/rangeproof/rangeproof.h" +#endif + +#define ARG_CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + ctx->illegal_callback.fn(#cond, ctx->illegal_callback.data); \ + return 0; \ + } \ +} while(0) + +static void default_illegal_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); + abort(); +} + +static const callback_t default_illegal_callback = { + default_illegal_callback_fn, + NULL +}; + +static void default_error_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); + abort(); +} + +static const callback_t default_error_callback = { + default_error_callback_fn, + NULL +}; + struct secp256k1_context_struct { secp256k1_ecmult_context_t ecmult_ctx; secp256k1_ecmult_gen_context_t ecmult_gen_ctx; - secp256k1_ecmult_gen2_context_t ecmult_gen2_ctx; +#ifdef ENABLE_MODULE_RANGEPROOF + secp256k1_pedersen_context_t pedersen_ctx; secp256k1_rangeproof_context_t rangeproof_ctx; +#endif + callback_t illegal_callback; + callback_t error_callback; }; secp256k1_context_t* secp256k1_context_create(int flags) { - secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(sizeof(secp256k1_context_t)); + secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(&default_error_callback, sizeof(secp256k1_context_t)); + ret->illegal_callback = default_illegal_callback; + ret->error_callback = default_error_callback; secp256k1_ecmult_context_init(&ret->ecmult_ctx); secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx); - secp256k1_ecmult_gen2_context_init(&ret->ecmult_gen2_ctx); +#ifdef ENABLE_MODULE_RANGEPROOF + secp256k1_pedersen_context_init(&ret->pedersen_ctx); secp256k1_rangeproof_context_init(&ret->rangeproof_ctx); +#endif if (flags & SECP256K1_CONTEXT_SIGN) { - secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx); + secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback); } if (flags & SECP256K1_CONTEXT_VERIFY) { - secp256k1_ecmult_context_build(&ret->ecmult_ctx); - } - if (flags & SECP256K1_CONTEXT_COMMIT) { - secp256k1_ecmult_gen2_context_build(&ret->ecmult_gen2_ctx); - } - if (flags & SECP256K1_CONTEXT_RANGEPROOF) { - secp256k1_rangeproof_context_build(&ret->rangeproof_ctx); + secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback); } return ret; } secp256k1_context_t* secp256k1_context_clone(const secp256k1_context_t* ctx) { - secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(sizeof(secp256k1_context_t)); - secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx); - secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx); - secp256k1_ecmult_gen2_context_clone(&ret->ecmult_gen2_ctx, &ctx->ecmult_gen2_ctx); - secp256k1_rangeproof_context_clone(&ret->rangeproof_ctx, &ctx->rangeproof_ctx); + secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_context_t)); + ret->illegal_callback = ctx->illegal_callback; + ret->error_callback = ctx->error_callback; + secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx, &ctx->error_callback); + secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx, &ctx->error_callback); +#ifdef ENABLE_MODULE_RANGEPROOF + secp256k1_pedersen_context_clone(&ret->pedersen_ctx, &ctx->pedersen_ctx, &ctx->error_callback); + secp256k1_rangeproof_context_clone(&ret->rangeproof_ctx, &ctx->rangeproof_ctx, &ctx->error_callback); +#endif return ret; } void secp256k1_context_destroy(secp256k1_context_t* ctx) { secp256k1_ecmult_context_clear(&ctx->ecmult_ctx); secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); - secp256k1_ecmult_gen2_context_clear(&ctx->ecmult_gen2_ctx); +#ifdef ENABLE_MODULE_RANGEPROOF + secp256k1_pedersen_context_clear(&ctx->pedersen_ctx); secp256k1_rangeproof_context_clear(&ctx->rangeproof_ctx); +#endif free(ctx); } -int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) { - secp256k1_ge_t q; - secp256k1_ecdsa_sig_t s; - secp256k1_scalar_t m; - int ret = -3; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(sig != NULL); - DEBUG_CHECK(pubkey != NULL); +void secp256k1_context_set_illegal_callback(secp256k1_context_t* ctx, void (*fun)(const char* message, void* data), void* data) { + ctx->illegal_callback.fn = fun; + ctx->illegal_callback.data = data; +} - secp256k1_scalar_set_b32(&m, msg32, NULL); +void secp256k1_context_set_error_callback(secp256k1_context_t* ctx, void (*fun)(const char* message, void* data), void* data) { + ctx->error_callback.fn = fun; + ctx->error_callback.data = data; +} - if (secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) { - if (secp256k1_ecdsa_sig_parse(&s, sig, siglen)) { - if (secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &s, &q, &m)) { - /* success is 1, all other values are fail */ - ret = 1; - } else { - ret = 0; - } - } else { - ret = -2; - } +static int secp256k1_pubkey_load(const secp256k1_context_t* ctx, secp256k1_ge_t* ge, const secp256k1_pubkey_t* pubkey) { + if (sizeof(secp256k1_ge_storage_t) == 64) { + /* When the secp256k1_ge_storage_t type is exactly 64 byte, use its + * representation inside secp256k1_pubkey_t, as conversion is very fast. + * Note that secp256k1_pubkey_save must use the same representation. */ + secp256k1_ge_storage_t s; + memcpy(&s, &pubkey->data[0], 64); + secp256k1_ge_from_storage(ge, &s); } else { - ret = -1; + /* Otherwise, fall back to 32-byte big endian for X and Y. */ + secp256k1_fe_t x, y; + secp256k1_fe_set_b32(&x, pubkey->data); + secp256k1_fe_set_b32(&y, pubkey->data + 32); + secp256k1_ge_set_xy(ge, &x, &y); } + ARG_CHECK(!secp256k1_fe_is_zero(&ge->x)); + return 1; +} +static void secp256k1_pubkey_save(secp256k1_pubkey_t* pubkey, secp256k1_ge_t* ge) { + if (sizeof(secp256k1_ge_storage_t) == 64) { + secp256k1_ge_storage_t s; + secp256k1_ge_to_storage(&s, ge); + memcpy(&pubkey->data[0], &s, 64); + } else { + VERIFY_CHECK(!secp256k1_ge_is_infinity(ge)); + secp256k1_fe_normalize_var(&ge->x); + secp256k1_fe_normalize_var(&ge->y); + secp256k1_fe_get_b32(pubkey->data, &ge->x); + secp256k1_fe_get_b32(pubkey->data + 32, &ge->y); + } +} + +int secp256k1_ec_pubkey_parse(const secp256k1_context_t* ctx, secp256k1_pubkey_t* pubkey, const unsigned char *input, int inputlen) { + secp256k1_ge_t Q; + + (void)ctx; + if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) { + memset(pubkey, 0, sizeof(*pubkey)); + return 0; + } + secp256k1_pubkey_save(pubkey, &Q); + secp256k1_ge_clear(&Q); + return 1; +} + +int secp256k1_ec_pubkey_serialize(const secp256k1_context_t* ctx, unsigned char *output, int *outputlen, const secp256k1_pubkey_t* pubkey, int compressed) { + secp256k1_ge_t Q; + + (void)ctx; + return (secp256k1_pubkey_load(ctx, &Q, pubkey) && + secp256k1_eckey_pubkey_serialize(&Q, output, outputlen, compressed)); +} + +static void secp256k1_ecdsa_signature_load(const secp256k1_context_t* ctx, secp256k1_scalar_t* r, secp256k1_scalar_t* s, int* recid, const secp256k1_ecdsa_signature_t* sig) { + (void)ctx; + if (sizeof(secp256k1_scalar_t) == 32) { + /* When the secp256k1_scalar_t type is exactly 32 byte, use its + * representation inside secp256k1_ecdsa_signature_t, as conversion is very fast. + * Note that secp256k1_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + secp256k1_scalar_set_b32(r, &sig->data[0], NULL); + secp256k1_scalar_set_b32(s, &sig->data[32], NULL); + } + if (recid) { + *recid = sig->data[64]; + } +} + +static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature_t* sig, const secp256k1_scalar_t* r, const secp256k1_scalar_t* s, int recid) { + if (sizeof(secp256k1_scalar_t) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + secp256k1_scalar_get_b32(&sig->data[0], r); + secp256k1_scalar_get_b32(&sig->data[32], s); + } + sig->data[64] = recid; +} + +int secp256k1_ecdsa_signature_parse_der(const secp256k1_context_t* ctx, secp256k1_ecdsa_signature_t* sig, const unsigned char *input, int inputlen) { + secp256k1_scalar_t r, s; + + (void)ctx; + ARG_CHECK(sig != NULL); + ARG_CHECK(input != NULL); + + if (secp256k1_ecdsa_sig_parse(&r, &s, input, inputlen)) { + secp256k1_ecdsa_signature_save(sig, &r, &s, -1); + return 1; + } else { + memset(sig, 0, sizeof(*sig)); + return 0; + } +} + +int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context_t* ctx, secp256k1_ecdsa_signature_t* sig, const unsigned char *input64, int recid) { + secp256k1_scalar_t r, s; + int ret = 1; + int overflow = 0; + + (void)ctx; + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + + secp256k1_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + secp256k1_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + ret &= (recid == -1 || (recid >= 0 && recid < 4)); + if (ret) { + secp256k1_ecdsa_signature_save(sig, &r, &s, recid); + } else { + memset(sig, 0, sizeof(*sig)); + } return ret; } -static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { +int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context_t* ctx, unsigned char *output, int *outputlen, const secp256k1_ecdsa_signature_t* sig) { + secp256k1_scalar_t r, s; + + (void)ctx; + ARG_CHECK(output != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(sig != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, NULL, sig); + return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s); +} + +int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context_t* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_signature_t* sig) { + secp256k1_scalar_t r, s; + int rec; + + (void)ctx; + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, &rec, sig); + secp256k1_scalar_get_b32(&output64[0], &r); + secp256k1_scalar_get_b32(&output64[32], &s); + if (recid) { + ARG_CHECK(rec >= 0 && rec < 4); + *recid = rec; + } + return 1; +} + +int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const secp256k1_ecdsa_signature_t *sig, const secp256k1_pubkey_t *pubkey) { + secp256k1_ge_t q; + secp256k1_scalar_t r, s; + secp256k1_scalar_t m; + ARG_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(pubkey != NULL); + + secp256k1_scalar_set_b32(&m, msg32, NULL); + secp256k1_ecdsa_signature_load(ctx, &r, &s, NULL, sig); + return (secp256k1_pubkey_load(ctx, &q, pubkey) && + secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m)); +} + +static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, unsigned int counter, const void *data) { + unsigned char keydata[112]; + int keylen = 64; secp256k1_rfc6979_hmac_sha256_t rng; unsigned int i; - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key32, 32, msg32, 32, (const unsigned char*)data, data != NULL ? 32 : 0); + /* We feed a byte array to the PRNG as input, consisting of: + * - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d. + * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data. + * - optionally 16 extra bytes with the algorithm name (the extra data bytes + * are set to zeroes when not present, while the algorithm name is). + */ + memcpy(keydata, key32, 32); + memcpy(keydata + 32, msg32, 32); + if (data != NULL) { + memcpy(keydata + 64, data, 32); + keylen = 96; + } + if (algo16 != NULL) { + memset(keydata + keylen, 0, 96 - keylen); + memcpy(keydata + 96, algo16, 16); + keylen = 112; + } + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, keylen); + memset(keydata, 0, sizeof(keydata)); for (i = 0; i <= counter; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); } @@ -118,18 +322,18 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; const secp256k1_nonce_function_t secp256k1_nonce_function_default = nonce_function_rfc6979; -int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *signature, int *signaturelen, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) { - secp256k1_ecdsa_sig_t sig; +int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, secp256k1_ecdsa_signature_t *signature, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) { + secp256k1_scalar_t r, s; secp256k1_scalar_t sec, non, msg; + int recid; int ret = 0; int overflow = 0; unsigned int count = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(signature != NULL); - DEBUG_CHECK(signaturelen != NULL); - DEBUG_CHECK(seckey != NULL); + ARG_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); if (noncefp == NULL) { noncefp = secp256k1_nonce_function_default; } @@ -140,140 +344,60 @@ int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *ms secp256k1_scalar_set_b32(&msg, msg32, NULL); while (1) { unsigned char nonce32[32]; - ret = noncefp(nonce32, msg32, seckey, count, noncedata); + ret = noncefp(nonce32, msg32, seckey, NULL, count, noncedata); 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, &sig, &sec, &msg, &non, NULL)) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) { break; } } count++; } - if (ret) { - ret = secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig); - } secp256k1_scalar_clear(&msg); secp256k1_scalar_clear(&non); secp256k1_scalar_clear(&sec); } - if (!ret) { - *signaturelen = 0; - } - return ret; -} - -int secp256k1_ecdsa_sign_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata, int *recid) { - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_t sec, non, msg; - int ret = 0; - int overflow = 0; - unsigned int count = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(sig64 != NULL); - DEBUG_CHECK(seckey != NULL); - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_default; - } - - secp256k1_scalar_set_b32(&sec, seckey, &overflow); - /* Fail if the secret key is invalid. */ - if (!overflow && !secp256k1_scalar_is_zero(&sec)) { - secp256k1_scalar_set_b32(&msg, msg32, NULL); - while (1) { - unsigned char nonce32[32]; - ret = noncefp(nonce32, msg32, seckey, count, noncedata); - 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, &sig, &sec, &msg, &non, recid)) { - break; - } - } - count++; - } - if (ret) { - secp256k1_scalar_get_b32(sig64, &sig.r); - secp256k1_scalar_get_b32(sig64 + 32, &sig.s); - } - secp256k1_scalar_clear(&msg); - secp256k1_scalar_clear(&non); - secp256k1_scalar_clear(&sec); - } - if (!ret) { - memset(sig64, 0, 64); - } - return ret; -} - -int secp256k1_ecdsa_recover_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid) { - secp256k1_ge_t q; - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_t m; - int ret = 0; - int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(sig64 != NULL); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); - DEBUG_CHECK(recid >= 0 && recid <= 3); - - secp256k1_scalar_set_b32(&sig.r, sig64, &overflow); - if (!overflow) { - secp256k1_scalar_set_b32(&sig.s, sig64 + 32, &overflow); - if (!overflow) { - secp256k1_scalar_set_b32(&m, msg32, NULL); - - if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &sig, &q, &m, recid)) { - ret = secp256k1_eckey_pubkey_serialize(&q, pubkey, pubkeylen, compressed); - } - } - } - return ret; -} - -int secp256k1_point_multiply(unsigned char *point, int *pointlen, const unsigned char *scalar) { - int ret = 0; - int overflow = 0; - secp256k1_gej_t res; - secp256k1_ge_t pt; - secp256k1_scalar_t s; - DEBUG_CHECK(point != NULL); - DEBUG_CHECK(pointlen != NULL); - DEBUG_CHECK(scalar != NULL); - - if (secp256k1_eckey_pubkey_parse(&pt, point, *pointlen)) { - secp256k1_scalar_set_b32(&s, scalar, &overflow); - if (overflow) { - ret = -2; - } else { - secp256k1_ecdh_point_multiply(&res, &pt, &s); - secp256k1_ge_set_gej(&pt, &res); - ret = secp256k1_eckey_pubkey_serialize(&pt, point, pointlen, *pointlen <= 33); - } + if (ret) { + secp256k1_ecdsa_signature_save(signature, &r, &s, recid); } else { - ret = -3; + memset(signature, 0, sizeof(*signature)); } - secp256k1_scalar_clear(&s); return ret; } +int secp256k1_ecdsa_recover(const secp256k1_context_t* ctx, const unsigned char *msg32, const secp256k1_ecdsa_signature_t *signature, secp256k1_pubkey_t *pubkey) { + secp256k1_ge_t q; + secp256k1_scalar_t r, s; + secp256k1_scalar_t m; + int recid; + ARG_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(pubkey != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, &recid, signature); + ARG_CHECK(recid >= 0 && recid < 4); + secp256k1_scalar_set_b32(&m, msg32, NULL); + if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) { + secp256k1_pubkey_save(pubkey, &q); + return 1; + } else { + memset(pubkey, 0, sizeof(*pubkey)); + return 0; + } +} + int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned char *seckey) { secp256k1_scalar_t sec; int ret; int overflow; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(seckey != NULL); + ARG_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); (void)ctx; secp256k1_scalar_set_b32(&sec, seckey, &overflow); @@ -282,49 +406,25 @@ int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned ch return ret; } -int secp256k1_ec_pubkey_verify(const secp256k1_context_t* ctx, const unsigned char *pubkey, int pubkeylen) { - secp256k1_ge_t q; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(pubkey != NULL); - (void)ctx; - - return secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen); -} - -int secp256k1_ec_pubkey_create(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) { +int secp256k1_ec_pubkey_create(const secp256k1_context_t* ctx, secp256k1_pubkey_t *pubkey, const unsigned char *seckey) { secp256k1_gej_t pj; secp256k1_ge_t p; secp256k1_scalar_t sec; int overflow; int ret = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); - DEBUG_CHECK(seckey != NULL); + ARG_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(seckey != NULL); secp256k1_scalar_set_b32(&sec, seckey, &overflow); - if (!overflow) { - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); - secp256k1_scalar_clear(&sec); - secp256k1_ge_set_gej(&p, &pj); - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, compressed); - } + ret = !overflow & !secp256k1_scalar_is_zero(&sec); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); + secp256k1_ge_set_gej(&p, &pj); + secp256k1_pubkey_save(pubkey, &p); + secp256k1_scalar_clear(&sec); if (!ret) { - *pubkeylen = 0; - } - return ret; -} - -int secp256k1_ec_pubkey_decompress(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen) { - secp256k1_ge_t p; - int ret = 0; - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); - (void)ctx; - - if (secp256k1_eckey_pubkey_parse(&p, pubkey, *pubkeylen)) { - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, 0); + memset(pubkey, 0, sizeof(*pubkey)); } return ret; } @@ -334,9 +434,9 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char secp256k1_scalar_t sec; int ret = 0; int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(tweak != NULL); + ARG_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak != NULL); (void)ctx; secp256k1_scalar_set_b32(&term, tweak, &overflow); @@ -352,26 +452,23 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char return ret; } -int secp256k1_ec_pubkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { +int secp256k1_ec_pubkey_tweak_add(const secp256k1_context_t* ctx, secp256k1_pubkey_t *pubkey, const unsigned char *tweak) { secp256k1_ge_t p; secp256k1_scalar_t term; int ret = 0; int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(tweak != NULL); + ARG_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak != NULL); secp256k1_scalar_set_b32(&term, tweak, &overflow); - if (!overflow) { - ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); + if (!overflow && secp256k1_pubkey_load(ctx, &p, pubkey)) { + ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term); if (ret) { - ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term); - } - if (ret) { - int oldlen = pubkeylen; - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33); - VERIFY_CHECK(pubkeylen == oldlen); + secp256k1_pubkey_save(pubkey, &p); + } else { + memset(pubkey, 0, sizeof(*pubkey)); } } @@ -383,9 +480,9 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char secp256k1_scalar_t sec; int ret = 0; int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(tweak != NULL); + ARG_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak != NULL); (void)ctx; secp256k1_scalar_set_b32(&factor, tweak, &overflow); @@ -400,26 +497,23 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char return ret; } -int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { +int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, secp256k1_pubkey_t *pubkey, const unsigned char *tweak) { secp256k1_ge_t p; secp256k1_scalar_t factor; int ret = 0; int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(tweak != NULL); + ARG_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak != NULL); secp256k1_scalar_set_b32(&factor, tweak, &overflow); - if (!overflow) { - ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); + if (!overflow && secp256k1_pubkey_load(ctx, &p, pubkey)) { + ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor); if (ret) { - ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor); - } - if (ret) { - int oldlen = pubkeylen; - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33); - VERIFY_CHECK(pubkeylen == oldlen); + secp256k1_pubkey_save(pubkey, &p); + } else { + memset(pubkey, 0, sizeof(*pubkey)); } } @@ -429,11 +523,11 @@ int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char int secp256k1_ec_privkey_export(const secp256k1_context_t* ctx, const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed) { secp256k1_scalar_t key; int ret = 0; - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(privkey != NULL); - DEBUG_CHECK(privkeylen != NULL); - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey != NULL); + ARG_CHECK(privkey != NULL); + ARG_CHECK(privkeylen != NULL); + ARG_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); secp256k1_scalar_set_b32(&key, seckey, NULL); ret = secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, privkeylen, &key, compressed); @@ -444,8 +538,8 @@ int secp256k1_ec_privkey_export(const secp256k1_context_t* ctx, const unsigned c int secp256k1_ec_privkey_import(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *privkey, int privkeylen) { secp256k1_scalar_t key; int ret = 0; - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(privkey != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(privkey != NULL); (void)ctx; ret = secp256k1_eckey_privkey_parse(&key, privkey, privkeylen); @@ -457,241 +551,44 @@ int secp256k1_ec_privkey_import(const secp256k1_context_t* ctx, unsigned char *s } int secp256k1_context_randomize(secp256k1_context_t* ctx, const unsigned char *seed32) { - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); return 1; } -/* Generates a pedersen commitment: *commit = blind * G + value * G2. The commitment is 33 bytes, the blinding factor is 32 bytes.*/ -int secp256k1_pedersen_commit(const secp256k1_context_t* ctx, unsigned char *commit, unsigned char *blind, uint64_t value) { - secp256k1_gej_t rj; - secp256k1_ge_t r; - secp256k1_scalar_t sec; - int sz; - int overflow; - int ret = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(secp256k1_ecmult_gen2_context_is_built(&ctx->ecmult_gen2_ctx)); - DEBUG_CHECK(commit != NULL); - DEBUG_CHECK(blind != NULL); - secp256k1_scalar_set_b32(&sec, blind, &overflow); - if (!overflow) { - secp256k1_ecmult_gen_gen2(&ctx->ecmult_gen_ctx, &ctx->ecmult_gen2_ctx, &rj, &sec, value); - if (!secp256k1_gej_is_infinity(&rj)) { - secp256k1_ge_set_gej(&r, &rj); - sz = 33; - ret = secp256k1_eckey_pubkey_serialize(&r, commit, &sz, 1); - } - secp256k1_gej_clear(&rj); - secp256k1_ge_clear(&r); - } - secp256k1_scalar_clear(&sec); - return ret; -} - -/** Takes a list of n pointers to 32 byte blinding values, the first negs of which are treated with positive sign and the rest - * negative, then calculates an additional blinding value that adds to zero. - */ -int secp256k1_pedersen_blind_sum(const secp256k1_context_t* ctx, unsigned char *blind_out, const unsigned char * const *blinds, int n, int npositive) { - secp256k1_scalar_t acc; - secp256k1_scalar_t x; +int secp256k1_ec_pubkey_combine(const secp256k1_context_t* ctx, secp256k1_pubkey_t *pubnonce, int n, const secp256k1_pubkey_t * const *pubnonces) { int i; - int overflow; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(blind_out != NULL); - DEBUG_CHECK(blinds != NULL); - secp256k1_scalar_set_int(&acc, 0); + secp256k1_gej_t Qj; + secp256k1_ge_t Q; + + ARG_CHECK(pubnonce != NULL); + ARG_CHECK(n >= 1); + ARG_CHECK(pubnonces != NULL); + + secp256k1_gej_set_infinity(&Qj); + for (i = 0; i < n; i++) { - secp256k1_scalar_set_b32(&x, blinds[i], &overflow); - if (overflow) { - return 0; - } - if (i >= npositive) { - secp256k1_scalar_negate(&x, &x); - } - secp256k1_scalar_add(&acc, &acc, &x); + secp256k1_pubkey_load(ctx, &Q, pubnonces[i]); + secp256k1_gej_add_ge(&Qj, &Qj, &Q); } - secp256k1_scalar_get_b32(blind_out, &acc); - secp256k1_scalar_clear(&acc); - secp256k1_scalar_clear(&x); - return 1; -} -/* Takes two list of 33-byte commitments and sums the first set and subtracts the second and verifies that they sum to excess. */ -int secp256k1_pedersen_verify_tally(const secp256k1_context_t* ctx, const unsigned char * const *commits, int pcnt, - const unsigned char * const *ncommits, int ncnt, int64_t excess) { - secp256k1_gej_t accj; - secp256k1_ge_t add; - int i; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(!pcnt || (commits != NULL)); - DEBUG_CHECK(!ncnt || (ncommits != NULL)); - DEBUG_CHECK(secp256k1_ecmult_gen2_context_is_built(&ctx->ecmult_gen2_ctx)); - secp256k1_gej_set_infinity(&accj); - if (excess) { - uint64_t ex; - int neg; - /* Take the absolute value, and negate the result if the input was negative. */ - neg = secp256k1_sign_and_abs64(&ex, excess); - secp256k1_ecmult_gen2_small(&ctx->ecmult_gen2_ctx, &accj, ex); - if (neg) { - secp256k1_gej_neg(&accj, &accj); - } - } - for (i = 0; i < ncnt; i++) { - if (!secp256k1_eckey_pubkey_parse(&add, ncommits[i], 33)) { - return 0; - } - secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL); - } - secp256k1_gej_neg(&accj, &accj); - for (i = 0; i < pcnt; i++) { - if (!secp256k1_eckey_pubkey_parse(&add, commits[i], 33)) { - return 0; - } - secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL); - } - return secp256k1_gej_is_infinity(&accj); -} - -int secp256k1_rangeproof_info(const secp256k1_context_t* ctx, int *exp, int *mantissa, - uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, int plen) { - int offset; - uint64_t scale; - DEBUG_CHECK(exp != NULL); - DEBUG_CHECK(mantissa != NULL); - DEBUG_CHECK(min_value != NULL); - DEBUG_CHECK(max_value != NULL); - offset = 0; - scale = 1; - (void)ctx; - return secp256k1_rangeproof_getheader_impl(&offset, exp, mantissa, &scale, min_value, max_value, proof, plen); -} - -int secp256k1_rangeproof_rewind(const secp256k1_context_t* ctx, - unsigned char *blind_out, uint64_t *value_out, unsigned char *message_out, int *outlen, const unsigned char *nonce, - uint64_t *min_value, uint64_t *max_value, - const unsigned char *commit, const unsigned char *proof, int plen) { - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(commit != NULL); - DEBUG_CHECK(proof != NULL); - DEBUG_CHECK(min_value != NULL); - DEBUG_CHECK(max_value != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(secp256k1_ecmult_gen2_context_is_built(&ctx->ecmult_gen2_ctx)); - DEBUG_CHECK(secp256k1_rangeproof_context_is_built(&ctx->rangeproof_ctx)); - return secp256k1_rangeproof_verify_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, &ctx->ecmult_gen2_ctx, &ctx->rangeproof_ctx, - blind_out, value_out, message_out, outlen, nonce, min_value, max_value, commit, proof, plen); -} - -int secp256k1_rangeproof_verify(const secp256k1_context_t* ctx, uint64_t *min_value, uint64_t *max_value, - const unsigned char *commit, const unsigned char *proof, int plen) { - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(commit != NULL); - DEBUG_CHECK(proof != NULL); - DEBUG_CHECK(min_value != NULL); - DEBUG_CHECK(max_value != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(secp256k1_ecmult_gen2_context_is_built(&ctx->ecmult_gen2_ctx)); - DEBUG_CHECK(secp256k1_rangeproof_context_is_built(&ctx->rangeproof_ctx)); - return secp256k1_rangeproof_verify_impl(&ctx->ecmult_ctx, NULL, &ctx->ecmult_gen2_ctx, &ctx->rangeproof_ctx, - NULL, NULL, NULL, NULL, NULL, min_value, max_value, commit, proof, plen); -} - -int secp256k1_rangeproof_sign(const secp256k1_context_t* ctx, unsigned char *proof, int *plen, uint64_t min_value, - const unsigned char *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value){ - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(proof != NULL); - DEBUG_CHECK(plen != NULL); - DEBUG_CHECK(commit != NULL); - DEBUG_CHECK(blind != NULL); - DEBUG_CHECK(nonce != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(secp256k1_ecmult_gen2_context_is_built(&ctx->ecmult_gen2_ctx)); - DEBUG_CHECK(secp256k1_rangeproof_context_is_built(&ctx->rangeproof_ctx)); - return secp256k1_rangeproof_sign_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, &ctx->ecmult_gen2_ctx, &ctx->rangeproof_ctx, - proof, plen, min_value, commit, blind, nonce, exp, min_bits, value); -} - -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); -} - -int secp256k1_schnorr_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) { - secp256k1_scalar_t sec, non; - int ret = 0; - int overflow = 0; - unsigned int count = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(sig64 != NULL); - DEBUG_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, count, noncedata); - 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, secp256k1_schnorr_msghash_sha256, msg32)) { - break; - } - } - count++; - } - secp256k1_scalar_clear(&non); - secp256k1_scalar_clear(&sec); - return ret; -} - -int secp256k1_schnorr_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig64, const unsigned char *pubkey, int pubkeylen) { - secp256k1_ge_t q; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(sig64 != NULL); - DEBUG_CHECK(pubkey != NULL); - - if (!secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) { + if (secp256k1_gej_is_infinity(&Qj)) { + memset(pubnonce, 0, sizeof(*pubnonce)); return 0; } - return secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32); + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(pubnonce, &Q); + return 1; } -int secp256k1_schnorr_verify_batch(const secp256k1_context_t* ctx, int n, const unsigned char *msg32, const unsigned char **sig64, const unsigned char **pubkey, const int *pubkeylen) { - secp256k1_ge_t q[SECP256K1_SCHNORR_MAX_BATCH]; - unsigned char sig[SECP256K1_SCHNORR_MAX_BATCH][64]; - int k; +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/main_impl.h" +#endif - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(sig64 != NULL); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); - DEBUG_CHECK(n <= SECP256K1_SCHNORR_MAX_BATCH); +#ifdef ENABLE_MODULE_SCHNORR +# include "modules/schnorr/main_impl.h" +#endif - for (k = 0; k < n; k++) { - memcpy(&sig[k], sig64[k], 64); - if (!secp256k1_eckey_pubkey_parse(&q[k], pubkey[k], pubkeylen[k])) { - return 0; - } - } - - return secp256k1_schnorr_sig_verify_batch(&ctx->ecmult_ctx, n, sig, q, secp256k1_schnorr_msghash_sha256, msg32); -} +#ifdef ENABLE_MODULE_RANGEPROOF +# include "modules/rangeproof/main_impl.h" +#endif diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h index 041bb92c47..a3d73dce7e 100644 --- a/src/secp256k1/src/testrand.h +++ b/src/secp256k1/src/testrand.h @@ -25,4 +25,7 @@ static void secp256k1_rand256(unsigned char *b32); /** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */ static void secp256k1_rand256_test(unsigned char *b32); +/** Generate a pseudorandom 64-bit integer in the range min..max, inclusive. */ +static int64_t secp256k1_rands64(uint64_t min, uint64_t max); + #endif diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h index 8d99306576..af70471cd4 100644 --- a/src/secp256k1/src/testrand_impl.h +++ b/src/secp256k1/src/testrand_impl.h @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * Copyright (c) 2013-2015 Pieter Wuille, Gregory Maxwell * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ @@ -18,7 +18,7 @@ static uint32_t secp256k1_test_rng_precomputed[8]; static int secp256k1_test_rng_precomputed_used = 8; SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16) { - secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, (const unsigned char*)"TestRNG", 7, seed16, 16, NULL, 0); + secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, seed16, 16); } SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { @@ -29,23 +29,6 @@ SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { return secp256k1_test_rng_precomputed[secp256k1_test_rng_precomputed_used++]; } -SECP256K1_INLINE static int64_t secp256k1_rands64(uint64_t min, uint64_t max) { - uint64_t range; - uint64_t r; - uint64_t clz; - DEBUG_CHECK(max >= min); - if (max == min) { - return min; - } - range = max - min; - clz = secp256k1_clz64_var(range); - do { - r = ((uint64_t)secp256k1_rand32() << 32) | secp256k1_rand32(); - r >>= clz; - } while (r > range); - return min + (int64_t)r; -} - static void secp256k1_rand256(unsigned char *b32) { secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32); } @@ -74,4 +57,21 @@ static void secp256k1_rand256_test(unsigned char *b32) { } } +SECP256K1_INLINE static int64_t secp256k1_rands64(uint64_t min, uint64_t max) { + uint64_t range; + uint64_t r; + uint64_t clz; + VERIFY_CHECK(max >= min); + if (max == min) { + return min; + } + range = max - min; + clz = secp256k1_clz64_var(range); + do { + r = ((uint64_t)secp256k1_rand32() << 32) | secp256k1_rand32(); + r >>= clz; + } while (r > range); + return min + (int64_t)r; +} + #endif diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c index 258ea917ce..2d5f7c146c 100644 --- a/src/secp256k1/src/tests.c +++ b/src/secp256k1/src/tests.c @@ -13,6 +13,7 @@ #include +#include "include/secp256k1.h" #include "secp256k1.c" #include "testrand_impl.h" @@ -47,9 +48,7 @@ void random_field_element_magnitude(secp256k1_fe_t *fe) { secp256k1_fe_negate(&zero, &zero, 0); secp256k1_fe_mul_int(&zero, n - 1); secp256k1_fe_add(fe, &zero); -#ifdef VERIFY - CHECK(fe->magnitude == n); -#endif + VERIFY_CHECK(fe->magnitude == n); } void random_group_element_test(secp256k1_ge_t *ge) { @@ -57,6 +56,7 @@ void random_group_element_test(secp256k1_ge_t *ge) { do { random_field_element_test(&fe); if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand32() & 1)) { + secp256k1_fe_normalize(&ge->y); break; } } while(1); @@ -153,12 +153,12 @@ void run_context_tests(void) { secp256k1_context_t *none = secp256k1_context_create(0); secp256k1_context_t *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); secp256k1_context_t *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); - secp256k1_context_t *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_COMMIT | SECP256K1_CONTEXT_RANGEPROOF); + secp256k1_context_t *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); secp256k1_gej_t pubj; secp256k1_ge_t pub; secp256k1_scalar_t msg, key, nonce; - secp256k1_ecdsa_sig_t sig; + secp256k1_scalar_t sigr, sigs; /*** clone and destroy all of them to make sure cloning was complete ***/ { @@ -179,15 +179,15 @@ void run_context_tests(void) { /* obtain a working nonce */ do { random_scalar_order_test(&nonce); - } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); /* try signing */ - CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); - CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); /* try verifying */ - CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sig, &pub, &msg)); - CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sig, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sigr, &sigs, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sigr, &sigs, &pub, &msg)); /* cleanup */ secp256k1_context_destroy(none); @@ -279,16 +279,14 @@ void run_hmac_sha256_tests(void) { } void run_rfc6979_hmac_sha256_tests(void) { - static const unsigned char key1[32] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00}; - static const unsigned char msg1[32] = {0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a}; + static const unsigned char key1[65] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a, 0}; static const unsigned char out1[3][32] = { {0x4f, 0xe2, 0x95, 0x25, 0xb2, 0x08, 0x68, 0x09, 0x15, 0x9a, 0xcd, 0xf0, 0x50, 0x6e, 0xfb, 0x86, 0xb0, 0xec, 0x93, 0x2c, 0x7b, 0xa4, 0x42, 0x56, 0xab, 0x32, 0x1e, 0x42, 0x1e, 0x67, 0xe9, 0xfb}, {0x2b, 0xf0, 0xff, 0xf1, 0xd3, 0xc3, 0x78, 0xa2, 0x2d, 0xc5, 0xde, 0x1d, 0x85, 0x65, 0x22, 0x32, 0x5c, 0x65, 0xb5, 0x04, 0x49, 0x1a, 0x0c, 0xbd, 0x01, 0xcb, 0x8f, 0x3a, 0xa6, 0x7f, 0xfd, 0x4a}, {0xf5, 0x28, 0xb4, 0x10, 0xcb, 0x54, 0x1f, 0x77, 0x00, 0x0d, 0x7a, 0xfb, 0x6c, 0x5b, 0x53, 0xc5, 0xc4, 0x71, 0xea, 0xb4, 0x3e, 0x46, 0x6d, 0x9a, 0xc5, 0x19, 0x0c, 0x39, 0xc8, 0x2f, 0xd8, 0x2e} }; - static const unsigned char key2[32] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - static const unsigned char msg2[32] = {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; + static const unsigned char key2[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; static const unsigned char out2[3][32] = { {0x9c, 0x23, 0x6c, 0x16, 0x5b, 0x82, 0xae, 0x0c, 0xd5, 0x90, 0x65, 0x9e, 0x10, 0x0b, 0x6b, 0xab, 0x30, 0x36, 0xe7, 0xba, 0x8b, 0x06, 0x74, 0x9b, 0xaf, 0x69, 0x81, 0xe1, 0x6f, 0x1a, 0x2b, 0x95}, {0xdf, 0x47, 0x10, 0x61, 0x62, 0x5b, 0xc0, 0xea, 0x14, 0xb6, 0x82, 0xfe, 0xee, 0x2c, 0x9c, 0x02, 0xf2, 0x35, 0xda, 0x04, 0x20, 0x4c, 0x1d, 0x62, 0xa1, 0x53, 0x6c, 0x6e, 0x17, 0xae, 0xd7, 0xa9}, @@ -297,24 +295,23 @@ void run_rfc6979_hmac_sha256_tests(void) { secp256k1_rfc6979_hmac_sha256_t rng; unsigned char out[32]; - unsigned char zero[1] = {0}; int i; - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 32, msg1, 32, NULL, 1); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64); for (i = 0; i < 3; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); CHECK(memcmp(out, out1[i], 32) == 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 32, msg1, 32, zero, 1); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 65); for (i = 0; i < 3; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); CHECK(memcmp(out, out1[i], 32) != 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 32, msg2, 32, zero, 0); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 64); for (i = 0; i < 3; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); CHECK(memcmp(out, out2[i], 32) == 0); @@ -607,7 +604,10 @@ void scalar_test(void) { r2 = s1; if (!secp256k1_scalar_add(&r1, &r1, &b)) { /* No overflow happened. */ - secp256k1_scalar_add_bit(&r2, bit); + secp256k1_scalar_cadd_bit(&r2, bit, 1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + /* cadd is a noop when flag is zero */ + secp256k1_scalar_cadd_bit(&r2, bit, 0); CHECK(secp256k1_scalar_eq(&r1, &r2)); } } @@ -797,13 +797,22 @@ void run_field_convert(void) { CHECK(memcmp(&fes2, &fes, sizeof(fes)) == 0); } +int fe_memcmp(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { + secp256k1_fe_t t = *b; +#ifdef VERIFY + t.magnitude = a->magnitude; + t.normalized = a->normalized; +#endif + return memcmp(a, &t, sizeof(secp256k1_fe_t)); +} + void run_field_misc(void) { secp256k1_fe_t x; secp256k1_fe_t y; secp256k1_fe_t z; secp256k1_fe_t q; secp256k1_fe_t fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); - int i; + int i, j; for (i = 0; i < 5*count; i++) { secp256k1_fe_storage_t xs, ys, zs; random_fe(&x); @@ -816,14 +825,27 @@ void run_field_misc(void) { /* Test fe conditional move; z is not normalized here. */ q = x; secp256k1_fe_cmov(&x, &z, 0); + VERIFY_CHECK(!x.normalized && x.magnitude == z.magnitude); secp256k1_fe_cmov(&x, &x, 1); - CHECK(memcmp(&x, &z, sizeof(x)) != 0); - CHECK(memcmp(&x, &q, sizeof(x)) == 0); + CHECK(fe_memcmp(&x, &z) != 0); + CHECK(fe_memcmp(&x, &q) == 0); secp256k1_fe_cmov(&q, &z, 1); - CHECK(memcmp(&q, &z, sizeof(q)) == 0); - /* Test storage conversion and conditional moves. */ - secp256k1_fe_normalize(&z); + VERIFY_CHECK(!q.normalized && q.magnitude == z.magnitude); + CHECK(fe_memcmp(&q, &z) == 0); + secp256k1_fe_normalize_var(&x); + secp256k1_fe_normalize_var(&z); CHECK(!secp256k1_fe_equal_var(&x, &z)); + secp256k1_fe_normalize_var(&q); + secp256k1_fe_cmov(&q, &z, (i&1)); + VERIFY_CHECK(q.normalized && q.magnitude == 1); + for (j = 0; j < 6; j++) { + secp256k1_fe_negate(&z, &z, j+1); + secp256k1_fe_normalize_var(&q); + secp256k1_fe_cmov(&q, &z, (j&1)); + VERIFY_CHECK(!q.normalized && q.magnitude == (j+2)); + } + secp256k1_fe_normalize_var(&z); + /* Test storage conversion and conditional moves. */ secp256k1_fe_to_storage(&xs, &x); secp256k1_fe_to_storage(&ys, &y); secp256k1_fe_to_storage(&zs, &z); @@ -974,7 +996,7 @@ void ge_equals_ge(const secp256k1_ge_t *a, const secp256k1_ge_t *b) { return; } CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); - CHECK(secp256k1_fe_equal_var(&b->y, &b->y)); + CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); } /* This compares jacobian points including their Z, not just their geometric meaning. */ @@ -1018,11 +1040,17 @@ void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) { void test_ge(void) { int i, i1; +#ifdef USE_ENDOMORPHISM + int runs = 6; +#else int runs = 4; +#endif /* Points: (infinity, p1, p1, -p1, -p1, p2, p2, -p2, -p2, p3, p3, -p3, -p3, p4, p4, -p4, -p4). * The second in each pair of identical points uses a random Z coordinate in the Jacobian form. * All magnitudes are randomized. * All 17*17 combinations of points are added to eachother, using all applicable methods. + * + * When the endomorphism code is compiled in, p5 = lambda*p1 and p6 = lambda^2*p1 are added as well. */ secp256k1_ge_t *ge = (secp256k1_ge_t *)malloc(sizeof(secp256k1_ge_t) * (1 + 4 * runs)); secp256k1_gej_t *gej = (secp256k1_gej_t *)malloc(sizeof(secp256k1_gej_t) * (1 + 4 * runs)); @@ -1037,6 +1065,14 @@ void test_ge(void) { int j; secp256k1_ge_t g; random_group_element_test(&g); +#ifdef USE_ENDOMORPHISM + if (i >= runs - 2) { + secp256k1_ge_mul_lambda(&g, &ge[1]); + } + if (i >= runs - 1) { + secp256k1_ge_mul_lambda(&g, &g); + } +#endif ge[1 + 4 * i] = g; ge[2 + 4 * i] = g; secp256k1_ge_neg(&ge[3 + 4 * i], &g); @@ -1188,7 +1224,7 @@ void test_ge(void) { } } 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); + secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej, &ctx->error_callback); for (i = 0; i < 4 * runs + 1; i++) { secp256k1_fe_t s; random_fe_non_zero(&s); @@ -1206,138 +1242,111 @@ void test_ge(void) { free(zinv); } +void test_add_neg_y_diff_x(void) { + /* The point of this test is to check that we can add two points + * whose y-coordinates are negatives of each other but whose x + * coordinates differ. If the x-coordinates were the same, these + * points would be negatives of each other and their sum is + * infinity. This is cool because it "covers up" any degeneracy + * in the addition algorithm that would cause the xy coordinates + * of the sum to be wrong (since infinity has no xy coordinates). + * HOWEVER, if the x-coordinates are different, infinity is the + * wrong answer, and such degeneracies are exposed. This is the + * root of https://github.com/bitcoin/secp256k1/issues/257 which + * this test is a regression test for. + * + * These points were generated in sage as + * # secp256k1 params + * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) + * C = EllipticCurve ([F (0), F (7)]) + * G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) + * N = FiniteField(G.order()) + * + * # endomorphism values (lambda is 1^{1/3} in N, beta is 1^{1/3} in F) + * x = polygen(N) + * lam = (1 - x^3).roots()[1][0] + * + * # random "bad pair" + * P = C.random_element() + * Q = -int(lam) * P + * print " P: %x %x" % P.xy() + * print " Q: %x %x" % Q.xy() + * print "P + Q: %x %x" % (P + Q).xy() + */ + secp256k1_gej_t aj = SECP256K1_GEJ_CONST( + 0x8d24cd95, 0x0a355af1, 0x3c543505, 0x44238d30, + 0x0643d79f, 0x05a59614, 0x2f8ec030, 0xd58977cb, + 0x001e337a, 0x38093dcd, 0x6c0f386d, 0x0b1293a8, + 0x4d72c879, 0xd7681924, 0x44e6d2f3, 0x9190117d + ); + secp256k1_gej_t bj = SECP256K1_GEJ_CONST( + 0xc7b74206, 0x1f788cd9, 0xabd0937d, 0x164a0d86, + 0x95f6ff75, 0xf19a4ce9, 0xd013bd7b, 0xbf92d2a7, + 0xffe1cc85, 0xc7f6c232, 0x93f0c792, 0xf4ed6c57, + 0xb28d3786, 0x2897e6db, 0xbb192d0b, 0x6e6feab2 + ); + secp256k1_gej_t sumj = SECP256K1_GEJ_CONST( + 0x671a63c0, 0x3efdad4c, 0x389a7798, 0x24356027, + 0xb3d69010, 0x278625c3, 0x5c86d390, 0x184a8f7a, + 0x5f6409c2, 0x2ce01f2b, 0x511fd375, 0x25071d08, + 0xda651801, 0x70e95caf, 0x8f0d893c, 0xbed8fbbe + ); + secp256k1_ge_t b; + secp256k1_gej_t resj; + secp256k1_ge_t res; + secp256k1_ge_set_gej(&b, &bj); + + secp256k1_gej_add_var(&resj, &aj, &bj, NULL); + secp256k1_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); + + secp256k1_gej_add_ge(&resj, &aj, &b); + secp256k1_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); + + secp256k1_gej_add_ge_var(&resj, &aj, &b, NULL); + secp256k1_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); +} + void run_ge(void) { int i; for (i = 0; i < count * 32; i++) { test_ge(); } + test_add_neg_y_diff_x(); } -/***** ECDH TESTS *****/ - -void ecdh_mult_zero(void) { - secp256k1_ge_t a; - secp256k1_scalar_t z = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - secp256k1_gej_t b; - - random_group_element_test(&a); - secp256k1_ecdh_point_multiply(&b, &a, &z); - CHECK(secp256k1_gej_is_infinity(&b)); -} - -void ecdh_random_mult(void) { - /* random starting point A (on the curve) */ - secp256k1_ge_t a = SECP256K1_GE_CONST( - 0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b, - 0xa97f9263, 0xb1e88044, 0x93351325, 0x91bc450a, - 0x535c59f7, 0x325e5d2b, 0xc391fbe8, 0x3c12787c, - 0x337e4a98, 0xe82a9011, 0x0123ba37, 0xdd769c7d - ); - /* random initial factor xn */ - secp256k1_scalar_t xn = SECP256K1_SCALAR_CONST( - 0x649d4f77, 0xc4242df7, 0x7f2079c9, 0x14530327, - 0xa31b876a, 0xd2d8ce2a, 0x2236d5c6, 0xd7b2029b - ); - /* expected xn * A (from sage) */ - secp256k1_ge_t expected_b = SECP256K1_GE_CONST( - 0x23773684, 0x4d209dc7, 0x098a786f, 0x20d06fcd, - 0x070a38bf, 0xc11ac651, 0x03004319, 0x1e2a8786, - 0xed8c3b8e, 0xc06dd57b, 0xd06ea66e, 0x45492b0f, - 0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956 - ); - secp256k1_gej_t b; - secp256k1_ecdh_point_multiply(&b, &a, &xn); - - CHECK(secp256k1_ge_is_valid_var(&a)); - ge_equals_gej(&expected_b, &b); -} - -void ecdh_commutativity(void) { - secp256k1_scalar_t a; - secp256k1_scalar_t b; - secp256k1_gej_t res1; - secp256k1_gej_t res2; - secp256k1_ge_t mid1; - secp256k1_ge_t mid2; - random_scalar_order_test(&a); - random_scalar_order_test(&b); - - secp256k1_ecdh_point_multiply(&res1, &secp256k1_ge_const_g, &a); - secp256k1_ecdh_point_multiply(&res2, &secp256k1_ge_const_g, &b); - secp256k1_ge_set_gej(&mid1, &res1); - secp256k1_ge_set_gej(&mid2, &res2); - secp256k1_ecdh_point_multiply(&res1, &mid1, &b); - secp256k1_ecdh_point_multiply(&res2, &mid2, &a); - secp256k1_ge_set_gej(&mid1, &res1); - secp256k1_ge_set_gej(&mid2, &res2); - ge_equals_ge(&mid1, &mid2); -} - -void ecdh_mult_zero_one(void) { - secp256k1_scalar_t zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - secp256k1_scalar_t one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_gej_t res1; - secp256k1_ge_t res2; - secp256k1_ge_t point; - - random_group_element_test(&point); - secp256k1_ecdh_point_multiply(&res1, &point, &zero); - secp256k1_ge_set_gej(&res2, &res1); - CHECK(secp256k1_ge_is_infinity(&res2)); - secp256k1_ecdh_point_multiply(&res1, &point, &one); - secp256k1_ge_set_gej(&res2, &res1); - ge_equals_ge(&res2, &point); -} - -void run_ecdh_tests(void) { - ecdh_mult_zero(); - ecdh_random_mult(); - ecdh_commutativity(); -} - -void run_ecdh_api_tests(void) { - const unsigned char scalar[] = {0x49, 0x68, 0xd5, 0x24, 0x2a, 0xbf, 0x9b, 0x7a, - 0x46, 0x6a, 0xbb, 0xcf, 0x34, 0xb1, 0x1b, 0x6d, - 0xcd, 0x83, 0xd3, 0x07, 0x82, 0x7b, 0xed, 0x62, - 0x05, 0xfa, 0xd0, 0xce, 0x18, 0xfa, 0xe6, 0x3b}; - const unsigned char expected_uncomp[] = { - 0x04, - /* x */ - 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, - 0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd, - 0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb, - 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f, - /* y */ - 0x5d, 0x19, 0x5d, 0x20, 0xe1, 0x91, 0xbf, 0x7f, - 0x1b, 0xe3, 0xe5, 0x5f, 0x56, 0xa8, 0x01, 0x96, - 0x60, 0x71, 0xad, 0x01, 0xf1, 0x46, 0x2f, 0x66, - 0xc9, 0x97, 0xfa, 0x94, 0xdb, 0x85, 0x84, 0x35 - }; - const unsigned char expected_comp[] = { - /* y */ - 0x03, - /* x */ - 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, - 0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd, - 0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb, - 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f - }; - unsigned char point[65]; - int pointlen = sizeof(point); - secp256k1_ge_t gen = secp256k1_ge_const_g; +void test_ec_combine(void) { + secp256k1_scalar_t sum = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_pubkey_t data[6]; + const secp256k1_pubkey_t* d[6]; + secp256k1_pubkey_t sd; + secp256k1_pubkey_t sd2; + secp256k1_gej_t Qj; + secp256k1_ge_t Q; int i; - /* uncompressed */ - secp256k1_eckey_pubkey_serialize(&gen, point, &pointlen, 0); - for (i = 0; i < 100; ++i) { - CHECK(secp256k1_point_multiply(point, &pointlen, scalar) == 1); + for (i = 1; i <= 6; i++) { + secp256k1_scalar_t s; + random_scalar_order_test(&s); + secp256k1_scalar_add(&sum, &sum, &s); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &s); + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(&data[i - 1], &Q); + d[i - 1] = &data[i - 1]; + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sum); + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(&sd, &Q); + CHECK(secp256k1_ec_pubkey_combine(ctx, &sd2, i, d) == 1); + CHECK(memcmp(&sd, &sd2, sizeof(sd)) == 0); } - CHECK(memcmp(point, expected_uncomp, 65) == 0); - /* compressed */ - secp256k1_eckey_pubkey_serialize(&gen, point, &pointlen, 1); - for (i = 0; i < 100; ++i) { - CHECK(secp256k1_point_multiply(point, &pointlen, scalar) == 1); +} + +void run_ec_combine(void) { + int i; + for (i = 0; i < count * 8; i++) { + test_ec_combine(); } - CHECK(memcmp(point, expected_comp, 33) == 0); } /***** ECMULT TESTS *****/ @@ -1441,47 +1450,6 @@ void test_point_times_order(const secp256k1_gej_t *point) { ge_equals_ge(&res3, &secp256k1_ge_const_g); } -void test_ecmult_points_ecmult(void) { - secp256k1_scalar_t x[SECP256K1_SCHNORR_MAX_BATCH]; - secp256k1_scalar_t t[SECP256K1_SCHNORR_MAX_BATCH], tall; - secp256k1_gej_t a[SECP256K1_SCHNORR_MAX_BATCH]; - secp256k1_gej_t tmp, res1, res2; - int n, i; - n = 1 + (secp256k1_rand32() % (SECP256K1_SCHNORR_MAX_BATCH - 1)); - for (i = 0; i < n; i++) { - random_scalar_order_test(&x[i]); - random_scalar_order_test(&t[i]); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &a[(i + 1) % n], &t[i]); - } - - /* Compute res1 = (x1*a1 + t1*g) + (x2*a2 + t2) + (x3*a3 + t3). */ - secp256k1_ecmult(&ctx->ecmult_ctx, &res1, &a[0], &x[0], &t[0]); - for (i = 1; i < n; i++) { - secp256k1_ecmult(&ctx->ecmult_ctx, &tmp, &a[i], &x[i], &t[i]); - secp256k1_gej_add_var(&res1, &res1, &tmp, NULL); - } - - /* Compute res2 = x1*a1 + x2*a2 + x3*a3 + (t1+t2+t3)*g. */ - tall = t[0]; - for (i = 1; i < n; i++) { - secp256k1_scalar_add(&tall, &tall, &t[i]); - } - secp256k1_ecmult_points(&ctx->ecmult_ctx, n, &res2, a, x, &tall); - - /* Compare res1 == res2. */ - secp256k1_gej_neg(&res2, &res2); - secp256k1_gej_add_var(&res2, &res2, &res1, NULL); - CHECK(secp256k1_gej_is_infinity(&res2)); -} - -void run_ecmult_points_ecmult(void) { - int i; - for (i = 0; i < 8 * count; i++) { - test_ecmult_points_ecmult(); - } -} - - void run_point_times_order(void) { int i; secp256k1_fe_t x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); @@ -1504,6 +1472,109 @@ void run_point_times_order(void) { CHECK(secp256k1_fe_equal_var(&x, &xr)); } +void ecmult_const_random_mult(void) { + /* random starting point A (on the curve) */ + secp256k1_ge_t a = SECP256K1_GE_CONST( + 0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b, + 0xa97f9263, 0xb1e88044, 0x93351325, 0x91bc450a, + 0x535c59f7, 0x325e5d2b, 0xc391fbe8, 0x3c12787c, + 0x337e4a98, 0xe82a9011, 0x0123ba37, 0xdd769c7d + ); + /* random initial factor xn */ + secp256k1_scalar_t xn = SECP256K1_SCALAR_CONST( + 0x649d4f77, 0xc4242df7, 0x7f2079c9, 0x14530327, + 0xa31b876a, 0xd2d8ce2a, 0x2236d5c6, 0xd7b2029b + ); + /* expected xn * A (from sage) */ + secp256k1_ge_t expected_b = SECP256K1_GE_CONST( + 0x23773684, 0x4d209dc7, 0x098a786f, 0x20d06fcd, + 0x070a38bf, 0xc11ac651, 0x03004319, 0x1e2a8786, + 0xed8c3b8e, 0xc06dd57b, 0xd06ea66e, 0x45492b0f, + 0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956 + ); + secp256k1_gej_t b; + secp256k1_ecmult_const(&b, &a, &xn); + + CHECK(secp256k1_ge_is_valid_var(&a)); + ge_equals_gej(&expected_b, &b); +} + +void ecmult_const_commutativity(void) { + secp256k1_scalar_t a; + secp256k1_scalar_t b; + secp256k1_gej_t res1; + secp256k1_gej_t res2; + secp256k1_ge_t mid1; + secp256k1_ge_t mid2; + random_scalar_order_test(&a); + random_scalar_order_test(&b); + + secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a); + secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b); + secp256k1_ge_set_gej(&mid1, &res1); + secp256k1_ge_set_gej(&mid2, &res2); + secp256k1_ecmult_const(&res1, &mid1, &b); + secp256k1_ecmult_const(&res2, &mid2, &a); + secp256k1_ge_set_gej(&mid1, &res1); + secp256k1_ge_set_gej(&mid2, &res2); + ge_equals_ge(&mid1, &mid2); +} + +void ecmult_const_mult_zero_one(void) { + secp256k1_scalar_t zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_scalar_t one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_scalar_t negone; + secp256k1_gej_t res1; + secp256k1_ge_t res2; + secp256k1_ge_t point; + secp256k1_scalar_negate(&negone, &one); + + random_group_element_test(&point); + secp256k1_ecmult_const(&res1, &point, &zero); + secp256k1_ge_set_gej(&res2, &res1); + CHECK(secp256k1_ge_is_infinity(&res2)); + secp256k1_ecmult_const(&res1, &point, &one); + secp256k1_ge_set_gej(&res2, &res1); + ge_equals_ge(&res2, &point); + secp256k1_ecmult_const(&res1, &point, &negone); + secp256k1_gej_neg(&res1, &res1); + secp256k1_ge_set_gej(&res2, &res1); + ge_equals_ge(&res2, &point); +} + +void ecmult_const_chain_multiply(void) { + /* Check known result (randomly generated test problem from sage) */ + const secp256k1_scalar_t scalar = SECP256K1_SCALAR_CONST( + 0x4968d524, 0x2abf9b7a, 0x466abbcf, 0x34b11b6d, + 0xcd83d307, 0x827bed62, 0x05fad0ce, 0x18fae63b + ); + const secp256k1_gej_t expected_point = SECP256K1_GEJ_CONST( + 0x5494c15d, 0x32099706, 0xc2395f94, 0x348745fd, + 0x757ce30e, 0x4e8c90fb, 0xa2bad184, 0xf883c69f, + 0x5d195d20, 0xe191bf7f, 0x1be3e55f, 0x56a80196, + 0x6071ad01, 0xf1462f66, 0xc997fa94, 0xdb858435 + ); + secp256k1_gej_t point; + secp256k1_ge_t res; + int i; + + secp256k1_gej_set_ge(&point, &secp256k1_ge_const_g); + for (i = 0; i < 100; ++i) { + secp256k1_ge_t tmp; + secp256k1_ge_set_gej(&tmp, &point); + secp256k1_ecmult_const(&point, &tmp, &scalar); + } + secp256k1_ge_set_gej(&res, &point); + ge_equals_gej(&res, &expected_point); +} + +void run_ecmult_const_tests(void) { + ecmult_const_mult_zero_one(); + ecmult_const_random_mult(); + ecmult_const_commutativity(); + ecmult_const_chain_multiply(); +} + void test_wnaf(const secp256k1_scalar_t *number, int w) { secp256k1_scalar_t x, two, t; int wnaf[256]; @@ -1512,7 +1583,7 @@ void test_wnaf(const secp256k1_scalar_t *number, int w) { int bits; secp256k1_scalar_set_int(&x, 0); secp256k1_scalar_set_int(&two, 2); - bits = secp256k1_ecmult_wnaf(wnaf, number, w); + bits = secp256k1_ecmult_wnaf(wnaf, 256, number, w); CHECK(bits <= 256); for (i = bits-1; i >= 0; i--) { int v = wnaf[i]; @@ -1548,7 +1619,7 @@ void test_constant_wnaf_negate(const secp256k1_scalar_t *number) { secp256k1_scalar_negate(&neg1, &neg1); sign1 = -1; } - sign2 = secp256k1_scalar_wnaf_force_odd(&neg2); + sign2 = secp256k1_scalar_cond_negate(&neg2, secp256k1_scalar_is_even(&neg2)); CHECK(sign1 == sign2); CHECK(secp256k1_scalar_eq(&neg1, &neg2)); } @@ -1556,14 +1627,24 @@ void test_constant_wnaf_negate(const secp256k1_scalar_t *number) { void test_constant_wnaf(const secp256k1_scalar_t *number, int w) { secp256k1_scalar_t x, shift; int wnaf[256] = {0}; - int bits, i; + int i; +#ifdef USE_ENDOMORPHISM + int skew; +#endif + secp256k1_scalar_t num = *number; secp256k1_scalar_set_int(&x, 0); secp256k1_scalar_set_int(&shift, 1 << w); - bits = secp256k1_ecdh_wnaf(wnaf, number, w); - CHECK(bits == (256 + w - 1) / w); + /* With USE_ENDOMORPHISM on we only consider 128-bit numbers */ +#ifdef USE_ENDOMORPHISM + for (i = 0; i < 16; ++i) + secp256k1_scalar_shr_int(&num, 8); + skew = secp256k1_wnaf_const(wnaf, num, w); +#else + secp256k1_wnaf_const(wnaf, num, w); +#endif - for (i = bits; i >= 0; --i) { + for (i = WNAF_SIZE(w); i >= 0; --i) { secp256k1_scalar_t t; int v = wnaf[i]; CHECK(v != 0); /* check nonzero */ @@ -1580,7 +1661,11 @@ void test_constant_wnaf(const secp256k1_scalar_t *number, int w) { } secp256k1_scalar_add(&x, &x, &t); } - CHECK(secp256k1_scalar_eq(&x, number)); +#ifdef USE_ENDOMORPHISM + /* Skew num because when encoding 128-bit numbers as odd we use an offset */ + secp256k1_scalar_cadd_bit(&num, skew == 2, 1); +#endif + CHECK(secp256k1_scalar_eq(&x, &num)); } void run_wnaf(void) { @@ -1682,12 +1767,39 @@ void run_ecmult_gen_blind(void) { } } +#ifdef USE_ENDOMORPHISM +/***** ENDOMORPHISH TESTS *****/ +void test_scalar_split(void) { + secp256k1_scalar_t full; + secp256k1_scalar_t s1, slam; + const unsigned char zero[32] = {0}; + unsigned char tmp[32]; -void random_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *key, const secp256k1_scalar_t *msg, int *recid) { + random_scalar_order_test(&full); + secp256k1_scalar_split_lambda(&s1, &slam, &full); + + /* check that both are <= 128 bits in size */ + if (secp256k1_scalar_is_high(&s1)) + secp256k1_scalar_negate(&s1, &s1); + if (secp256k1_scalar_is_high(&slam)) + secp256k1_scalar_negate(&slam, &slam); + + secp256k1_scalar_get_b32(tmp, &s1); + CHECK(memcmp(zero, tmp, 16) == 0); + secp256k1_scalar_get_b32(tmp, &slam); + CHECK(memcmp(zero, tmp, 16) == 0); +} + +void run_endomorphism_tests(void) { + test_scalar_split(); +} +#endif + +void random_sign(secp256k1_scalar_t *sigr, secp256k1_scalar_t *sigs, const secp256k1_scalar_t *key, const secp256k1_scalar_t *msg, int *recid) { secp256k1_scalar_t nonce; do { random_scalar_order_test(&nonce); - } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sig, key, msg, &nonce, recid)); + } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid)); } void test_ecdsa_sign_verify(void) { @@ -1695,7 +1807,7 @@ void test_ecdsa_sign_verify(void) { secp256k1_ge_t pub; secp256k1_scalar_t one; secp256k1_scalar_t msg, key; - secp256k1_ecdsa_sig_t sig; + secp256k1_scalar_t sigr, sigs; int recid; int getrec; random_scalar_order_test(&msg); @@ -1703,14 +1815,14 @@ void test_ecdsa_sign_verify(void) { secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); secp256k1_ge_set_gej(&pub, &pubj); getrec = secp256k1_rand32()&1; - random_sign(&sig, &key, &msg, getrec?&recid:NULL); + random_sign(&sigr, &sigs, &key, &msg, getrec?&recid:NULL); if (getrec) { CHECK(recid >= 0 && recid < 4); } - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); secp256k1_scalar_set_int(&one, 1); secp256k1_scalar_add(&msg, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &pub, &msg)); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); } void run_ecdsa_sign_verify(void) { @@ -1721,22 +1833,23 @@ void run_ecdsa_sign_verify(void) { } /** Dummy nonce generation function that just uses a precomputed nonce, and fails if it is not accepted. Use only for testing. */ -static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { +static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, unsigned int counter, const void *data) { (void)msg32; (void)key32; + (void)algo16; memcpy(nonce32, data, 32); return (counter == 0); } -static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { +static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, unsigned int counter, const void *data) { /* Dummy nonce generator that has a fatal error on the first counter value. */ if (counter == 0) { return 0; } - return nonce_function_rfc6979(nonce32, msg32, key32, counter - 1, data); + return nonce_function_rfc6979(nonce32, msg32, key32, algo16, counter - 1, data); } -static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { +static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, unsigned int counter, const void *data) { /* Dummy nonce generator that produces unacceptable nonces for the first several counter values. */ if (counter < 3) { memset(nonce32, counter==0 ? 0 : 255, 32); @@ -1763,12 +1876,12 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char if (counter > 5) { return 0; } - return nonce_function_rfc6979(nonce32, msg32, key32, counter - 5, data); + return nonce_function_rfc6979(nonce32, msg32, key32, algo16, counter - 5, data); } -int is_empty_compact_signature(const unsigned char *sig64) { - static const unsigned char res[64] = {0}; - return memcmp(sig64, res, 64) == 0; +int is_empty_signature(const secp256k1_ecdsa_signature_t *sig) { + static const unsigned char res[sizeof(secp256k1_ecdsa_signature_t)] = {0}; + return memcmp(sig, res, sizeof(secp256k1_ecdsa_signature_t)) == 0; } void test_ecdsa_end_to_end(void) { @@ -1776,21 +1889,15 @@ void test_ecdsa_end_to_end(void) { unsigned char privkey[32]; unsigned char message[32]; unsigned char privkey2[32]; - unsigned char csignature[64]; - unsigned char signature[72]; - unsigned char signature2[72]; - unsigned char signature3[72]; - unsigned char signature4[72]; - unsigned char pubkey[65]; - unsigned char recpubkey[65]; + secp256k1_ecdsa_signature_t signature[5]; + unsigned char sig[74]; + int siglen = 74; + unsigned char pubkeyc[65]; + int pubkeyclen = 65; + secp256k1_pubkey_t pubkey; + secp256k1_pubkey_t recpubkey; unsigned char seckey[300]; - int signaturelen = 72; - int signaturelen2 = 72; - int signaturelen3 = 72; - int signaturelen4 = 72; int recid = 0; - int recpubkeylen = 0; - int pubkeylen = 65; int seckeylen = 300; /* Generate a random key and message. */ @@ -1804,11 +1911,12 @@ void test_ecdsa_end_to_end(void) { /* Construct and verify corresponding public key. */ CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, pubkey, &pubkeylen, privkey, (secp256k1_rand32() & 3) != 0) == 1); - if (secp256k1_rand32() & 1) { - CHECK(secp256k1_ec_pubkey_decompress(ctx, pubkey, &pubkeylen)); - } - CHECK(secp256k1_ec_pubkey_verify(ctx, pubkey, pubkeylen)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Verify exporting and importing public key. */ + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand32() % 2) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); /* Verify private key import and export. */ CHECK(secp256k1_ec_privkey_export(ctx, privkey, seckey, &seckeylen, secp256k1_rand32() % 2) == 1); @@ -1820,17 +1928,16 @@ void test_ecdsa_end_to_end(void) { int ret1; int ret2; unsigned char rnd[32]; - unsigned char pubkey2[65]; - int pubkeylen2 = 65; + secp256k1_pubkey_t pubkey2; secp256k1_rand256_test(rnd); ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_add(ctx, pubkey, pubkeylen, rnd); + ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd); CHECK(ret1 == ret2); if (ret1 == 0) { return; } - CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); - CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } /* Optionally tweak the keys using multiplication. */ @@ -1838,59 +1945,70 @@ void test_ecdsa_end_to_end(void) { int ret1; int ret2; unsigned char rnd[32]; - unsigned char pubkey2[65]; - int pubkeylen2 = 65; + secp256k1_pubkey_t pubkey2; secp256k1_rand256_test(rnd); ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, pubkey, pubkeylen, rnd); + ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd); CHECK(ret1 == ret2); if (ret1 == 0) { return; } - CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); - CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } /* Sign. */ - CHECK(secp256k1_ecdsa_sign(ctx, message, signature, &signaturelen, privkey, NULL, NULL) == 1); - CHECK(signaturelen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, message, signature2, &signaturelen2, privkey, NULL, extra) == 1); - CHECK(signaturelen2 > 0); + CHECK(secp256k1_ecdsa_sign(ctx, message, &signature[0], privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, message, &signature[4], privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, message, &signature[1], privkey, NULL, extra) == 1); extra[31] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, message, signature3, &signaturelen3, privkey, NULL, extra) == 1); - CHECK(signaturelen3 > 0); + CHECK(secp256k1_ecdsa_sign(ctx, message, &signature[2], privkey, NULL, extra) == 1); extra[31] = 0; extra[0] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, message, signature4, &signaturelen4, privkey, NULL, extra) == 1); - CHECK(signaturelen3 > 0); - CHECK((signaturelen != signaturelen2) || (memcmp(signature, signature2, signaturelen) != 0)); - CHECK((signaturelen != signaturelen3) || (memcmp(signature, signature3, signaturelen) != 0)); - CHECK((signaturelen3 != signaturelen2) || (memcmp(signature3, signature2, signaturelen3) != 0)); - CHECK((signaturelen4 != signaturelen3) || (memcmp(signature4, signature3, signaturelen4) != 0)); - CHECK((signaturelen4 != signaturelen2) || (memcmp(signature4, signature2, signaturelen4) != 0)); - CHECK((signaturelen4 != signaturelen) || (memcmp(signature4, signature, signaturelen4) != 0)); + CHECK(secp256k1_ecdsa_sign(ctx, message, &signature[3], privkey, NULL, extra) == 1); + CHECK(memcmp(&signature[0], &signature[4], sizeof(signature[0])) == 0); + CHECK(memcmp(&signature[0], &signature[1], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[0], &signature[2], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[0], &signature[3], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[1], &signature[2], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[1], &signature[3], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[2], &signature[3], sizeof(signature[0])) != 0); /* Verify. */ - CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature2, signaturelen2, pubkey, pubkeylen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature3, signaturelen3, pubkey, pubkeylen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature4, signaturelen4, pubkey, pubkeylen) == 1); - /* Destroy signature and verify again. */ - signature[signaturelen - 1 - secp256k1_rand32() % 20] += 1 + (secp256k1_rand32() % 255); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) != 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[0], &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[1], &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[2], &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[3], &pubkey) == 1); - /* Compact sign. */ - CHECK(secp256k1_ecdsa_sign_compact(ctx, message, csignature, privkey, NULL, NULL, &recid) == 1); - CHECK(!is_empty_compact_signature(csignature)); - /* Recover. */ - CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1); - CHECK(recpubkeylen == pubkeylen); - CHECK(memcmp(pubkey, recpubkey, pubkeylen) == 0); - /* Destroy signature and verify again. */ - csignature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); - CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) != 1 || - memcmp(pubkey, recpubkey, pubkeylen) != 0); - CHECK(recpubkeylen == pubkeylen); + /* Serialize/parse DER and verify again */ + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); + memset(&signature[0], 0, sizeof(signature[0])); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[0], &pubkey) == 1); + /* Serialize/destroy/parse DER and verify again. */ + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); + sig[secp256k1_rand32() % siglen] += 1 + (secp256k1_rand32() % 255); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 || + secp256k1_ecdsa_verify(ctx, message, &signature[0], &pubkey) == 0); + /* Serialize/parse compact (without recovery id) and verify again. */ + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, sig, &recid, &signature[4]) == 1); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, sig, NULL, &signature[4]) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[4], &pubkey) == 1); + memset(&signature[4], 0, sizeof(signature[4])); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature[4], sig, -1) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[4], &pubkey) == 1); + /* Parse compact (with recovery id) and recover. */ + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, message, &signature[4], &recpubkey) == 1); + CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); + /* Serialize/destroy/parse signature and verify again. */ + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, sig, &recid, &signature[4]) == 1); + sig[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[4], &pubkey) == 0); + /* Recover again */ + CHECK(secp256k1_ecdsa_recover(ctx, message, &signature[4], &recpubkey) == 0 || + memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); } void test_random_pubkeys(void) { @@ -1992,9 +2110,8 @@ void test_ecdsa_edge_cases(void) { 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 }; - unsigned char pubkey[65]; + secp256k1_pubkey_t pubkey; int t; - int pubkeylen = 65; /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ const unsigned char sigb64[64] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -2006,14 +2123,18 @@ void test_ecdsa_edge_cases(void) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, }; - unsigned char pubkeyb[33]; - int pubkeyblen = 33; + secp256k1_pubkey_t pubkeyb; + secp256k1_ecdsa_signature_t sig; int recid; - CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 0)); - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 1)); - CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 2)); - CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 3)); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sig64, 0)); + CHECK(!secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkey)); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sig64, 1)); + CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkey)); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sig64, 2)); + CHECK(!secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkey)); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sig64, 3)); + CHECK(!secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkey)); for (recid = 0; recid < 4; recid++) { int i; @@ -2058,34 +2179,41 @@ void test_ecdsa_edge_cases(void) { 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 }; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkeyb, &pubkeyblen, 1, recid)); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigb64, recid) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkeyb) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 1); for (recid2 = 0; recid2 < 4; recid2++) { - unsigned char pubkey2b[33]; - int pubkey2blen = 33; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkey2b, &pubkey2blen, 1, recid2)); + secp256k1_pubkey_t pubkey2b; + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigb64, recid2) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkey2b) == 1); /* Verifying with (order + r,4) should always fail. */ - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderlong, sizeof(sigbderlong), pubkey2b, pubkey2blen) != 1); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 0); } /* DER parsing tests. */ /* Zero length r/s. */ - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zr, sizeof(sigcder_zr), pubkeyb, pubkeyblen) == -2); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zs, sizeof(sigcder_zs), pubkeyb, pubkeyblen) == -2); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); /* Leading zeros. */ - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt1, sizeof(sigbderalt1), pubkeyb, pubkeyblen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt2, sizeof(sigbderalt2), pubkeyb, pubkeyblen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 1); sigbderalt3[4] = 1; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == -2); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); sigbderalt4[7] = 1; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == -2); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); /* Damage signature. */ sigbder[7]++; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 0); sigbder[7]--; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, 6, pubkeyb, pubkeyblen) == -2); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder)-1, pubkeyb, pubkeyblen) == -2); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0); for(i = 0; i < 8; i++) { int c; unsigned char orig = sigbder[i]; @@ -2095,8 +2223,7 @@ void test_ecdsa_edge_cases(void) { continue; } sigbder[i] = c; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == - (i==4 || i==7) ? 0 : -2 ); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 0); } sigbder[i] = orig; } @@ -2107,15 +2234,15 @@ void test_ecdsa_edge_cases(void) { secp256k1_gej_t keyj; secp256k1_ge_t key; secp256k1_scalar_t msg; - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_set_int(&sig.s, 1); - secp256k1_scalar_negate(&sig.s, &sig.s); - secp256k1_scalar_inverse(&sig.s, &sig.s); - secp256k1_scalar_set_int(&sig.r, 1); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sig.r); + secp256k1_scalar_t sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_negate(&ss, &ss); + secp256k1_scalar_inverse(&ss, &ss); + secp256k1_scalar_set_int(&sr, 1); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr); secp256k1_ge_set_gej(&key, &keyj); - msg = sig.s; - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &key, &msg) == 0); + msg = ss; + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); } /* Test r/s equal to zero */ @@ -2132,24 +2259,31 @@ void test_ecdsa_edge_cases(void) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, }; - unsigned char pubkeyc[65]; - int pubkeyclen = 65; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyc, &pubkeyclen, 0, 0) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 1); + secp256k1_pubkey_t pubkeyc; + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkeyc) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyc) == 1); sigcder[4] = 0; sigc64[31] = 0; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkeyb) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyc) == 0); sigcder[4] = 1; sigcder[7] = 0; sigc64[31] = 1; sigc64[63] = 0; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkeyb) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyc) == 0); } /*Signature where s would be zero.*/ { + unsigned char signature[72]; + int siglen; const unsigned char nonce[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -2174,21 +2308,15 @@ void test_ecdsa_edge_cases(void) { 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, }; - unsigned char sig[72]; - int siglen = 72; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 0); - CHECK(siglen == 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 0); - CHECK(siglen == 0); + CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce) == 0); + CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce2) == 0); msg[31] = 0xaa; + CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce2) == 1); siglen = 72; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 1); - CHECK(siglen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 1); - CHECK(siglen > 0); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1); siglen = 10; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) != 1); - CHECK(siglen == 0); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0); } /* Nonce function corner cases. */ @@ -2197,65 +2325,43 @@ void test_ecdsa_edge_cases(void) { int i; unsigned char key[32]; unsigned char msg[32]; - unsigned char sig[72]; - unsigned char sig2[72]; - secp256k1_ecdsa_sig_t s[512]; - int siglen = 72; - int siglen2 = 72; - int recid2; + secp256k1_ecdsa_signature_t sig2; + secp256k1_scalar_t sr[512], ss; const unsigned char *extra; extra = t == 0 ? NULL : zero; memset(msg, 0, 32); msg[31] = 1; /* High key results in signature failure. */ memset(key, 0xFF, 32); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 0); - CHECK(siglen == 0); + CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, NULL, extra) == 0); + CHECK(is_empty_signature(&sig)); /* Zero key results in signature failure. */ memset(key, 0, 32); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 0); - CHECK(siglen == 0); + CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, NULL, extra) == 0); + CHECK(is_empty_signature(&sig)); /* Nonce function failure results in signature failure. */ key[31] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, nonce_function_test_fail, extra) == 0); - CHECK(siglen == 0); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_fail, extra, &recid) == 0); - CHECK(is_empty_compact_signature(sig)); + CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, nonce_function_test_fail, extra) == 0); + CHECK(is_empty_signature(&sig)); /* The retry loop successfully makes its way to the first good value. */ - siglen = 72; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, nonce_function_test_retry, extra) == 1); - CHECK(siglen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, nonce_function_rfc6979, extra) == 1); - CHECK(siglen > 0); - CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_retry, extra, &recid) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, nonce_function_rfc6979, extra, &recid2) == 1); - CHECK(!is_empty_compact_signature(sig2)); - CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0)); + CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, nonce_function_test_retry, extra) == 1); + CHECK(!is_empty_signature(&sig)); + CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, nonce_function_rfc6979, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); /* The default nonce function is determinstic. */ - siglen = 72; - siglen2 = 72; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 1); - CHECK(siglen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); - CHECK(siglen2 > 0); - CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, NULL, extra, &recid) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, NULL, extra, &recid2) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0)); + CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); /* The default nonce function changes output with different messages. */ for(i = 0; i < 256; i++) { int j; - siglen2 = 72; msg[0] = i; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); + CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, NULL, &sig2); for (j = 0; j < i; j++) { - CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r)); + CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); } } msg[0] = 0; @@ -2263,12 +2369,12 @@ void test_ecdsa_edge_cases(void) { /* The default nonce function changes output with different keys. */ for(i = 256; i < 512; i++) { int j; - siglen2 = 72; key[0] = i - 256; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); - CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); + CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, NULL, &sig2); for (j = 0; j < i; j++) { - CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r)); + CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); } } key[0] = 0; @@ -2293,67 +2399,6 @@ void run_ecdsa_edge_cases(void) { test_ecdsa_edge_cases(); } -/** 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_t pubkeyj[3]; - secp256k1_ge_t pubkey[3]; - secp256k1_scalar_t 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], &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_rand32() % 64; - int mod = 1 + (secp256k1_rand32() % 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; - } - } - - CHECK(secp256k1_schnorr_sig_verify_batch(&ctx->ecmult_ctx, 3, sig64, pubkey, test_schnorr_hash, msg32)); - - for (i = 0; i < 4; i++) { - int pos = secp256k1_rand32() % 64; - int mod = 1 + (secp256k1_rand32() % 255); - k = secp256k1_rand32() % 3; - sig64[k][pos] ^= mod; - CHECK(secp256k1_schnorr_sig_verify_batch(&ctx->ecmult_ctx, 3, sig64, pubkey, &test_schnorr_hash, msg32) == 0); - sig64[k][pos] ^= mod; - } -} - -void run_schnorr_sign_verify(void) { - int i; - for (i = 0; i < 32 * count; i++) { - test_schnorr_sign_verify(); - } -} - #ifdef ENABLE_OPENSSL_TESTS EC_KEY *get_openssl_key(const secp256k1_scalar_t *key) { unsigned char privkey[300]; @@ -2370,7 +2415,7 @@ EC_KEY *get_openssl_key(const secp256k1_scalar_t *key) { void test_ecdsa_openssl(void) { secp256k1_gej_t qj; secp256k1_ge_t q; - secp256k1_ecdsa_sig_t sig; + secp256k1_scalar_t sigr, sigs; secp256k1_scalar_t one; secp256k1_scalar_t msg2; secp256k1_scalar_t key, msg; @@ -2387,14 +2432,14 @@ void test_ecdsa_openssl(void) { ec_key = get_openssl_key(&key); CHECK(ec_key); CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key)); - CHECK(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg)); + CHECK(secp256k1_ecdsa_sig_parse(&sigr, &sigs, signature, sigsize)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg)); secp256k1_scalar_set_int(&one, 1); secp256k1_scalar_add(&msg2, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg2)); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg2)); - random_sign(&sig, &key, &msg, NULL); - CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sig)); + random_sign(&sigr, &sigs, &key, &msg, NULL); + CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sigr, &sigs)); CHECK(ECDSA_verify(0, message, sizeof(message), signature, secp_sigsize, ec_key) == 1); EC_KEY_free(ec_key); @@ -2408,285 +2453,21 @@ void run_ecdsa_openssl(void) { } #endif -void test_pedersen(void) { - unsigned char commits[33*19]; - const unsigned char *cptr[19]; - unsigned char blinds[32*19]; - const unsigned char *bptr[19]; - secp256k1_scalar_t s; - uint64_t values[19]; - int64_t totalv; - int i; - int inputs; - int outputs; - int total; - inputs = (secp256k1_rand32() & 7) + 1; - outputs = (secp256k1_rand32() & 7) + 2; - total = inputs + outputs; - for (i = 0; i < 19; i++) { - cptr[i] = &commits[i * 33]; - bptr[i] = &blinds[i * 32]; - } - totalv = 0; - for (i = 0; i < inputs; i++) { - values[i] = secp256k1_rands64(0, INT64_MAX - totalv); - totalv += values[i]; - } - if (secp256k1_rand32() & 1) { - for (i = 0; i < outputs; i++) { - int64_t max = INT64_MAX; - if (totalv < 0) { - max += totalv; - } - values[i + inputs] = secp256k1_rands64(0, max); - totalv -= values[i + inputs]; - } - } else { - for (i = 0; i < outputs - 1; i++) { - values[i + inputs] = secp256k1_rands64(0, totalv); - totalv -= values[i + inputs]; - } - values[total - 1] = totalv >> (secp256k1_rand32() & 1); - totalv -= values[total - 1]; - } - for (i = 0; i < total - 1; i++) { - random_scalar_order(&s); - secp256k1_scalar_get_b32(&blinds[i * 32], &s); - } - CHECK(secp256k1_pedersen_blind_sum(ctx, &blinds[(total - 1) * 32], bptr, total - 1, inputs)); - for (i = 0; i < total; i++) { - CHECK(secp256k1_pedersen_commit(ctx, &commits[i * 33], &blinds[i * 32], values[i])); - } - CHECK(secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs, totalv)); - CHECK(!secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs, totalv + 1)); - random_scalar_order(&s); - for (i = 0; i < 4; i++) { - secp256k1_scalar_get_b32(&blinds[i * 32], &s); - } - values[0] = INT64_MAX; - values[1] = 0; - values[2] = 1; - for (i = 0; i < 3; i++) { - CHECK(secp256k1_pedersen_commit(ctx, &commits[i * 33], &blinds[i * 32], values[i])); - } - CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[2], 1, -1)); - CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[2], 1, &cptr[1], 1, 1)); - CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1, 0)); - CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[1], 1, INT64_MAX)); - CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1, 0)); - CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[0], 1, -INT64_MAX)); -} +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/tests_impl.h" +#endif -void run_pedersen(void) { - int i; - for (i = 0; i < 10*count; i++) { - test_pedersen(); - } -} - -void test_borromean(void) { - unsigned char e0[32]; - secp256k1_scalar_t s[64]; - secp256k1_gej_t pubs[64]; - secp256k1_scalar_t k[8]; - secp256k1_scalar_t sec[8]; - secp256k1_ge_t ge; - secp256k1_scalar_t one; - unsigned char m[32]; - int rsizes[8]; - int secidx[8]; - int nrings; - int i; - int j; - int c; - secp256k1_rand256_test(m); - nrings = 1 + (secp256k1_rand32()&7); - c = 0; - secp256k1_scalar_set_int(&one, 1); - if (secp256k1_rand32()&1) { - secp256k1_scalar_negate(&one, &one); - } - for (i = 0; i < nrings; i++) { - rsizes[i] = 1 + (secp256k1_rand32()&7); - secidx[i] = secp256k1_rand32() % rsizes[i]; - random_scalar_order(&sec[i]); - random_scalar_order(&k[i]); - if(secp256k1_rand32()&7) { - sec[i] = one; - } - if(secp256k1_rand32()&7) { - k[i] = one; - } - for (j = 0; j < rsizes[i]; j++) { - random_scalar_order(&s[c + j]); - if(secp256k1_rand32()&7) { - s[i] = one; - } - if (j == secidx[i]) { - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubs[c + j], &sec[i]); - } else { - random_group_element_test(&ge); - random_group_element_jacobian_test(&pubs[c + j],&ge); - } - } - c += rsizes[i]; - } - CHECK(secp256k1_borromean_sign(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, e0, s, pubs, k, sec, rsizes, secidx, nrings, m, 32)); - CHECK(secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32)); - i = secp256k1_rand32() % c; - secp256k1_scalar_negate(&s[i],&s[i]); - CHECK(!secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32)); - secp256k1_scalar_negate(&s[i],&s[i]); - secp256k1_scalar_set_int(&one, 1); - for(j = 0; j < 4; j++) { - i = secp256k1_rand32() % c; - if (secp256k1_rand32() & 1) { - secp256k1_gej_double_var(&pubs[i],&pubs[i], NULL); - } else { - secp256k1_scalar_add(&s[i],&s[i],&one); - } - CHECK(!secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32)); - } -} - -void test_rangeproof(void) { - const uint64_t testvs[11] = {0, 1, 5, 11, 65535, 65537, INT32_MAX, UINT32_MAX, INT64_MAX - 1, INT64_MAX, UINT64_MAX}; - unsigned char commit[33]; - unsigned char commit2[33]; - unsigned char proof[5134]; - unsigned char blind[32]; - unsigned char blindout[32]; - unsigned char message[4096]; - int mlen; - uint64_t v; - uint64_t vout; - uint64_t vmin; - uint64_t minv; - uint64_t maxv; - int len; - int i; - int j; - int k; - secp256k1_rand256(blind); - for (i = 0; i < 11; i++) { - v = testvs[i]; - CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v)); - for (vmin = 0; vmin < (i<9 && i > 0 ? 2 : 1); vmin++) { - len = 5134; - CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, commit, blind, commit, 0, 0, v)); - CHECK(len <= 5134); - mlen = 4096; - CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit, &minv, &maxv, commit, proof, len)); - for (j = 0; j < mlen; j++) { - CHECK(message[j] == 0); - } - CHECK(mlen <= 4096); - CHECK(memcmp(blindout, blind, 32) == 0); - CHECK(vout == v); - CHECK(minv <= v); - CHECK(maxv >= v); - len = 5134; - CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v, commit, blind, commit, -1, 64, v)); - CHECK(len <= 73); - CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit, &minv, &maxv, commit, proof, len)); - CHECK(memcmp(blindout, blind, 32) == 0); - CHECK(vout == v); - CHECK(minv == v); - CHECK(maxv == v); - } - } - secp256k1_rand256(blind); - v = INT64_MAX - 1; - CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v)); - for (i = 0; i < 19; i++) { - len = 5134; - CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, commit, blind, commit, i, 0, v)); - CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit, proof, len)); - CHECK(len <= 5134); - CHECK(minv <= v); - CHECK(maxv >= v); - } - secp256k1_rand256(blind); - { - /*Malleability test.*/ - v = secp256k1_rands64(0, 255); - CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v)); - len = 5134; - CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, commit, blind, commit, 0, 3, v)); - CHECK(len <= 5134); - for (i = 0; i < len*8; i++) { - proof[i >> 3] ^= 1 << (i & 7); - CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit, proof, len)); - proof[i >> 3] ^= 1 << (i & 7); - } - CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit, proof, len)); - CHECK(minv <= v); - CHECK(maxv >= v); - } - memcpy(commit2, commit, 33); - for (i = 0; i < 10 * count; i++) { - int exp; - int min_bits; - v = secp256k1_rands64(0, UINT64_MAX >> (secp256k1_rand32()&63)); - vmin = 0; - if ((v < INT64_MAX) && (secp256k1_rand32()&1)) { - vmin = secp256k1_rands64(0, v); - } - secp256k1_rand256(blind); - CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v)); - len = 5134; - exp = (int)secp256k1_rands64(0,18)-(int)secp256k1_rands64(0,18); - if (exp < 0) { - exp = -exp; - } - min_bits = (int)secp256k1_rands64(0,64)-(int)secp256k1_rands64(0,64); - if (min_bits < 0) { - min_bits = -min_bits; - } - CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, commit, blind, commit, exp, min_bits, v)); - CHECK(len <= 5134); - mlen = 4096; - CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit, &minv, &maxv, commit, proof, len)); - for (j = 0; j < mlen; j++) { - CHECK(message[j] == 0); - } - CHECK(mlen <= 4096); - CHECK(memcmp(blindout, blind, 32) == 0); - CHECK(vout == v); - CHECK(minv <= v); - CHECK(maxv >= v); - CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit, &minv, &maxv, commit, proof, len)); - memcpy(commit2, commit, 33); - } - for (j = 0; j < 10; j++) { - for (i = 0; i < 96; i++) { - secp256k1_rand256(&proof[i * 32]); - } - for (k = 0; k < 128; k++) { - len = k; - CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit2, proof, len)); - } - len = secp256k1_rands64(0, 3072); - CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit2, proof, len)); - } -} - -void run_borromean(void) { - int i; - for (i = 0; i < 10*count; i++) { - test_borromean(); - } -} - -void run_rangeproof(void) { - test_rangeproof(); -} +#ifdef ENABLE_MODULE_SCHNORR +# include "modules/schnorr/tests_impl.h" +#endif +#ifdef ENABLE_MODULE_RANGEPROOF +# include "modules/rangeproof/tests_impl.h" +#endif int main(int argc, char **argv) { unsigned char seed16[16] = {0}; unsigned char run32[32] = {0}; - memset(seed16, 0, sizeof(seed16)); /* find iteration count */ if (argc > 1) { count = strtol(argv[1], NULL, 0); @@ -2728,7 +2509,7 @@ int main(int argc, char **argv) { /* initialize */ run_context_tests(); - ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_COMMIT | SECP256K1_CONTEXT_RANGEPROOF); + ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); if (secp256k1_rand32() & 1) { secp256k1_rand256(run32); @@ -2737,10 +2518,6 @@ int main(int argc, char **argv) { run_util_tests(); - run_pedersen(); - run_borromean(); - run_rangeproof(); - run_sha256_tests(); run_hmac_sha256_tests(); run_rfc6979_hmac_sha256_tests(); @@ -2771,11 +2548,18 @@ int main(int argc, char **argv) { run_ecmult_chain(); run_ecmult_constants(); run_ecmult_gen_blind(); - run_ecmult_points_ecmult(); + run_ecmult_const_tests(); + run_ec_combine(); + /* endomorphism tests */ +#ifdef USE_ENDOMORPHISM + run_endomorphism_tests(); +#endif + +#ifdef ENABLE_MODULE_ECDH /* ecdh tests */ run_ecdh_tests(); - run_ecdh_api_tests(); +#endif /* ecdsa tests */ run_random_pubkeys(); @@ -2786,8 +2570,14 @@ int main(int argc, char **argv) { run_ecdsa_openssl(); #endif +#ifdef ENABLE_MODULE_SCHNORR /* Schnorr tests */ - run_schnorr_sign_verify(); + run_schnorr_tests(); +#endif + +#ifdef ENABLE_MODULE_RANGEPROOF + run_rangeproof_tests(); +#endif secp256k1_rand256(run32); printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h index abe3a00c43..7e7581f172 100644 --- a/src/secp256k1/src/util.h +++ b/src/secp256k1/src/util.h @@ -13,9 +13,13 @@ #include #include -#include #include +typedef struct { + void (*fn)(const char *text, void* data); + void* data; +} callback_t; + #ifdef DETERMINISTIC #define TEST_FAILURE(msg) do { \ fprintf(stderr, "%s\n", msg); \ @@ -48,26 +52,50 @@ } while(0) #endif -/* Like assert(), but safe to use on expressions with side effects. */ -#ifndef NDEBUG -#define DEBUG_CHECK CHECK -#else -#define DEBUG_CHECK(cond) do { (void)(cond); } while(0) -#endif - -/* Like DEBUG_CHECK(), but when VERIFY is defined instead of NDEBUG not defined. */ +/* Like assert(), but when VERIFY is defined, and side-effect safe. */ #ifdef VERIFY #define VERIFY_CHECK CHECK +#define VERIFY_SETUP(stmt) do { stmt; } while(0) #else #define VERIFY_CHECK(cond) do { (void)(cond); } while(0) +#define VERIFY_SETUP(stmt) #endif -static SECP256K1_INLINE void *checked_malloc(size_t size) { +static SECP256K1_INLINE void *checked_malloc(const callback_t* cb, size_t size) { void *ret = malloc(size); - CHECK(ret != NULL); + if (ret == NULL) { + cb->fn("Out of memory", cb->data); + } return ret; } +/* Extract the sign of an int64, take the abs and return a uint64, constant time. */ +SECP256K1_INLINE static int secp256k1_sign_and_abs64(uint64_t *out, int64_t in) { + uint64_t mask0, mask1; + int ret; + ret = in < 0; + mask0 = ret + ~((uint64_t)0); + mask1 = ~mask0; + *out = (uint64_t)in; + *out = (*out & mask0) | ((~*out + 1) & mask1); + return ret; +} + +SECP256K1_INLINE static int secp256k1_clz64_var(uint64_t x) { + int ret; + if (!x) { + return 64; + } +# if defined(HAVE_BUILTIN_CLZLL) + ret = __builtin_clzll(x); +# else + /*FIXME: debruijn fallback. */ + for (ret = 0; ((x & (1ULL << 63)) == 0); x <<= 1, ret++); +# endif + return ret; + +} + /* Macro for restrict, when available and not in a VERIFY build. */ #if defined(SECP256K1_BUILD) && defined(VERIFY) # define SECP256K1_RESTRICT @@ -102,32 +130,4 @@ static SECP256K1_INLINE void *checked_malloc(size_t size) { SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; #endif -/* Extract the sign of an int64, take the abs and return a uint64, constant time. */ -SECP256K1_INLINE static int secp256k1_sign_and_abs64(uint64_t *out, int64_t in) { - uint64_t mask0, mask1; - int ret; - ret = in < 0; - mask0 = ret + ~((uint64_t)0); - mask1 = ~mask0; - *out = (uint64_t)in; - *out = (*out & mask0) | ((~*out + 1) & mask1); - return ret; -} - -SECP256K1_INLINE static int secp256k1_clz64_var(uint64_t x) { - int ret; - if (!x) { - return 64; - } -# if defined(HAVE_BUILTIN_CLZLL) - ret = __builtin_clzll(x); -# else - /*FIXME: debruijn fallback. */ - for (ret = 0; ((x & (1ULL << 63)) == 0); x <<= 1, ret++); -# endif - return ret; - -} - - #endif diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json index 899725a9ce..df4c27ebc2 100644 --- a/src/test/data/script_invalid.json +++ b/src/test/data/script_invalid.json @@ -519,115 +519,115 @@ ["Automatically generated test cases"], [ - "0x41 0x40935c44b798ebd79da7a83cefe2310c7cc2e60aa4eb353417d0f7646fa9886dcde7cc347575f5ebe004e4c3bdfe58bd92012177ba7615eb2dfdce59cbc20dd201", + "0x41 0x0d676d409b7e64a10317ee8ede493482f90c3cdbf81cefe3c22f1326c53087352fa61ba8a289273706c3d80b3030b679be674ec2e40c3692067d063b1c3c06b801", "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "", "P2PK, bad sig" ], [ - "0x41 0x2e98609c89cd86386b5b42d9b992028217a3d198387c8ff7e5980af68e25fe27760abb21a3f90b9f7757966d8658ad6af32f84afda6f739dd685fc460e31f3e001 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", + "0x41 0x82501cd8c9032f48e70e698cc4553b3e546be50657ea31322e0a2435918c7f682e790b98b7e337c51fee33e81c5d8bcb28efbf623258ec94b2d7afac09bb550901 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", "DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG", "", "P2PKH, bad pubkey" ], [ - "0x41 0x4f0d68fe60fe86298dc48d7a2d8416c49a037d9471b849e3408bdd417e7282a8169b7610632cdc5241cc554e239147cebdf3e8b9be2e08777a415e6d5fc0500d01", + "0x41 0x040f320c2201b8aa7daa5e30d2be94564e6aac8cf6d9c74bd19e39839b4405a3bbcce62918cd7f1b8e26965c9634543c806fc032277be0b198f21ab106ee90ca01", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "", "P2PK anyonecanpay marked with normal hashtype" ], [ - "0x41 0x9e6312ff6b1e091d1874a6ae0402fd3e5554d44b77e26a1d3aa3c73a68fb41cf4ad2a561e52929769421cf0c6e0ea2bf7ffcf0511b8e16f335f314b358b1202901 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", + "0x41 0xa6637f9b08d85bab62929779dc1d0d7627e542d27a9b83e81b1f5dea098b9f56913be9fbeca898a60e26c18969d9458e83f782a7832f3d0346dddc79447d078301 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", "P2SH", "P2SH(P2PK), bad redeemscript" ], [ - "0x41 0x06971e9df6c53de39238b9aea03f586aaf194b48e0dfdb99cd3fc3e446ac358b17361fc415445110a44b97cfe7692c2666ad6fb72a1a33d3cb449cc9f4d0443301 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", + "0x41 0xa594654c074e82156a9d47a46fd78f105e0d200eae1fb198c95edb297fbf4bbbe7292da1c68fa7563ee1f448ffb1cc00757c4e9b52930bef0bcef3cc7f044ce701 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", "P2SH", "P2SH(P2PKH), bad sig" ], [ - "0 0x41 0x434260ba2a37f605c8c5959abd764d1785ed5678f5112875e8d708db790e0f4d6d7b42b291b2a66dae09140852f60e6ee37ab2c031387a6e8e2ba15179463bae01 0x41 0xe64e579c3cdb1c5d99ed3ac4dd73095554860eec64ac40924772138eb3e3765675decfb264e69865465fe3e7d84992791ed23be1d96b1b49f3eb5e6866ab83e601 0", + "0 0x41 0xb852c8c7207c813acd1e002fb98a63327324db6474782558f1726750df6544a3b898c43bb0ddee5848c34e45b719cee1559d8d74b789eef83665d43dca5f243c01 0x41 0xd8bf0745999d38500ecc503ca0941c5d7103272428ca6733cad1ae4b19e97d0b021479b53242476dbab1b19d10c065d0373ffa01f0bfeb15e72c941ab7bc8c1b01 0", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", "3-of-3, 2 sigs" ], [ - "0 0x41 0x8b03faf3dcd30dde4ec45aa313a51de01769d1e25233eb68b732f45b3949cfb4f77c5ad4629ce73a310d449cae3bd4449b0a10fa07112cdbfb2cee2025b2691b01 0 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", + "0 0x41 0xc98cdd05746c1232eee979e134680a47b53f14f484a35aaf4ece9487e1010f4240ed76d2acf6dc641b66ed1c1d331d663ff47ba749f8f50f7188f9e6c230944b01 0 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", "P2SH", "P2SH(2-of-3), 1 sig" ], [ - "0x41 0x98b330e1a8662c34ec3982e1db35a1409a7a472db6bcb0db7af4a02bf00b051affd2a4dfd70a96aea9b08e64e984e79c963407f62d9b7ff622dfd4438468b88801", + "0x41 0x4196ce2d3cfbb5f81aa894153cbf59a6a07281a8b2beb14f0d5ba034f9a5c41de0f5f4a2d9d932c961e1e500bdae14dac64cc0ed5ede10cb7df62a2616a618cd01", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "STRICTENC", "P2PK with hybrid pubkey" ], [ - "0x41 0xe9c1ca40b01fe16d8ddb6128496616ebbff6ef1fa214b8dd46f2d9fb143f307f0e6813c4be37790d86826feb13e0818974089440ff9a47a030c2dbfd1a6af07d01", + "0x41 0x710f8d3e4abdeffc9c715aa660f76243d0b219e3a0087b8bdd928a709870e9781a43a6bd870beefc5865d2a548d11439ac51aa7e2e57f287471ed215f0f6e70801", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", "", "P2PK NOT with hybrid pubkey but no STRICTENC" ], [ - "0x41 0xe9c1ca40b01fe16d8ddb6128496616ebbff6ef1fa214b8dd46f2d9fb143f307f0e6813c4be37790d86826feb13e0818974089440ff9a47a030c2dbfd1a6af07d01", + "0x41 0x710f8d3e4abdeffc9c715aa660f76243d0b219e3a0087b8bdd928a709870e9781a43a6bd870beefc5865d2a548d11439ac51aa7e2e57f287471ed215f0f6e70801", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", "STRICTENC", "P2PK NOT with hybrid pubkey" ], [ - "0x41 0xe9c1ca40b01fe16d8ddb6028496616ebbff6ef1fa214b8dd46f2d9fb143f307f0e6813c4be37790d86826feb13e0818974089440ff9a47a030c2dbfd1a6af07d01", + "0x41 0x710f8d3e4abdeffc9c715ba660f76243d0b219e3a0087b8bdd928a709870e9781a43a6bd870beefc5865d2a548d11439ac51aa7e2e57f287471ed215f0f6e70801", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", "STRICTENC", "P2PK NOT with invalid hybrid pubkey" ], [ - "0 0x41 0x5ab9dada5869f774573e9749c95f1ae31ff416c50232d5ee27bc16ab511a84dae9575afe8733869295b62f1729a495bcd217e9c50b609c9911675fec4c194a7801", + "0 0x41 0x099981456a47f7d9dbe190985794ae28449b3cda259c40db07ad3b5b6c8fa1dab4506a5d519b8fab88a097ef45bbad8b880594596132cfa34b913929bc98c1ef01", "1 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 2 CHECKMULTISIG", "STRICTENC", "1-of-2 with the first 1 hybrid pubkey" ], [ - "0x41 0x3e97989da4fd193f094caaebbdb75522564604f90673bf276164522d3c0528003d039e65ced8d9a3b52299f75f25344b33a1b6d36f1946e3e62392f10a86677005", + "0x41 0x91896eb451aa34bedeedeb8e042c5de0d1774fa6151705eec402aa949523fad55c7067d80542f01892ff89ba1a703aca6adc9038f1d4e8541c66212512f4620505", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "STRICTENC", "P2PK with undefined hashtype" ], [ - "0x41 0x7494b1309e9447cdc23dbc92ff3ca33a2a8bd42e5df669fa8ae4b4d65435069b4ab31b52eea2b8ab2854d9d40a12c262bcc691eb9dd20afed3fe8f73fbb7cd7605", + "0x41 0xe2ae57ffe4b6858a9b097023835e4ee68faf7f8406b149790ba76892cbc650513a4a76f86aef2b94e85dc9dee3edb835488e70a9db0383adaca5441ac4e6a75105", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT", "STRICTENC", "P2PK NOT with invalid sig and undefined hashtype" ], [ - "1 0x41 0x434260ba2a37f605c8c5959abd764d1785ed5678f5112875e8d708db790e0f4d6d7b42b291b2a66dae09140852f60e6ee37ab2c031387a6e8e2ba15179463bae01 0x41 0xe64e579c3cdb1c5d99ed3ac4dd73095554860eec64ac40924772138eb3e3765675decfb264e69865465fe3e7d84992791ed23be1d96b1b49f3eb5e6866ab83e601 0x41 0x095bce722466be45b3b110f8e92be4c3ae17abefccb73c84fbdd458b667646ea8b3dea40fccf036985e5dcd43ef1e6c781c99bcea36691d9f90ae958307cc48901", + "1 0x41 0xb852c8c7207c813acd1e002fb98a63327324db6474782558f1726750df6544a3b898c43bb0ddee5848c34e45b719cee1559d8d74b789eef83665d43dca5f243c01 0x41 0xd8bf0745999d38500ecc503ca0941c5d7103272428ca6733cad1ae4b19e97d0b021479b53242476dbab1b19d10c065d0373ffa01f0bfeb15e72c941ab7bc8c1b01 0x41 0xaaa573ffdcf283a4aa608b81540e0bab4a8d2aa2e8bffe030736831c3399e360c78eab9ebf8da9d98c6306409ad752fcbc762222828dc3e54a7d2594d7fb728b01", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "NULLDUMMY", "3-of-3 with nonzero dummy" ], [ - "1 0x41 0x1040558786f096861c0f202bf12e8de33e2c4354a7c8d9fd625bdccd350fc2ffa6cb54fc126652e9d89b757e478c10d336c14efb7342afaf688067321a2be2d901 0x41 0x254dc8cb5633fe5a9fb6951b8987c1bfeb8c69c876e1c4dec588d1f9708853260a5c386740ed87394537a6b1e72f942480c56f43c5d281feae37f8eb1d7b611c01 0x41 0xbb03ec9b47446fb988049e7e0f97f8c60528886f50d4679ae4d6e8c55558314257031b5c18b8424d409d41707177dc0eb571dd5c7083a454a52a7dd52aaa550701", + "1 0x41 0xc5ade7edc471ebf6f93cfdcd081efc826e42c90b9608257336917fe19dd49f1f9d9025cf85851990010e76f90fa2a10091aa20d7b4714c1dbbe35d7ab4ae7af901 0x41 0x636bac4be2a9d2bb9efb027b3455a09b942904b15f421d1578f058fb35ec8116a80690cbc2f994596d3ce9469bff6aa0a6a5a850abec57f70c32a51cd6175b1401 0x41 0x0dfa9ea0fd70ff9a86a83d9e41408b90e26797549977698b4362c8f41ce7201caea6c53a79b99065d09cd338bf7f262756b81ddae4e4d1626e41f7945272576801", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT", "NULLDUMMY", "3-of-3 NOT with invalid sig with nonzero dummy" ], [ - "0 0x41 0x2d35edb5b8539821925fd0315e30882e7db9a1b4b697a0f339b77a3835216ffae2d196dd275901c78877942a44da3ad91bc9702e134545c5a7f4b5da4170fd8301 DUP", + "0 0x41 0xde2fb5c3ac521e16c92a44a31bffc213dbafbf39fc370ec3aab76e2af7e4be6d33f1dea322991d3921ca483fd3db8b9f5f3f9a42b6ca3e9b561d963887d7c8b101 DUP", "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", "SIGPUSHONLY", "2-of-2 with two identical keys and sigs pushed using OP_DUP" ], [ - "0x41 0x63025a2ea40b83adae916ef3d30b8e1cdc2283847d024ea8b6c33d199a2933652de1aeef0deddd7160ba6b149cae87231da61367e88f1ef3257b33e3fbfd08b801 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", + "0x41 0x2e3cee81c63207d7f4730be4be45c9b5cec7316494d5d10da84e26196a270051542401318e8871020a60f7beedf68202327358fdb3303945d6f793f1232bc2fb01 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "", "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY" ], [ - "0x41 0x63025a2ea40b83adae916ef3d30b8e1cdc2283847d024ea8b6c33d199a2933652de1aeef0deddd7160ba6b149cae87231da61367e88f1ef3257b33e3fbfd08b801 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", + "0x41 0x2e3cee81c63207d7f4730be4be45c9b5cec7316494d5d10da84e26196a270051542401318e8871020a60f7beedf68202327358fdb3303945d6f793f1232bc2fb01 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "SIGPUSHONLY", "P2SH(P2PK) with non-push scriptSig" diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json index 6be140bea2..23c10d341b 100644 --- a/src/test/data/script_valid.json +++ b/src/test/data/script_valid.json @@ -767,85 +767,85 @@ ["Automatically generated test cases"], [ - "0x41 0x40935c44b798ebd79da7a93cefe2310c7cc2e60aa4eb353417d0f7646fa9886dcde7cc347575f5ebe004e4c3bdfe58bd92012177ba7615eb2dfdce59cbc20dd201", + "0x41 0x0d676d409b7e64a10317ef8ede493482f90c3cdbf81cefe3c22f1326c53087352fa61ba8a289273706c3d80b3030b679be674ec2e40c3692067d063b1c3c06b801", "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "", "P2PK" ], [ - "0x41 0xcfbcd6d7c65ac52b50bb79ad3ae34f3caf4ceef26640bc7321cc0684ca0b79a24c6586c66997a994de4066a615fee25770d8990d46aaa29a377c680541fa226f01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508", + "0x41 0x5f4a78c77c1b27aa28abc0f33c9fc0dc4a959fb554d73d8356c79f6db5083537cb195f7ca14644300dbe0b206789838f6ed6e336f8bd62ccc240f77c1921fe0901 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508", "DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG", "", "P2PKH" ], [ - "0x41 0x4f0d68fe60fe86298dc48d7a2d8416c49a037d9471b849e3408bdd417e7282a8169b7610632cdc5241cc554e239147cebdf3e8b9be2e08777a415e6d5fc0500d81", + "0x41 0x040f320c2201b8aa7daa5e30d2be94564e6aac8cf6d9c74bd19e39839b4405a3bbcce62918cd7f1b8e26965c9634543c806fc032277be0b198f21ab106ee90ca81", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "", "P2PK anyonecanpay" ], [ - "0x41 0x9e6312ff6b1e091d1874a6ae0402fd3e5554d44b77e26a1d3aa3c73a68fb41cf4ad2a561e52929769421cf0c6e0ea2bf7ffcf0511b8e16f335f314b358b1202901 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", + "0x41 0xa6637f9b08d85bab62929779dc1d0d7627e542d27a9b83e81b1f5dea098b9f56913be9fbeca898a60e26c18969d9458e83f782a7832f3d0346dddc79447d078301 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", "P2SH", "P2SH(P2PK)" ], [ - "0x41 0x06971e9df6c53de39238b9aea03f586aaf194b48e0dfdb99cd3fc3e446ac358b17361fc415445110a44b97cfe7692c2666ad6fb72a1a33d3cb449cc9f4d0443301 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", + "0x41 0xa594654c074e82156a9d47a46fd78f105e0d200eae1fb198c95edb297fbf4bbbe7292da1c68fa7563ee1f448ffb1cc00757c4e9b52930bef0bcef3cc7f044ce701 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", "", "P2SH(P2PKH), bad sig but no VERIFY_P2SH" ], [ - "0 0x41 0x434260ba2a37f605c8c5959abd764d1785ed5678f5112875e8d708db790e0f4d6d7b42b291b2a66dae09140852f60e6ee37ab2c031387a6e8e2ba15179463bae01 0x41 0xe64e579c3cdb1c5d99ed3ac4dd73095554860eec64ac40924772138eb3e3765675decfb264e69865465fe3e7d84992791ed23be1d96b1b49f3eb5e6866ab83e601 0x41 0x095bce722466be45b3b110f8e92be4c3ae17abefccb73c84fbdd458b667646ea8b3dea40fccf036985e5dcd43ef1e6c781c99bcea36691d9f90ae958307cc48901", + "0 0x41 0xb852c8c7207c813acd1e002fb98a63327324db6474782558f1726750df6544a3b898c43bb0ddee5848c34e45b719cee1559d8d74b789eef83665d43dca5f243c01 0x41 0xd8bf0745999d38500ecc503ca0941c5d7103272428ca6733cad1ae4b19e97d0b021479b53242476dbab1b19d10c065d0373ffa01f0bfeb15e72c941ab7bc8c1b01 0x41 0xaaa573ffdcf283a4aa608b81540e0bab4a8d2aa2e8bffe030736831c3399e360c78eab9ebf8da9d98c6306409ad752fcbc762222828dc3e54a7d2594d7fb728b01", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", "3-of-3" ], [ - "0 0x41 0x8b03faf3dcd30dde4ec45aa313a51de01769d1e25233eb68b732f45b3949cfb4f77c5ad4629ce73a310d449cae3bd4449b0a10fa07112cdbfb2cee2025b2691b01 0x41 0xd1f2e618b835f2d0dbb42dbbe2318d80be504088489b5db168ba94beea2faa7dc2f614b5ba609bd51b9cee9709da4cef54e45a153c69193e487c29ec102f04a901 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", + "0 0x41 0xc98cdd05746c1232eee979e134680a47b53f14f484a35aaf4ece9487e1010f4240ed76d2acf6dc641b66ed1c1d331d663ff47ba749f8f50f7188f9e6c230944b01 0x41 0xe586a5bd52a49f3a7be3dbd3d03f5401f8d0d5b512e0d338a594cd09caad40234af81dca46da41e9926ec601655635af8d1ec75e8864808885ecf1c2555afdf801 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", "P2SH", "P2SH(2-of-3)" ], [ - "0x41 0x98b330e1a8662c34ec3982e1db35a1409a7a472db6bcb0db7af4a02bf00b051affd2a4dfd70a96aea9b08e64e984e79c963407f62d9b7ff622dfd4438468b88801", + "0x41 0x4196ce2d3cfbb5f81aa894153cbf59a6a07281a8b2beb14f0d5ba034f9a5c41de0f5f4a2d9d932c961e1e500bdae14dac64cc0ed5ede10cb7df62a2616a618cd01", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "", "P2PK with hybrid pubkey but no STRICTENC" ], [ - "0 0x41 0x881e9d32f9d565dd4097fe5816bfb1d7196a27b4e83cb246f061f37844418d972d9feb51be3d6308061841284143cd72223a09afce1817b6377e4fd430da105301", + "0 0x41 0x5d781335e74c423e6b5b26b20b3fe6760e0ce4395f16462a8f69c019661618af0550aad9d20c56b8b156a33aa428f3b026a4b79c807a500df5f9c4de3b3cc21d01", "1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", "", "1-of-2 with the second 1 hybrid pubkey and no STRICTENC" ], [ - "0 0x41 0x881e9d32f9d565dd4097fe5816bfb1d7196a27b4e83cb246f061f37844418d972d9feb51be3d6308061841284143cd72223a09afce1817b6377e4fd430da105301", + "0 0x41 0x5d781335e74c423e6b5b26b20b3fe6760e0ce4395f16462a8f69c019661618af0550aad9d20c56b8b156a33aa428f3b026a4b79c807a500df5f9c4de3b3cc21d01", "1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", "STRICTENC", "1-of-2 with the second 1 hybrid pubkey" ], [ - "0x41 0x3e97989da4fd193f094caaebbdb75522564604f90673bf276164522d3c0528003d039e65ced8d9a3b52299f75f25344b33a1b6d36f1946e3e62392f10a86677005", + "0x41 0x91896eb451aa34bedeedeb8e042c5de0d1774fa6151705eec402aa949523fad55c7067d80542f01892ff89ba1a703aca6adc9038f1d4e8541c66212512f4620505", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "", "P2PK with undefined hashtype but no STRICTENC" ], [ - "1 0x41 0x434260ba2a37f605c8c5959abd764d1785ed5678f5112875e8d708db790e0f4d6d7b42b291b2a66dae09140852f60e6ee37ab2c031387a6e8e2ba15179463bae01 0x41 0xe64e579c3cdb1c5d99ed3ac4dd73095554860eec64ac40924772138eb3e3765675decfb264e69865465fe3e7d84992791ed23be1d96b1b49f3eb5e6866ab83e601 0x41 0x095bce722466be45b3b110f8e92be4c3ae17abefccb73c84fbdd458b667646ea8b3dea40fccf036985e5dcd43ef1e6c781c99bcea36691d9f90ae958307cc48901", + "1 0x41 0xb852c8c7207c813acd1e002fb98a63327324db6474782558f1726750df6544a3b898c43bb0ddee5848c34e45b719cee1559d8d74b789eef83665d43dca5f243c01 0x41 0xd8bf0745999d38500ecc503ca0941c5d7103272428ca6733cad1ae4b19e97d0b021479b53242476dbab1b19d10c065d0373ffa01f0bfeb15e72c941ab7bc8c1b01 0x41 0xaaa573ffdcf283a4aa608b81540e0bab4a8d2aa2e8bffe030736831c3399e360c78eab9ebf8da9d98c6306409ad752fcbc762222828dc3e54a7d2594d7fb728b01", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", "3-of-3 with nonzero dummy but no NULLDUMMY" ], [ - "0 0x41 0x2d35edb5b8539821925fd0315e30882e7db9a1b4b697a0f339b77a3835216ffae2d196dd275901c78877942a44da3ad91bc9702e134545c5a7f4b5da4170fd8301 DUP", + "0 0x41 0xde2fb5c3ac521e16c92a44a31bffc213dbafbf39fc370ec3aab76e2af7e4be6d33f1dea322991d3921ca483fd3db8b9f5f3f9a42b6ca3e9b561d963887d7c8b101 DUP", "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", "", "2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY" ], [ - "0 0x41 0x2d35edb5b8539821925fd0315e30882e7db9a1b4b697a0f339b77a3835216ffae2d196dd275901c78877942a44da3ad91bc9702e134545c5a7f4b5da4170fd8301 0x41 0x2d35edb5b8539821925fd0315e30882e7db9a1b4b697a0f339b77a3835216ffae2d196dd275901c78877942a44da3ad91bc9702e134545c5a7f4b5da4170fd8301", + "0 0x41 0xde2fb5c3ac521e16c92a44a31bffc213dbafbf39fc370ec3aab76e2af7e4be6d33f1dea322991d3921ca483fd3db8b9f5f3f9a42b6ca3e9b561d963887d7c8b101 0x41 0xde2fb5c3ac521e16c92a44a31bffc213dbafbf39fc370ec3aab76e2af7e4be6d33f1dea322991d3921ca483fd3db8b9f5f3f9a42b6ca3e9b561d963887d7c8b101", "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", "SIGPUSHONLY", "2-of-2 with two identical keys and sigs pushed" diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 9d9c2f9a41..e0b349b22d 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -172,11 +172,11 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK(key1.Sign(hashMsg, detsig)); BOOST_CHECK(key1C.Sign(hashMsg, detsigc)); BOOST_CHECK(detsig == detsigc); - BOOST_CHECK_EQUAL(HexStr(detsig), "12cb87b6c94fab15d458e97ed5eeffdd6d0253c0711c5ee3097da3cef1c8ef071ec0f7f495ccb15d41cca8d371901fa5a649bd06d15e7f78b1627cceef333b11"); + BOOST_CHECK_EQUAL(HexStr(detsig), "66fd0c716c5d11ecc91fc2197af0e66cfd262ec2e6fb2819706930532d07b0236e43dd1586d12b6498173318c99e95413c8e9763b59a33cccd1328e880151e57"); BOOST_CHECK(key2.Sign(hashMsg, detsig)); BOOST_CHECK(key2C.Sign(hashMsg, detsigc)); BOOST_CHECK(detsig == detsigc); - BOOST_CHECK_EQUAL(HexStr(detsig), "7f4d0435d40be2a2c20a55720e901acf1ec5fc574fd04c41417c5f625d688be0939ec6f72a4823744cfa24c24dc98a6a9015dc391ace1c27d10db7abbbdca8f9"); + BOOST_CHECK_EQUAL(HexStr(detsig), "f7a0ff919b2c2282846f60bc319b99ddd82ee7f88b75a053a5005de5a992eea56413aa2f5c6167babac05c8a2171253aa63b6b16a0a1e72587bfc4c5e6c32547"); BOOST_CHECK(key1.SignCompact(hashMsg, detsig)); BOOST_CHECK(key1C.SignCompact(hashMsg, detsigc)); BOOST_CHECK_EQUAL(HexStr(detsig), "1c5dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6");