Merge pull request #46

a671356 Squashed 'src/secp256k1/' changes from 22f60a6..71ed475 (Pieter Wuille)
77269e0 Update to new libsecp256k1 (Pieter Wuille)
This commit is contained in:
Pieter Wuille 2015-08-07 02:37:23 +02:00
commit 601116fd2d
No known key found for this signature in database
GPG key ID: 57896D2FF8F0B657
73 changed files with 3955 additions and 2307 deletions

View file

@ -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

View file

@ -6,14 +6,17 @@
#include "util.h"
#include <secp256k1.h>
#include <secp256k1_rangeproof.h>
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<std::vector<unsigned char> >& 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);

View file

@ -9,6 +9,7 @@
#include <assert.h>
#include <secp256k1.h>
#include <secp256k1_rangeproof.h>
/**
* calculate number of bytes for the bitmask, and its number of non-zero bytes

View file

@ -12,6 +12,8 @@
#include "random.h"
#include <secp256k1.h>
#include <secp256k1_ecdh.h>
#include <secp256k1_schnorr.h>
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<unsigned char>& 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;
}

View file

@ -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.

View file

@ -5,6 +5,8 @@
#include "pubkey.h"
#include <secp256k1.h>
#include <secp256k1_rangeproof.h>
#include <secp256k1_schnorr.h>
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<unsigned char>& 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<unsigned cha
return false;
int recid = (vchSig[0] - 27) & 3;
bool fComp = ((vchSig[0] - 27) & 4) != 0;
int pubkeylen = 65;
if (!secp256k1_ecdsa_recover_compact(secp256k1_context, (const unsigned char*)&hash, &vchSig[1], (unsigned char*)begin(), &pubkeylen, fComp, recid))
secp256k1_pubkey_t pubkey;
secp256k1_ecdsa_signature_t sig;
if (!secp256k1_ecdsa_signature_parse_compact(secp256k1_context, &sig, &vchSig[1], recid)) {
return false;
assert((int)size() == pubkeylen);
}
if (!secp256k1_ecdsa_recover(secp256k1_context, hash.begin(), &sig, &pubkey)) {
return false;
}
unsigned char pub[65];
int publen = 0;
secp256k1_ec_pubkey_serialize(secp256k1_context, pub, &publen, &pubkey, fComp);
Set(pub, pub + publen);
return true;
}
bool CPubKey::IsFullyValid() const {
if (!IsValid())
return false;
if (!secp256k1_ec_pubkey_verify(secp256k1_context, begin(), size()))
secp256k1_pubkey_t pubkey;
if (!secp256k1_ec_pubkey_parse(secp256k1_context, &pubkey, begin(), size()))
return false;
return true;
}
@ -42,10 +56,14 @@ bool CPubKey::IsFullyValid() const {
bool CPubKey::Decompress() {
if (!IsValid())
return false;
int clen = size();
int ret = secp256k1_ec_pubkey_decompress(secp256k1_context, (unsigned char*)begin(), &clen);
assert(ret);
assert(clen == (int)size());
secp256k1_pubkey_t pubkey;
if (!secp256k1_ec_pubkey_parse(secp256k1_context, &pubkey, &(*this)[0], size())) {
return false;
}
unsigned char pub[65];
int publen = 0;
secp256k1_ec_pubkey_serialize(secp256k1_context, pub, &publen, &pubkey, false);
Set(pub, pub + publen);
return true;
}
@ -56,9 +74,18 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, unsigned char ccChild[32], unsigned i
unsigned char out[64];
BIP32Hash(cc, nChild, *begin(), begin()+1, out);
memcpy(ccChild, out+32, 32);
pubkeyChild = *this;
bool ret = secp256k1_ec_pubkey_tweak_add(secp256k1_context, (unsigned char*)pubkeyChild.begin(), pubkeyChild.size(), out);
return ret;
secp256k1_pubkey_t pubkey;
if (!secp256k1_ec_pubkey_parse(secp256k1_context, &pubkey, &(*this)[0], size())) {
return false;
}
if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context, &pubkey, out)) {
return false;
}
unsigned char pub[33];
int publen = 0;
secp256k1_ec_pubkey_serialize(secp256k1_context, pub, &publen, &pubkey, 1);
pubkeyChild.Set(pub, pub + publen);
return true;
}
void CExtPubKey::Encode(unsigned char code[74]) const {
@ -90,8 +117,10 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const {
void ECC_Verify_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_VERIFY);
assert(ctx != NULL);
secp256k1_pedersen_context_initialize(ctx);
secp256k1_rangeproof_context_initialize(ctx);
secp256k1_context = ctx;
}

View file

@ -26,13 +26,15 @@
#include <boost/assign/list_of.hpp>
#include "json/json_spirit_utils.h"
#include "json/json_spirit_value.h"
#include <secp256k1.h>
#include <secp256k1_rangeproof.h>
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 {

View file

@ -1462,7 +1462,11 @@ bool EvalScript(vector<vector<unsigned char> >& 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));
}
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 <bonzini@gnu.org>
#
# 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
])

View file

@ -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"

View file

@ -5,8 +5,6 @@
extern "C" {
# endif
#include <stdint.h>
# 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
}

View file

@ -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

View file

@ -0,0 +1,186 @@
#ifndef _SECP256K1_RANGEPROOF_
# define _SECP256K1_RANGEPROOF_
# include "secp256k1.h"
# ifdef __cplusplus
extern "C" {
# endif
#include <stdint.h>
/** 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

View file

@ -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

View file

@ -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_

View file

@ -7,18 +7,19 @@
#include <string.h>
#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;
}

View file

@ -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);

View file

@ -6,7 +6,7 @@
#include <stdint.h>
#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;

View file

@ -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). */
}
}
}

View file

@ -8,6 +8,7 @@
#include <string.h>
#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;

View file

@ -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. */

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -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

View file

@ -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
}

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -15,6 +15,7 @@
#include "ecmult_gen.h"
#include "borromean.h"
#include <limits.h>
#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)) {

View file

@ -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

View file

@ -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 <stdint.h>
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

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 <string.h>
#include "schnorr.h"
#include "num.h"
#include "field.h"
#include "group.h"
#include "ecmult.h"
#include "ecmult_gen.h"
/**
* Custom Schnorr-based signature scheme. They support multiparty signing, public key
* recovery and batch validation.
*
* Rationale for verifying R's y coordinate:
* In order to support batch validation and public key recovery, the full R point must
* be known to verifiers, rather than just its x coordinate. In order to not risk
* being more strict in batch validation than normal validation, validators must be
* required to reject signatures with incorrect y coordinate. This is only possible
* by including a (relatively slow) field inverse, or a field square root. However,
* batch validation offers potentially much higher benefits than this cost.
*
* Rationale for having an implicit y coordinate oddness:
* If we commit to having the full R point known to verifiers, there are two mechanism.
* Either include its oddness in the signature, or give it an implicit fixed value.
* As the R y coordinate can be flipped by a simple negation of the nonce, we choose the
* latter, as it comes with nearly zero impact on signing or validation performance, and
* saves a byte in the signature.
*
* Signing:
* Inputs: 32-byte message m, 32-byte scalar key x (!=0), 32-byte scalar nonce k (!=0)
*
* Compute point R = k * G. Reject nonce if R's y coordinate is odd (or negate nonce).
* Compute 32-byte r, the serialization of R's x coordinate.
* Compute scalar h = Hash(r || m). Reject nonce if h == 0 or h >= order.
* Compute scalar s = k - h * x.
* The signature is (r, s).
*
*
* Verification:
* Inputs: 32-byte message m, public key point Q, signature: (32-byte r, scalar s)
*
* Signature is invalid if s >= order.
* Signature is invalid if r >= p.
* Compute scalar h = Hash(r || m). Signature is invalid if h == 0 or h >= order.
* Option 1 (faster for single verification):
* Compute point R = h * Q + s * G. Signature is invalid if R is infinity or R's y coordinate is odd.
* Signature is valid if the serialization of R's x coordinate equals r.
* Option 2 (allows batch validation and pubkey recovery):
* Decompress x coordinate r into point R, with odd y coordinate. Fail if R is not on the curve.
* Signature is valid if R + h * Q + s * G == 0.
*/
static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context_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

View file

@ -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

View file

@ -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. */

View file

@ -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

View file

@ -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

View file

@ -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);

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -13,9 +13,13 @@
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include <stdio.h>
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

View file

@ -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"

View file

@ -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"

View file

@ -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");