mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-18 13:17:55 +02:00
update libsecpt to secp256k1-zkp 4f7a50e173f85113a3c495fba053053fc284dcf6
This commit is contained in:
parent
b8cace5912
commit
34965e7165
51 changed files with 4001 additions and 656 deletions
|
|
@ -93,7 +93,10 @@ TESTS =
|
|||
if USE_TESTS
|
||||
noinst_PROGRAMS += tests
|
||||
tests_SOURCES = src/tests.c
|
||||
tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
|
||||
tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
|
||||
if !ENABLE_COVERAGE
|
||||
tests_CPPFLAGS += -DVERIFY
|
||||
endif
|
||||
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
|
||||
tests_LDFLAGS = -static
|
||||
TESTS += tests
|
||||
|
|
@ -102,7 +105,10 @@ endif
|
|||
if USE_EXHAUSTIVE_TESTS
|
||||
noinst_PROGRAMS += exhaustive_tests
|
||||
exhaustive_tests_SOURCES = src/tests_exhaustive.c
|
||||
exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src $(SECP_INCLUDES)
|
||||
exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDES)
|
||||
if !ENABLE_COVERAGE
|
||||
exhaustive_tests_CPPFLAGS += -DVERIFY
|
||||
endif
|
||||
exhaustive_tests_LDADD = $(SECP_LIBS)
|
||||
exhaustive_tests_LDFLAGS = -static
|
||||
TESTS += exhaustive_tests
|
||||
|
|
@ -170,6 +176,18 @@ if ENABLE_MODULE_RECOVERY
|
|||
include src/modules/recovery/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_GENERATOR
|
||||
include src/modules/generator/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_RANGEPROOF
|
||||
include src/modules/rangeproof/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_WHITELIST
|
||||
include src/modules/whitelist/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_SURJECTIONPROOF
|
||||
include src/modules/surjection/Makefile.am.include
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ AC_PATH_TOOL(STRIP, strip)
|
|||
AX_PROG_CC_FOR_BUILD
|
||||
|
||||
if test "x$CFLAGS" = "x"; then
|
||||
CFLAGS="-O3 -g"
|
||||
CFLAGS="-g"
|
||||
fi
|
||||
|
||||
AM_PROG_CC_C_O
|
||||
|
|
@ -89,6 +89,11 @@ AC_ARG_ENABLE(benchmark,
|
|||
[use_benchmark=$enableval],
|
||||
[use_benchmark=no])
|
||||
|
||||
AC_ARG_ENABLE(coverage,
|
||||
AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis]),
|
||||
[enable_coverage=$enableval],
|
||||
[enable_coverage=no])
|
||||
|
||||
AC_ARG_ENABLE(tests,
|
||||
AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]),
|
||||
[use_tests=$enableval],
|
||||
|
|
@ -129,16 +134,31 @@ AC_ARG_ENABLE(module_recovery,
|
|||
[enable_module_recovery=$enableval],
|
||||
[enable_module_recovery=no])
|
||||
|
||||
AC_ARG_ENABLE(module_generator,
|
||||
AS_HELP_STRING([--enable-module-generator],[enable NUMS generator module (default is no)]),
|
||||
[enable_module_generator=$enableval],
|
||||
[enable_module_generator=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_ENABLE(module_whitelist,
|
||||
AS_HELP_STRING([--enable-module-whitelist],[enable key whitelisting module (default is no)]),
|
||||
[enable_module_whitelist=$enableval],
|
||||
[enable_module_whitelist=no])
|
||||
|
||||
AC_ARG_ENABLE(jni,
|
||||
AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]),
|
||||
[use_jni=$enableval],
|
||||
[use_jni=auto])
|
||||
|
||||
AC_ARG_ENABLE(module_surjectionproof,
|
||||
AS_HELP_STRING([--enable-module-surjectionproof],[enable surjection proof module (default is no)]),
|
||||
[enable_module_surjectionproof=$enableval],
|
||||
[enable_module_surjectionproof=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])
|
||||
|
||||
|
|
@ -159,6 +179,20 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],
|
|||
[ AC_MSG_RESULT([no])
|
||||
])
|
||||
|
||||
if test x"$enable_coverage" = x"yes"; then
|
||||
AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code])
|
||||
CFLAGS="$CFLAGS -O0 --coverage"
|
||||
LDFLAGS="--coverage"
|
||||
else
|
||||
CFLAGS="$CFLAGS -O3"
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([for __builtin_popcount])
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_popcount(0);}]])],
|
||||
[ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_POPCOUNT,1,[Define this symbol if __builtin_popcount is available]) ],
|
||||
[ AC_MSG_RESULT([no])
|
||||
])
|
||||
|
||||
if test x"$use_ecmult_static_precomputation" != x"no"; then
|
||||
save_cross_compiling=$cross_compiling
|
||||
cross_compiling=no
|
||||
|
|
@ -187,6 +221,12 @@ else
|
|||
set_precomp=no
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([for __builtin_clzll])
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() { __builtin_clzll(1);}]])],
|
||||
[ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_CLZLL,1,[Define this symbol if __builtin_clzll is available]) ],
|
||||
[ 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
|
||||
|
|
@ -427,10 +467,22 @@ if test x"$enable_module_recovery" = x"yes"; then
|
|||
AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])
|
||||
fi
|
||||
|
||||
if test x"$enable_module_generator" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_GENERATOR, 1, [Define this symbol to enable the NUMS generator 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
|
||||
|
||||
if test x"$enable_module_whitelist" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_WHITELIST, 1, [Define this symbol to enable the key whitelisting module])
|
||||
fi
|
||||
|
||||
if test x"$enable_module_surjectionproof" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_SURJECTIONPROOF, 1, [Define this symbol to enable the surjection proof module])
|
||||
fi
|
||||
|
||||
AC_C_BIGENDIAN()
|
||||
|
||||
if test x"$use_external_asm" = x"yes"; then
|
||||
|
|
@ -443,6 +495,7 @@ AC_MSG_NOTICE([Using field implementation: $set_field])
|
|||
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 for coverage analysis: $enable_coverage])
|
||||
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
|
||||
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
|
||||
AC_MSG_NOTICE([Using jni: $use_jni])
|
||||
|
|
@ -452,22 +505,45 @@ if test x"$enable_experimental" = x"yes"; then
|
|||
AC_MSG_NOTICE([WARNING: experimental build])
|
||||
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
|
||||
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
|
||||
AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr])
|
||||
AC_MSG_NOTICE([Building NUMS generator module: $enable_module_generator])
|
||||
AC_MSG_NOTICE([Building range proof module: $enable_module_rangeproof])
|
||||
AC_MSG_NOTICE([Building key whitelisting module: $enable_module_whitelist])
|
||||
AC_MSG_NOTICE([Building surjection proof module: $enable_module_surjectionproof])
|
||||
AC_MSG_NOTICE([******])
|
||||
else
|
||||
if test x"$enable_module_schnorr" = x"yes"; then
|
||||
AC_MSG_ERROR([Schnorr signature module is experimental. Use --enable-experimental to allow.])
|
||||
|
||||
if test x"$enable_module_generator" != x"yes"; then
|
||||
if test x"$enable_module_rangeproof" = x"yes"; then
|
||||
AC_MSG_ERROR([Rangeproof module requires the generator module. Use --enable-module-generator to allow.])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$enable_module_rangeproof" != x"yes"; then
|
||||
if test x"$enable_module_whitelist" = x"yes"; then
|
||||
AC_MSG_ERROR([Whitelist module requires the rangeproof module. Use --enable-module-rangeproof to allow.])
|
||||
fi
|
||||
if test x"$enable_module_surjectionproof" = x"yes"; then
|
||||
AC_MSG_ERROR([Surjection proof module requires the rangeproof module. Use --enable-module-rangeproof to allow.])
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if test x"$enable_module_ecdh" = x"yes"; then
|
||||
AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$set_asm" = x"arm"; then
|
||||
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_generator" = x"yes"; then
|
||||
AC_MSG_ERROR([NUMS generator module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_rangeproof" = x"yes"; then
|
||||
AC_MSG_ERROR([Range proof module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_whitelist" = x"yes"; then
|
||||
AC_MSG_ERROR([Key whitelisting module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_surjectionproof" = x"yes"; then
|
||||
AC_MSG_ERROR([Surjection proof module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
|
||||
|
|
@ -477,17 +553,20 @@ AC_SUBST(SECP_INCLUDES)
|
|||
AC_SUBST(SECP_LIBS)
|
||||
AC_SUBST(SECP_TEST_LIBS)
|
||||
AC_SUBST(SECP_TEST_INCLUDES)
|
||||
AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"])
|
||||
AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
|
||||
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"])
|
||||
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
|
||||
AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
|
||||
AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_GENERATOR], [test x"$enable_module_generator" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_RANGEPROOF], [test x"$enable_module_rangeproof" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_WHITELIST], [test x"$enable_module_whitelist" = x"yes"])
|
||||
AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"])
|
||||
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
|
||||
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_SURJECTIONPROOF], [test x"$enable_module_surjectionproof" = x"yes"])
|
||||
|
||||
dnl make sure nothing new is exported so that we don't break the cache
|
||||
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
|
||||
|
|
|
|||
|
|
@ -163,6 +163,8 @@ typedef int (*secp256k1_nonce_function)(
|
|||
*
|
||||
* Returns: a newly created context object.
|
||||
* In: flags: which parts of the context to initialize.
|
||||
*
|
||||
* See also secp256k1_context_randomize.
|
||||
*/
|
||||
SECP256K1_API secp256k1_context* secp256k1_context_create(
|
||||
unsigned int flags
|
||||
|
|
@ -507,7 +509,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
|
|||
secp256k1_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
|
||||
/** Tweak a private key by adding tweak to it.
|
||||
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
|
||||
* uniformly random 32-byte arrays, or if the resulting private key
|
||||
|
|
@ -566,11 +567,24 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
|
|||
const unsigned char *tweak
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Updates the context randomization.
|
||||
/** Updates the context randomization to protect against side-channel leakage.
|
||||
* Returns: 1: randomization successfully updated
|
||||
* 0: error
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state)
|
||||
*
|
||||
* While secp256k1 code is written to be constant-time no matter what secret
|
||||
* values are, it's possible that a future compiler may output code which isn't,
|
||||
* and also that the CPU may not emit the same radio frequencies or draw the same
|
||||
* amount power for all values.
|
||||
*
|
||||
* This function provides a seed which is combined into the blinding value: that
|
||||
* blinding value is added before each multiplication (and removed afterwards) so
|
||||
* that it does not affect function results, but shields against attacks which
|
||||
* rely on any input-dependent behaviour.
|
||||
*
|
||||
* You should call this after secp256k1_context_create or
|
||||
* secp256k1_context_clone, and may call this repeatedly afterwards.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
|
||||
secp256k1_context* ctx,
|
||||
|
|
|
|||
96
src/secp256k1/include/secp256k1_generator.h
Normal file
96
src/secp256k1/include/secp256k1_generator.h
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#ifndef _SECP256K1_GENERATOR_
|
||||
# define _SECP256K1_GENERATOR_
|
||||
|
||||
# include "secp256k1.h"
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Opaque data structure that stores a base point
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 33 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage or transmission, use
|
||||
* the secp256k1_generator_serialize_*.
|
||||
*
|
||||
* Furthermore, it is guaranteed to identical points will have identical
|
||||
* representation, so they can be memcmp'ed.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[33];
|
||||
} secp256k1_generator;
|
||||
|
||||
/** Parse a 33-byte generator byte sequence into a generator object.
|
||||
*
|
||||
* Returns: 1 if input contains a valid generator.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: commit: pointer to the output generator object
|
||||
* In: input: pointer to a 33-byte serialized generator
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_generator* commit,
|
||||
const unsigned char *input
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize a 33-byte generator into a serialized byte sequence.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: output: a pointer to a 33-byte byte array
|
||||
* In: commit: a pointer to a generator
|
||||
*/
|
||||
SECP256K1_API int secp256k1_generator_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output,
|
||||
const secp256k1_generator* commit
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Generate a generator for the curve.
|
||||
*
|
||||
* Returns: 0 in the highly unlikely case the seed is not acceptable,
|
||||
* 1 otherwise.
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: gen: a generator object
|
||||
* In: seed32: a 32-byte seed
|
||||
*
|
||||
* If succesful, a valid generator will be placed in gen. The produced
|
||||
* generators are distributed uniformly over the curve, and will not have a
|
||||
* known dicrete logarithm with respect to any other generator produced,
|
||||
* or to the base generator G.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_generator* gen,
|
||||
const unsigned char *seed32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Generate a blinded generator for the curve.
|
||||
*
|
||||
* Returns: 0 in the highly unlikely case the seed is not acceptable or when
|
||||
* blind is out of range. 1 otherwise.
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: gen: a generator object
|
||||
* In: seed32: a 32-byte seed
|
||||
* blind32: a 32-byte secret value to blind the generator with.
|
||||
*
|
||||
* The result is equivalent to first calling secp256k1_generator_generate,
|
||||
* converting the result to a public key, calling secp256k1_ec_pubkey_tweak_add,
|
||||
* and then converting back to generator form.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate_blinded(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_generator* gen,
|
||||
const unsigned char *key32,
|
||||
const unsigned char *blind32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
# define _SECP256K1_RANGEPROOF_
|
||||
|
||||
# include "secp256k1.h"
|
||||
# include "secp256k1_generator.h"
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -9,6 +10,53 @@ extern "C" {
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Opaque data structure that stores a Pedersen commitment
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 33 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage or transmission, use
|
||||
* secp256k1_pedersen_commitment_serialize and secp256k1_pedersen_commitment_parse.
|
||||
*
|
||||
* Furthermore, it is guaranteed to identical signatures will have identical
|
||||
* representation, so they can be memcmp'ed.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[33];
|
||||
} secp256k1_pedersen_commitment;
|
||||
|
||||
/**
|
||||
* Static constant generator 'h' maintained for historical reasons.
|
||||
*/
|
||||
extern const secp256k1_generator *secp256k1_generator_h;
|
||||
|
||||
/** Parse a 33-byte commitment into a commitment object.
|
||||
*
|
||||
* Returns: 1 if input contains a valid commitment.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: commit: pointer to the output commitment object
|
||||
* In: input: pointer to a 33-byte serialized commitment key
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commitment_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pedersen_commitment* commit,
|
||||
const unsigned char *input
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize a commitment object into a serialized byte sequence.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: output: a pointer to a 33-byte byte array
|
||||
* In: commit: a pointer to a secp256k1_pedersen_commitment containing an
|
||||
* initialized commitment
|
||||
*/
|
||||
SECP256K1_API int secp256k1_pedersen_commitment_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output,
|
||||
const secp256k1_pedersen_commitment* commit
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Initialize a context for usage with Pedersen commitments. */
|
||||
void secp256k1_pedersen_context_initialize(secp256k1_context* ctx);
|
||||
|
||||
|
|
@ -18,16 +66,18 @@ void secp256k1_pedersen_context_initialize(secp256k1_context* ctx);
|
|||
* 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)
|
||||
* gen: additional generator 'h'
|
||||
* Out: commit: pointer to 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(
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *commit,
|
||||
unsigned char *blind,
|
||||
uint64_t value
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
secp256k1_pedersen_commitment *commit,
|
||||
const unsigned char *blind,
|
||||
uint64_t value,
|
||||
const secp256k1_generator *gen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Computes the sum of multiple positive and negative blinding factors.
|
||||
* Returns 1: sum successfully computed.
|
||||
|
|
@ -35,43 +85,77 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
|
|||
* 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.
|
||||
* npositive: 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(
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *blind_out,
|
||||
const unsigned char * const *blinds,
|
||||
int n,
|
||||
int npositive
|
||||
size_t n,
|
||||
size_t 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)
|
||||
* In: ctx: pointer to a context object (cannot be NULL)
|
||||
* commits: pointer to array of pointers to 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)
|
||||
* ncommits: pointer to array of pointers to the 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.
|
||||
* This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) == 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.
|
||||
* A pedersen commitment is xG + vA where G and A 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, for each distinct generator
|
||||
* A all blinding factors and all values must sum to zero.
|
||||
*
|
||||
*/
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
|
||||
const secp256k1_context* ctx,
|
||||
const unsigned char * const *commits,
|
||||
int pcnt,
|
||||
const unsigned char * const *ncommits,
|
||||
int ncnt,
|
||||
int64_t excess
|
||||
const secp256k1_pedersen_commitment * const* commits,
|
||||
size_t pcnt,
|
||||
const secp256k1_pedersen_commitment * const* ncommits,
|
||||
size_t ncnt
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Sets the final Pedersen blinding factor correctly when the generators themselves
|
||||
* have blinding factors.
|
||||
*
|
||||
* Consider a generator of the form A' = A + rG, where A is the "real" generator
|
||||
* but A' is the generator provided to verifiers. Then a Pedersen commitment
|
||||
* P = vA' + r'G really has the form vA + (vr + r')G. To get all these (vr + r')
|
||||
* to sum to zero for multiple commitments, we take three arrays consisting of
|
||||
* the `v`s, `r`s, and `r'`s, respectively called `value`s, `generator_blind`s
|
||||
* and `blinding_factor`s, and sum them.
|
||||
*
|
||||
* The function then subtracts the sum of all (vr + r') from the last element
|
||||
* of the `blinding_factor` array, setting the total sum to zero.
|
||||
*
|
||||
* Returns 1 always.
|
||||
*
|
||||
* In: ctx: pointer to a context object
|
||||
* value: array of asset values, `v` in the above paragraph.
|
||||
* May not be NULL unless `n_total` is 0.
|
||||
* generator_blind: array of asset blinding factors, `r` in the above paragraph
|
||||
* May not be NULL unless `n_total` is 0.
|
||||
* n_total: Total size of the above arrays
|
||||
* n_inputs: How many of the initial array elements represent commitments that
|
||||
* will be negated in the final sum
|
||||
* In/Out: blinding_factor: array of commitment blinding factors, `r'` in the above paragraph
|
||||
* May not be NULL unless `n_total` is 0.
|
||||
* the last value will be modified to get the total sum to zero.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_generator_blind_sum(
|
||||
const secp256k1_context* ctx,
|
||||
const uint64_t *value,
|
||||
const unsigned char* const* generator_blind,
|
||||
unsigned char* const* blinding_factor,
|
||||
size_t n_total,
|
||||
size_t n_inputs
|
||||
);
|
||||
|
||||
/** Initialize a context for usage with Pedersen commitments. */
|
||||
void secp256k1_rangeproof_context_initialize(secp256k1_context* ctx);
|
||||
|
||||
|
|
@ -79,29 +163,38 @@ void secp256k1_rangeproof_context_initialize(secp256k1_context* ctx);
|
|||
* 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)
|
||||
* commit: the commitment being proved. (cannot be NULL)
|
||||
* proof: pointer to character array with the proof. (cannot be NULL)
|
||||
* plen: length of proof in bytes.
|
||||
* extra_commit: additional data covered in rangeproof signature
|
||||
* extra_commit_len: length of extra_commit byte array (0 if NULL)
|
||||
* gen: additional generator 'h'
|
||||
* 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(
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify(
|
||||
const secp256k1_context* ctx,
|
||||
uint64_t *min_value,
|
||||
uint64_t *max_value,
|
||||
const unsigned char *commit,
|
||||
const secp256k1_pedersen_commitment *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);
|
||||
size_t plen,
|
||||
const unsigned char *extra_commit,
|
||||
size_t extra_commit_len,
|
||||
const secp256k1_generator* gen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(9);
|
||||
|
||||
/** 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)
|
||||
* commit: the 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)
|
||||
* extra_commit: additional data covered in rangeproof signature
|
||||
* extra_commit_len: length of extra_commit byte array (0 if NULL)
|
||||
* gen: additional generator 'h'
|
||||
* 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.
|
||||
|
|
@ -109,19 +202,22 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify(
|
|||
* 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(
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *blind_out,
|
||||
uint64_t *value_out,
|
||||
unsigned char *message_out,
|
||||
int *outlen,
|
||||
size_t *outlen,
|
||||
const unsigned char *nonce,
|
||||
uint64_t *min_value,
|
||||
uint64_t *max_value,
|
||||
const unsigned char *commit,
|
||||
const secp256k1_pedersen_commitment *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);
|
||||
size_t plen,
|
||||
const unsigned char *extra_commit,
|
||||
size_t extra_commit_len,
|
||||
const secp256k1_generator *gen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(9) SECP256K1_ARG_NONNULL(10) SECP256K1_ARG_NONNULL(14);
|
||||
|
||||
/** Author a proof that a committed value is within a range.
|
||||
* Returns 1: Proof successfully created.
|
||||
|
|
@ -129,13 +225,18 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind(
|
|||
* 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.
|
||||
* commit: 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.
|
||||
* message: pointer to a byte array of data to be embedded in the rangeproof that can be recovered by rewinding the proof
|
||||
* msg_len: size of the message to be embedded in the rangeproof
|
||||
* extra_commit: additional data to be covered in rangeproof signature
|
||||
* extra_commit_len: length of extra_commit byte array (0 if NULL)
|
||||
* gen: additional generator 'h'
|
||||
* 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.
|
||||
|
|
@ -145,18 +246,23 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind(
|
|||
* 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(
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *proof,
|
||||
int *plen,
|
||||
size_t *plen,
|
||||
uint64_t min_value,
|
||||
const unsigned char *commit,
|
||||
const secp256k1_pedersen_commitment *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);
|
||||
uint64_t value,
|
||||
const unsigned char *message,
|
||||
size_t msg_len,
|
||||
const unsigned char *extra_commit,
|
||||
size_t extra_commit_len,
|
||||
const secp256k1_generator *gen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(15);
|
||||
|
||||
/** Extract some basic information from a range-proof.
|
||||
* Returns 1: Information successfully extracted.
|
||||
|
|
@ -169,14 +275,14 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign(
|
|||
* 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(
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_info(
|
||||
const secp256k1_context* ctx,
|
||||
int *exp,
|
||||
int *mantissa,
|
||||
uint64_t *min_value,
|
||||
uint64_t *max_value,
|
||||
const unsigned char *proof,
|
||||
int plen
|
||||
size_t plen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
# ifdef __cplusplus
|
||||
|
|
|
|||
212
src/secp256k1/include/secp256k1_surjectionproof.h
Normal file
212
src/secp256k1/include/secp256k1_surjectionproof.h
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
#ifndef _SECP256K1_SURJECTIONPROOF_
|
||||
#define _SECP256K1_SURJECTIONPROOF_
|
||||
|
||||
#include "secp256k1.h"
|
||||
#include "secp256k1_rangeproof.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Maximum number of inputs that may be given in a surjection proof */
|
||||
#define SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS 256
|
||||
|
||||
/** Number of bytes a serialized surjection proof requires given the
|
||||
* number of inputs and the number of used inputs.
|
||||
*/
|
||||
#define SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(n_inputs, n_used_inputs) \
|
||||
(2 + (n_inputs + 7)/8 + 32 * (1 + (n_used_inputs)))
|
||||
|
||||
/** Maximum number of bytes a serialized surjection proof requires. */
|
||||
#define SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX \
|
||||
SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS)
|
||||
|
||||
/** Opaque data structure that holds a parsed surjection proof
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. Nor is
|
||||
* it guaranteed to have any particular size, nor that identical proofs
|
||||
* will have identical representation. (That is, memcmp may return nonzero
|
||||
* even for identical proofs.)
|
||||
*
|
||||
* To obtain these properties, instead use secp256k1_surjectionproof_parse
|
||||
* and secp256k1_surjectionproof_serialize to encode/decode proofs into a
|
||||
* well-defined format.
|
||||
*
|
||||
* The representation is exposed to allow creation of these objects on the
|
||||
* stack; please *do not* use these internals directly.
|
||||
*/
|
||||
typedef struct {
|
||||
#ifdef VERIFY
|
||||
/** Mark whether this proof has gone through `secp256k1_surjectionproof_initialize` */
|
||||
int initialized;
|
||||
#endif
|
||||
/** Total number of input asset tags */
|
||||
size_t n_inputs;
|
||||
/** Bitmap of which input tags are used in the surjection proof */
|
||||
unsigned char used_inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS / 8];
|
||||
/** Borromean signature: e0, scalars */
|
||||
unsigned char data[32 * (1 + SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS)];
|
||||
} secp256k1_surjectionproof;
|
||||
|
||||
/** Parse a surjection proof
|
||||
*
|
||||
* Returns: 1 when the proof could be parsed, 0 otherwise.
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: proof: a pointer to a proof object
|
||||
* In: input: a pointer to the array to parse
|
||||
* inputlen: length of the array pointed to by input
|
||||
*
|
||||
* The proof must consist of:
|
||||
* - A 2-byte little-endian total input count `n`
|
||||
* - A ceil(n/8)-byte bitmap indicating which inputs are used.
|
||||
* - A big-endian 32-byte borromean signature e0 value
|
||||
* - `m` big-endian 32-byte borromean signature s values, where `m`
|
||||
* is the number of set bits in the bitmap
|
||||
*/
|
||||
SECP256K1_API int secp256k1_surjectionproof_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_surjectionproof *proof,
|
||||
const unsigned char *input,
|
||||
size_t inputlen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize a surjection proof
|
||||
*
|
||||
* Returns: 1 if enough space was available to serialize, 0 otherwise
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: output: a pointer to an array to store the serialization
|
||||
* In/Out: outputlen: a pointer to an integer which is initially set to the
|
||||
* size of output, and is overwritten with the written
|
||||
* size.
|
||||
* In: proof: a pointer to an initialized proof object
|
||||
*
|
||||
* See secp256k1_surjectionproof_parse for details about the encoding.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_surjectionproof_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output,
|
||||
size_t *outputlen,
|
||||
const secp256k1_surjectionproof *proof
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Data structure that holds a fixed asset tag.
|
||||
*
|
||||
* This data type is *not* opaque. It will always be 32 bytes of whatever
|
||||
* data the API user wants to use as an asset tag. Its contents have no
|
||||
* semantic meaning to libsecp whatsoever.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[32];
|
||||
} secp256k1_fixed_asset_tag;
|
||||
|
||||
/** Returns the total number of inputs a proof expects to be over.
|
||||
*
|
||||
* Returns: the number of inputs for the given proof
|
||||
* In: ctx: pointer to a context object
|
||||
* proof: a pointer to a proof object
|
||||
*/
|
||||
SECP256K1_API size_t secp256k1_surjectionproof_n_total_inputs(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_surjectionproof* proof
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Returns the actual number of inputs that a proof uses
|
||||
*
|
||||
* Returns: the number of inputs for the given proof
|
||||
* In: ctx: pointer to a context object
|
||||
* proof: a pointer to a proof object
|
||||
*/
|
||||
SECP256K1_API size_t secp256k1_surjectionproof_n_used_inputs(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_surjectionproof* proof
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Returns the total size this proof would take, in bytes, when serialized
|
||||
*
|
||||
* Returns: the total size
|
||||
* In: ctx: pointer to a context object
|
||||
* proof: a pointer to a proof object
|
||||
*/
|
||||
SECP256K1_API size_t secp256k1_surjectionproof_serialized_size(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_surjectionproof* proof
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Surjection proof initialization function; decides on inputs to use
|
||||
* Returns 0: inputs could not be selected
|
||||
* n: inputs were selected after n iterations of random selection
|
||||
*
|
||||
* In: ctx: pointer to a context object
|
||||
* fixed_input_tags: fixed input tags `A_i` for all inputs. (If the fixed tag is not known,
|
||||
* e.g. in a coinjoin with others' inputs, an ephemeral tag can be given;
|
||||
* this won't match the output tag but might be used in the anonymity set.)
|
||||
* n_input_tags: the number of entries in the fixed_input_tags array
|
||||
* n_input_tags_to_use: the number of inputs to select randomly to put in the anonymity set
|
||||
* fixed_output_tag: fixed output tag
|
||||
* max_n_iterations: the maximum number of iterations to do before giving up
|
||||
* random_seed32: a random seed to be used for input selection
|
||||
* Out: proof: The proof whose bitvector will be initialized. In case of failure,
|
||||
* the state of the proof is undefined.
|
||||
* input_index: The index of the actual input that is secretly mapped to the output
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_initialize(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_surjectionproof* proof,
|
||||
size_t *input_index,
|
||||
const secp256k1_fixed_asset_tag* fixed_input_tags,
|
||||
const size_t n_input_tags,
|
||||
const size_t n_input_tags_to_use,
|
||||
const secp256k1_fixed_asset_tag* fixed_output_tag,
|
||||
const size_t n_max_iterations,
|
||||
const unsigned char *random_seed32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(7);
|
||||
|
||||
/** Surjection proof generation function
|
||||
* Returns 0: proof could not be created
|
||||
* 1: proof was successfully created
|
||||
*
|
||||
* In: ctx: pointer to a context object, initialized for signing and verification
|
||||
* ephemeral_input_tags: the ephemeral asset tag of all inputs
|
||||
* n_ephemeral_input_tags: the number of entries in the ephemeral_input_tags array
|
||||
* ephemeral_output_tag: the ephemeral asset tag of the output
|
||||
* input_index: the index of the input that actually maps to the output
|
||||
* input_blinding_key: the blinding key of the input
|
||||
* output_blinding_key: the blinding key of the output
|
||||
* In/Out: proof: The produced surjection proof. Must have already gone through `secp256k1_surjectionproof_initialize`
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_generate(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_surjectionproof* proof,
|
||||
const secp256k1_generator* ephemeral_input_tags,
|
||||
size_t n_ephemeral_input_tags,
|
||||
const secp256k1_generator* ephemeral_output_tag,
|
||||
size_t input_index,
|
||||
const unsigned char *input_blinding_key,
|
||||
const unsigned char *output_blinding_key
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8);
|
||||
|
||||
|
||||
/** Surjection proof verification function
|
||||
* Returns 0: proof was invalid
|
||||
* 1: proof was valid
|
||||
*
|
||||
* In: ctx: pointer to a context object, initialized for signing and verification
|
||||
* proof: proof to be verified
|
||||
* ephemeral_input_tags: the ephemeral asset tag of all inputs
|
||||
* n_ephemeral_input_tags: the number of entries in the ephemeral_input_tags array
|
||||
* ephemeral_output_tag: the ephemeral asset tag of the output
|
||||
*/
|
||||
SECP256K1_API int secp256k1_surjectionproof_verify(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_surjectionproof* proof,
|
||||
const secp256k1_generator* ephemeral_input_tags,
|
||||
size_t n_ephemeral_input_tags,
|
||||
const secp256k1_generator* ephemeral_output_tag
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
146
src/secp256k1/include/secp256k1_whitelist.h
Normal file
146
src/secp256k1/include/secp256k1_whitelist.h
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2016 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_WHITELIST_
|
||||
#define _SECP256K1_WHITELIST_
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SECP256K1_WHITELIST_MAX_N_KEYS 256
|
||||
|
||||
/** Opaque data structure that holds a parsed whitelist proof
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. Nor is
|
||||
* it guaranteed to have any particular size, nor that identical signatures
|
||||
* will have identical representation. (That is, memcmp may return nonzero
|
||||
* even for identical signatures.)
|
||||
*
|
||||
* To obtain these properties, instead use secp256k1_whitelist_signature_parse
|
||||
* and secp256k1_whitelist_signature_serialize to encode/decode signatures
|
||||
* into a well-defined format.
|
||||
*
|
||||
* The representation is exposed to allow creation of these objects on the
|
||||
* stack; please *do not* use these internals directly. To learn the number
|
||||
* of keys for a signature, use `secp256k1_whitelist_signature_n_keys`.
|
||||
*/
|
||||
typedef struct {
|
||||
size_t n_keys;
|
||||
/* e0, scalars */
|
||||
unsigned char data[32 * (1 + SECP256K1_WHITELIST_MAX_N_KEYS)];
|
||||
} secp256k1_whitelist_signature;
|
||||
|
||||
/** Parse a whitelist signature
|
||||
*
|
||||
* Returns: 1 when the signature could be parsed, 0 otherwise.
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: sig: a pointer to a signature object
|
||||
* In: input: a pointer to the array to parse
|
||||
*
|
||||
* The signature must consist of a 1-byte n_keys value, followed by a 32-byte
|
||||
* big endian e0 value, followed by n_keys many 32-byte big endian s values.
|
||||
* If n_keys falls outside of [0..SECP256K1_WHITELIST_MAX_N_KEYS] the encoding
|
||||
* is invalid.
|
||||
*
|
||||
* The total length of the input array must therefore be 33 + 32 * n_keys.
|
||||
*
|
||||
* After the call, sig will always be initialized. If parsing failed or any
|
||||
* scalar values overflow or are zero, the resulting sig value is guaranteed
|
||||
* to fail validation for any set of keys.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_whitelist_signature_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_whitelist_signature *sig,
|
||||
const unsigned char *input
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Returns the number of keys a signature expects to have.
|
||||
*
|
||||
* Returns: the number of keys for the given signature
|
||||
* In: sig: a pointer to a signature object
|
||||
*/
|
||||
SECP256K1_API size_t secp256k1_whitelist_signature_n_keys(
|
||||
const secp256k1_whitelist_signature *sig
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Serialize a whitelist signature
|
||||
*
|
||||
* Returns: 1
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: output64: a pointer to an array to store the serialization
|
||||
* In: sig: a pointer to an initialized signature object
|
||||
*
|
||||
* See secp256k1_whitelist_signature_parse for details about the encoding.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_whitelist_signature_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output,
|
||||
const secp256k1_whitelist_signature *sig
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Compute a whitelist signature
|
||||
* Returns 1: signature was successfully created
|
||||
* 0: signature was not successfully created
|
||||
* In: ctx: pointer to a context object, initialized for signing and verification
|
||||
* online_pubkeys: list of all online pubkeys
|
||||
* offline_pubkeys: list of all offline pubkeys
|
||||
* n_keys: the number of entries in each of the above two arrays
|
||||
* sub_pubkey: the key to be whitelisted
|
||||
* online_seckey: the secret key to the signer's online pubkey
|
||||
* summed_seckey: the secret key to the sum of (whitelisted key, signer's offline pubkey)
|
||||
* index: the signer's index in the lists of keys
|
||||
* 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: The produced signature.
|
||||
*
|
||||
* The signatures are of the list of all passed pubkeys in the order
|
||||
* ( whitelist, online_1, offline_1, online_2, offline_2, ... )
|
||||
* The verification key list consists of
|
||||
* online_i + H(offline_i + whitelist)(offline_i + whitelist)
|
||||
* for each public key pair (offline_i, offline_i). Here H means sha256 of the
|
||||
* compressed serialization of the key.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_whitelist_sign(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_whitelist_signature *sig,
|
||||
const secp256k1_pubkey *online_pubkeys,
|
||||
const secp256k1_pubkey *offline_pubkeys,
|
||||
const size_t n_keys,
|
||||
const secp256k1_pubkey *sub_pubkey,
|
||||
const unsigned char *online_seckey,
|
||||
const unsigned char *summed_seckey,
|
||||
const size_t index,
|
||||
secp256k1_nonce_function noncefp,
|
||||
const void *noncedata
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8);
|
||||
|
||||
/** Verify a whitelist signature
|
||||
* Returns 1: signature is valid
|
||||
* 0: signature is not valid
|
||||
* In: ctx: pointer to a context object, initialized for signing and verification
|
||||
* sig: the signature to be verified
|
||||
* online_pubkeys: list of all online pubkeys
|
||||
* offline_pubkeys: list of all offline pubkeys
|
||||
* n_keys: the number of entries in each of the above two arrays
|
||||
* sub_pubkey: the key to be whitelisted
|
||||
*/
|
||||
SECP256K1_API int secp256k1_whitelist_verify(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_whitelist_signature *sig,
|
||||
const secp256k1_pubkey *online_pubkeys,
|
||||
const secp256k1_pubkey *offline_pubkeys,
|
||||
const secp256k1_pubkey *sub_pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
51
src/secp256k1/sage/shallue_van_de_woestijne.sage
Normal file
51
src/secp256k1/sage/shallue_van_de_woestijne.sage
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
### http://www.di.ens.fr/~fouque/pub/latincrypt12.pdf
|
||||
|
||||
# Parameters for secp256k1
|
||||
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
|
||||
a = 0
|
||||
b = 7
|
||||
F = FiniteField (p)
|
||||
C = EllipticCurve ([F(a), F(b)])
|
||||
|
||||
def svdw(t):
|
||||
sqrt_neg_3 = F(-3).nth_root(2)
|
||||
|
||||
## Compute candidate x values
|
||||
w = sqrt_neg_3 * t / (1 + b + t^2)
|
||||
x = [ F(0), F(0), F(0) ]
|
||||
x[0] = (-1 + sqrt_neg_3) / 2 - t * w
|
||||
x[1] = -1 - x[0]
|
||||
x[2] = 1 + 1 / w^2
|
||||
|
||||
print
|
||||
print "On %2d" % t
|
||||
print " x1 %064x" % x[0]
|
||||
print " x2 %064x" % x[1]
|
||||
print " x3 %064x" % x[2]
|
||||
|
||||
## Select which to use
|
||||
alph = jacobi_symbol(x[0]^3 + b, p)
|
||||
beta = jacobi_symbol(x[1]^3 + b, p)
|
||||
if alph == 1 and beta == 1:
|
||||
i = 0
|
||||
elif alph == 1 and beta == -1:
|
||||
i = 0
|
||||
elif alph == -1 and beta == 1:
|
||||
i = 1
|
||||
elif alph == -1 and beta == -1:
|
||||
i = 2
|
||||
else:
|
||||
print "Help! I don't understand Python!"
|
||||
|
||||
## Expand to full point
|
||||
sign = 1 - 2 * (int(F(t)) % 2)
|
||||
ret_x = x[i]
|
||||
ret_y = sign * F(x[i]^3 + b).nth_root(2)
|
||||
return C.point((ret_x, ret_y))
|
||||
|
||||
|
||||
## main
|
||||
for i in range(1, 11):
|
||||
res = svdw(i)
|
||||
print "Result: %064x %064x" % res.xy()
|
||||
59
src/secp256k1/src/bench_generator.c
Normal file
59
src/secp256k1/src/bench_generator.c
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2016 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "include/secp256k1_generator.h"
|
||||
#include "util.h"
|
||||
#include "bench.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context* ctx;
|
||||
unsigned char key[32];
|
||||
unsigned char blind[32];
|
||||
} bench_generator_t;
|
||||
|
||||
static void bench_generator_setup(void* arg) {
|
||||
bench_generator_t *data = (bench_generator_t*)arg;
|
||||
memset(data->key, 0x31, 32);
|
||||
memset(data->blind, 0x13, 32);
|
||||
}
|
||||
|
||||
static void bench_generator_generate(void* arg) {
|
||||
int i;
|
||||
bench_generator_t *data = (bench_generator_t*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
secp256k1_generator gen;
|
||||
CHECK(secp256k1_generator_generate(data->ctx, &gen, data->key));
|
||||
data->key[i & 31]++;
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_generator_generate_blinded(void* arg) {
|
||||
int i;
|
||||
bench_generator_t *data = (bench_generator_t*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
secp256k1_generator gen;
|
||||
CHECK(secp256k1_generator_generate_blinded(data->ctx, &gen, data->key, data->blind));
|
||||
data->key[1 + (i & 30)]++;
|
||||
data->blind[1 + (i & 30)]++;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
bench_generator_t data;
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
|
||||
run_benchmark("generator_generate", bench_generator_generate, bench_generator_setup, NULL, &data, 10, 20000);
|
||||
run_benchmark("generator_generate_blinded", bench_generator_generate_blinded, bench_generator_setup, NULL, &data, 10, 20000);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -251,7 +251,7 @@ void bench_wnaf_const(void* arg) {
|
|||
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_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A, 256, 1);
|
||||
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@
|
|||
|
||||
typedef struct {
|
||||
secp256k1_context* ctx;
|
||||
unsigned char commit[33];
|
||||
secp256k1_pedersen_commitment commit;
|
||||
unsigned char proof[5134];
|
||||
unsigned char blind[32];
|
||||
int len;
|
||||
size_t len;
|
||||
int min_bits;
|
||||
uint64_t v;
|
||||
} bench_rangeproof_t;
|
||||
|
|
@ -28,10 +28,10 @@ static void bench_rangeproof_setup(void* arg) {
|
|||
|
||||
data->v = 0;
|
||||
for (i = 0; i < 32; i++) data->blind[i] = i + 1;
|
||||
CHECK(secp256k1_pedersen_commit(data->ctx, data->commit, data->blind, data->v));
|
||||
CHECK(secp256k1_pedersen_commit(data->ctx, &data->commit, data->blind, data->v, secp256k1_generator_h));
|
||||
data->len = 5134;
|
||||
CHECK(secp256k1_rangeproof_sign(data->ctx, data->proof, &data->len, 0, data->commit, data->blind, data->commit, 0, data->min_bits, data->v));
|
||||
CHECK(secp256k1_rangeproof_verify(data->ctx, &minv, &maxv, data->commit, data->proof, data->len));
|
||||
CHECK(secp256k1_rangeproof_sign(data->ctx, data->proof, &data->len, 0, &data->commit, data->blind, (const unsigned char*)&data->commit, 0, data->min_bits, data->v, NULL, 0, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(secp256k1_rangeproof_verify(data->ctx, &minv, &maxv, &data->commit, data->proof, data->len, NULL, 0, secp256k1_generator_h));
|
||||
}
|
||||
|
||||
static void bench_rangeproof(void* arg) {
|
||||
|
|
@ -42,7 +42,7 @@ static void bench_rangeproof(void* arg) {
|
|||
int j;
|
||||
uint64_t minv;
|
||||
uint64_t maxv;
|
||||
j = secp256k1_rangeproof_verify(data->ctx, &minv, &maxv, data->commit, data->proof, data->len);
|
||||
j = secp256k1_rangeproof_verify(data->ctx, &minv, &maxv, &data->commit, data->proof, data->len, NULL, 0, secp256k1_generator_h);
|
||||
for (j = 0; j < 4; j++) {
|
||||
data->proof[j + 2 + 32 *((data->min_bits + 1) >> 1) - 4] = (i >> 8)&255;
|
||||
}
|
||||
|
|
@ -53,8 +53,6 @@ int main(void) {
|
|||
bench_rangeproof_t data;
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -225,14 +225,12 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const
|
|||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
{
|
||||
secp256k1_scalar computed_r;
|
||||
int overflow = 0;
|
||||
secp256k1_ge pr_ge;
|
||||
secp256k1_ge_set_gej(&pr_ge, &pr);
|
||||
secp256k1_fe_normalize(&pr_ge.x);
|
||||
|
||||
secp256k1_fe_get_b32(c, &pr_ge.x);
|
||||
secp256k1_scalar_set_b32(&computed_r, c, &overflow);
|
||||
/* we fully expect overflow */
|
||||
secp256k1_scalar_set_b32(&computed_r, c, NULL);
|
||||
return secp256k1_scalar_eq(sigr, &computed_r);
|
||||
}
|
||||
#else
|
||||
|
|
@ -285,14 +283,10 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec
|
|||
secp256k1_fe_normalize(&r.y);
|
||||
secp256k1_fe_get_b32(b, &r.x);
|
||||
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.
|
||||
* This branch is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N.
|
||||
*/
|
||||
secp256k1_gej_clear(&rp);
|
||||
secp256k1_ge_clear(&r);
|
||||
return 0;
|
||||
}
|
||||
/* These two conditions should be checked before calling */
|
||||
VERIFY_CHECK(!secp256k1_scalar_is_zero(sigr));
|
||||
VERIFY_CHECK(overflow == 0);
|
||||
|
||||
if (recid) {
|
||||
/* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log
|
||||
* of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria.
|
||||
|
|
|
|||
|
|
@ -10,6 +10,6 @@
|
|||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
|
||||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);
|
||||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q, int bits);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -12,12 +12,7 @@
|
|||
#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))
|
||||
#define WNAF_SIZE(bits, w) (((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 { \
|
||||
|
|
@ -54,7 +49,7 @@
|
|||
*
|
||||
* 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 s, int w) {
|
||||
static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size, int maybe_negative) {
|
||||
int global_sign;
|
||||
int skew = 0;
|
||||
int word = 0;
|
||||
|
|
@ -75,26 +70,34 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
|
|||
* or 2 (for odd) to the number we are encoding, returning a skew value indicating
|
||||
* this, and having the caller compensate after doing the multiplication. */
|
||||
|
||||
/* Negative numbers will be negated to keep their bit representation below the maximum width */
|
||||
flip = secp256k1_scalar_is_high(&s);
|
||||
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
|
||||
bit = flip ^ !secp256k1_scalar_is_even(&s);
|
||||
/* We check for negative one, since adding 2 to it will cause an overflow */
|
||||
secp256k1_scalar_negate(&neg_s, &s);
|
||||
not_neg_one = !secp256k1_scalar_is_one(&neg_s);
|
||||
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;
|
||||
if (maybe_negative) {
|
||||
/* Negative numbers will be negated to keep their bit representation below the maximum width */
|
||||
flip = maybe_negative ? secp256k1_scalar_is_high(&s) : 0;
|
||||
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
|
||||
bit = flip ^ !secp256k1_scalar_is_even(&s);
|
||||
/* We check for negative one, since adding 2 to it will cause an overflow */
|
||||
secp256k1_scalar_negate(&neg_s, &s);
|
||||
not_neg_one = !secp256k1_scalar_is_one(&neg_s);
|
||||
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 {
|
||||
VERIFY_CHECK(!secp256k1_scalar_is_high(&s));
|
||||
bit = !secp256k1_scalar_is_even(&s);
|
||||
skew = 1 << bit;
|
||||
secp256k1_scalar_cadd_bit(&s, bit, 1);
|
||||
global_sign = 1;
|
||||
}
|
||||
|
||||
/* 4 */
|
||||
u_last = secp256k1_scalar_shr_int(&s, w);
|
||||
while (word * w < WNAF_BITS) {
|
||||
do {
|
||||
int sign;
|
||||
int even;
|
||||
|
||||
|
|
@ -110,41 +113,50 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
|
|||
wnaf[word++] = u_last * global_sign;
|
||||
|
||||
u_last = u;
|
||||
}
|
||||
} while(word * w < size);
|
||||
wnaf[word] = u * global_sign;
|
||||
|
||||
VERIFY_CHECK(secp256k1_scalar_is_zero(&s));
|
||||
VERIFY_CHECK(word == WNAF_SIZE(w));
|
||||
VERIFY_CHECK(word == WNAF_SIZE(size, w));
|
||||
return skew;
|
||||
}
|
||||
|
||||
|
||||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) {
|
||||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar, int size) {
|
||||
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
secp256k1_ge tmpa;
|
||||
secp256k1_fe Z;
|
||||
|
||||
int skew_1;
|
||||
int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||
int wnaf_1[1 + WNAF_SIZE(128, WINDOW_A - 1)];
|
||||
int wnaf_lam[1 + WNAF_SIZE(128, WINDOW_A - 1)];
|
||||
int skew_lam;
|
||||
secp256k1_scalar q_1, q_lam;
|
||||
#else
|
||||
int wnaf_1[1 + WNAF_SIZE(256, WINDOW_A - 1)];
|
||||
#endif
|
||||
|
||||
int i;
|
||||
secp256k1_scalar sc = *scalar;
|
||||
|
||||
/* build wnaf representation for q. */
|
||||
int rsize = size;
|
||||
#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);
|
||||
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
|
||||
skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1);
|
||||
if (size > 128) {
|
||||
rsize = 128;
|
||||
/* 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);
|
||||
skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1, 128, 1);
|
||||
skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1, 128, 1);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1, size, size == 256);
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
skew_lam = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Calculate odd multiples of a.
|
||||
* All multiples are brought to the same Z 'denominator', which is stored
|
||||
|
|
@ -158,26 +170,30 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
|
|||
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]);
|
||||
if (size > 128) {
|
||||
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) */
|
||||
i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)];
|
||||
i = wnaf_1[WNAF_SIZE(rsize, WINDOW_A - 1)];
|
||||
VERIFY_CHECK(i != 0);
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
|
||||
secp256k1_gej_set_ge(r, &tmpa);
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
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);
|
||||
if (size > 128) {
|
||||
i = wnaf_lam[WNAF_SIZE(rsize, 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);
|
||||
}
|
||||
#endif
|
||||
/* remaining loop iterations */
|
||||
for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) {
|
||||
for (i = WNAF_SIZE(rsize, WINDOW_A - 1) - 1; i >= 0; i--) {
|
||||
int n;
|
||||
int j;
|
||||
for (j = 0; j < WINDOW_A - 1; ++j) {
|
||||
|
|
@ -189,10 +205,12 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
|
|||
VERIFY_CHECK(n != 0);
|
||||
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
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);
|
||||
if (size > 128) {
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -212,14 +230,18 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
|
|||
secp256k1_ge_set_gej(&correction, &tmpj);
|
||||
secp256k1_ge_to_storage(&correction_1_stor, a);
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
secp256k1_ge_to_storage(&correction_lam_stor, a);
|
||||
if (size > 128) {
|
||||
secp256k1_ge_to_storage(&correction_lam_stor, a);
|
||||
}
|
||||
#endif
|
||||
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);
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
|
||||
if (size > 128) {
|
||||
secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Apply the correction */
|
||||
|
|
@ -228,10 +250,12 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
|
|||
secp256k1_gej_add_ge(r, r, &correction);
|
||||
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
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);
|
||||
if (size > 128) {
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,10 +38,6 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) {
|
|||
}
|
||||
VERIFY_CHECK(r == 1);
|
||||
}
|
||||
#else
|
||||
static void secp256k1_fe_verify(const secp256k1_fe *a) {
|
||||
(void)a;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void secp256k1_fe_normalize(secp256k1_fe *r) {
|
||||
|
|
|
|||
|
|
@ -49,10 +49,6 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) {
|
|||
}
|
||||
VERIFY_CHECK(r == 1);
|
||||
}
|
||||
#else
|
||||
static void secp256k1_fe_verify(const secp256k1_fe *a) {
|
||||
(void)a;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void secp256k1_fe_normalize(secp256k1_fe *r) {
|
||||
|
|
|
|||
|
|
@ -200,12 +200,6 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
|
|||
secp256k1_fe_clear(&r->z);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
|
||||
r->infinity = 1;
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_clear(secp256k1_gej *r) {
|
||||
r->infinity = 0;
|
||||
secp256k1_fe_clear(&r->x);
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const se
|
|||
secp256k1_gej res;
|
||||
secp256k1_ge pt;
|
||||
secp256k1_scalar s;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
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);
|
||||
|
|
@ -30,7 +30,7 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const se
|
|||
unsigned char y[1];
|
||||
secp256k1_sha256_t sha;
|
||||
|
||||
secp256k1_ecmult_const(&res, &pt, &s);
|
||||
secp256k1_ecmult_const(&res, &pt, &s, 256);
|
||||
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
|
||||
|
|
|
|||
|
|
@ -7,6 +7,35 @@
|
|||
#ifndef _SECP256K1_MODULE_ECDH_TESTS_
|
||||
#define _SECP256K1_MODULE_ECDH_TESTS_
|
||||
|
||||
void test_ecdh_api(void) {
|
||||
/* Setup context that just counts errors */
|
||||
secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||
secp256k1_pubkey point;
|
||||
unsigned char res[32];
|
||||
unsigned char s_one[32] = { 0 };
|
||||
int32_t ecount = 0;
|
||||
s_one[31] = 1;
|
||||
|
||||
secp256k1_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount);
|
||||
CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1);
|
||||
|
||||
/* Check all NULLs are detected */
|
||||
CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
|
||||
CHECK(ecount == 3);
|
||||
|
||||
/* Cleanup */
|
||||
secp256k1_context_destroy(tctx);
|
||||
}
|
||||
|
||||
void test_ecdh_generator_basepoint(void) {
|
||||
unsigned char s_one[32] = { 0 };
|
||||
secp256k1_pubkey point[2];
|
||||
|
|
@ -68,6 +97,7 @@ void test_bad_scalar(void) {
|
|||
}
|
||||
|
||||
void run_ecdh_tests(void) {
|
||||
test_ecdh_api();
|
||||
test_ecdh_generator_basepoint();
|
||||
test_bad_scalar();
|
||||
}
|
||||
|
|
|
|||
8
src/secp256k1/src/modules/generator/Makefile.am.include
Normal file
8
src/secp256k1/src/modules/generator/Makefile.am.include
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
include_HEADERS += include/secp256k1_generator.h
|
||||
noinst_HEADERS += src/modules/generator/main_impl.h
|
||||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_generator
|
||||
bench_generator_SOURCES = src/bench_generator.c
|
||||
bench_generator_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
bench_generator_LDFLAGS = -static
|
||||
endif
|
||||
207
src/secp256k1/src/modules/generator/main_impl.h
Normal file
207
src/secp256k1/src/modules/generator/main_impl.h
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2016 Andrew Poelstra & 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_GENERATOR_MAIN
|
||||
#define SECP256K1_MODULE_GENERATOR_MAIN
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
#include "hash.h"
|
||||
#include "scalar.h"
|
||||
|
||||
static void secp256k1_generator_load(secp256k1_ge* ge, const secp256k1_generator* gen) {
|
||||
secp256k1_fe fe;
|
||||
secp256k1_fe_set_b32(&fe, &gen->data[1]);
|
||||
secp256k1_ge_set_xquad(ge, &fe);
|
||||
if (gen->data[0] & 1) {
|
||||
secp256k1_ge_neg(ge, ge);
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_generator_save(secp256k1_generator* commit, secp256k1_ge* ge) {
|
||||
secp256k1_fe_normalize(&ge->x);
|
||||
secp256k1_fe_get_b32(&commit->data[1], &ge->x);
|
||||
commit->data[0] = 11 ^ secp256k1_fe_is_quad_var(&ge->y);
|
||||
}
|
||||
|
||||
int secp256k1_generator_parse(const secp256k1_context* ctx, secp256k1_generator* gen, const unsigned char *input) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(gen != NULL);
|
||||
ARG_CHECK(input != NULL);
|
||||
if ((input[0] & 0xFE) != 10) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(gen->data, input, sizeof(gen->data));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_generator_serialize(const secp256k1_context* ctx, unsigned char *output, const secp256k1_generator* gen) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output != NULL);
|
||||
ARG_CHECK(gen != NULL);
|
||||
memcpy(output, gen->data, sizeof(gen->data));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void shallue_van_de_woestijne(secp256k1_ge* ge, const secp256k1_fe* t) {
|
||||
/* Implements the algorithm from:
|
||||
* Indifferentiable Hashing to Barreto-Naehrig Curves
|
||||
* Pierre-Alain Fouque and Mehdi Tibouchi
|
||||
* Latincrypt 2012
|
||||
*/
|
||||
|
||||
/* Basic algorithm:
|
||||
|
||||
c = sqrt(-3)
|
||||
d = (c - 1)/2
|
||||
|
||||
w = c * t / (1 + b + t^2) [with b = 7]
|
||||
x1 = d - t*w
|
||||
x2 = -(x1 + 1)
|
||||
x3 = 1 + 1/w^2
|
||||
|
||||
To avoid the 2 divisions, compute the above in numerator/denominator form:
|
||||
wn = c * t
|
||||
wd = 1 + 7 + t^2
|
||||
x1n = d*wd - t*wn
|
||||
x1d = wd
|
||||
x2n = -(x1n + wd)
|
||||
x2d = wd
|
||||
x3n = wd^2 + c^2 + t^2
|
||||
x3d = (c * t)^2
|
||||
|
||||
The joint denominator j = wd * c^2 * t^2, and
|
||||
1 / x1d = 1/j * c^2 * t^2
|
||||
1 / x2d = x3d = 1/j * wd
|
||||
*/
|
||||
|
||||
static const secp256k1_fe c = SECP256K1_FE_CONST(0x0a2d2ba9, 0x3507f1df, 0x233770c2, 0xa797962c, 0xc61f6d15, 0xda14ecd4, 0x7d8d27ae, 0x1cd5f852);
|
||||
static const secp256k1_fe d = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40);
|
||||
static const secp256k1_fe b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 7);
|
||||
static const secp256k1_fe b_plus_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 8);
|
||||
|
||||
secp256k1_fe wn, wd, x1n, x2n, x3n, x3d, jinv, tmp, x1, x2, x3, alphain, betain, gammain, y1, y2, y3;
|
||||
int alphaquad, betaquad;
|
||||
|
||||
secp256k1_fe_mul(&wn, &c, t); /* mag 1 */
|
||||
secp256k1_fe_sqr(&wd, t); /* mag 1 */
|
||||
secp256k1_fe_add(&wd, &b_plus_one); /* mag 2 */
|
||||
secp256k1_fe_mul(&tmp, t, &wn); /* mag 1 */
|
||||
secp256k1_fe_negate(&tmp, &tmp, 1); /* mag 2 */
|
||||
secp256k1_fe_mul(&x1n, &d, &wd); /* mag 1 */
|
||||
secp256k1_fe_add(&x1n, &tmp); /* mag 3 */
|
||||
x2n = x1n; /* mag 3 */
|
||||
secp256k1_fe_add(&x2n, &wd); /* mag 5 */
|
||||
secp256k1_fe_negate(&x2n, &x2n, 5); /* mag 6 */
|
||||
secp256k1_fe_mul(&x3d, &c, t); /* mag 1 */
|
||||
secp256k1_fe_sqr(&x3d, &x3d); /* mag 1 */
|
||||
secp256k1_fe_sqr(&x3n, &wd); /* mag 1 */
|
||||
secp256k1_fe_add(&x3n, &x3d); /* mag 2 */
|
||||
secp256k1_fe_mul(&jinv, &x3d, &wd); /* mag 1 */
|
||||
secp256k1_fe_inv(&jinv, &jinv); /* mag 1 */
|
||||
secp256k1_fe_mul(&x1, &x1n, &x3d); /* mag 1 */
|
||||
secp256k1_fe_mul(&x1, &x1, &jinv); /* mag 1 */
|
||||
secp256k1_fe_mul(&x2, &x2n, &x3d); /* mag 1 */
|
||||
secp256k1_fe_mul(&x2, &x2, &jinv); /* mag 1 */
|
||||
secp256k1_fe_mul(&x3, &x3n, &wd); /* mag 1 */
|
||||
secp256k1_fe_mul(&x3, &x3, &jinv); /* mag 1 */
|
||||
|
||||
secp256k1_fe_sqr(&alphain, &x1); /* mag 1 */
|
||||
secp256k1_fe_mul(&alphain, &alphain, &x1); /* mag 1 */
|
||||
secp256k1_fe_add(&alphain, &b); /* mag 2 */
|
||||
secp256k1_fe_sqr(&betain, &x2); /* mag 1 */
|
||||
secp256k1_fe_mul(&betain, &betain, &x2); /* mag 1 */
|
||||
secp256k1_fe_add(&betain, &b); /* mag 2 */
|
||||
secp256k1_fe_sqr(&gammain, &x3); /* mag 1 */
|
||||
secp256k1_fe_mul(&gammain, &gammain, &x3); /* mag 1 */
|
||||
secp256k1_fe_add(&gammain, &b); /* mag 2 */
|
||||
|
||||
alphaquad = secp256k1_fe_sqrt(&y1, &alphain);
|
||||
betaquad = secp256k1_fe_sqrt(&y2, &betain);
|
||||
secp256k1_fe_sqrt(&y3, &gammain);
|
||||
|
||||
secp256k1_fe_cmov(&x1, &x2, (!alphaquad) & betaquad);
|
||||
secp256k1_fe_cmov(&y1, &y2, (!alphaquad) & betaquad);
|
||||
secp256k1_fe_cmov(&x1, &x3, (!alphaquad) & !betaquad);
|
||||
secp256k1_fe_cmov(&y1, &y3, (!alphaquad) & !betaquad);
|
||||
|
||||
secp256k1_ge_set_xy(ge, &x1, &y1);
|
||||
|
||||
/* The linked algorithm from the paper uses the Jacobi symbol of t to
|
||||
* determine the Jacobi symbol of the produced y coordinate. Since the
|
||||
* rest of the algorithm only uses t^2, we can safely use another criterion
|
||||
* as long as negation of t results in negation of the y coordinate. Here
|
||||
* we choose to use t's oddness, as it is faster to determine. */
|
||||
secp256k1_fe_negate(&tmp, &ge->y, 1);
|
||||
secp256k1_fe_cmov(&ge->y, &tmp, secp256k1_fe_is_odd(t));
|
||||
}
|
||||
|
||||
static int secp256k1_generator_generate_internal(const secp256k1_context* ctx, secp256k1_generator* gen, const unsigned char *key32, const unsigned char *blind32) {
|
||||
static const unsigned char prefix1[16] = "1st generation: ";
|
||||
static const unsigned char prefix2[16] = "2nd generation: ";
|
||||
secp256k1_fe t = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 4);
|
||||
secp256k1_ge add;
|
||||
secp256k1_gej accum;
|
||||
int overflow;
|
||||
secp256k1_sha256_t sha256;
|
||||
unsigned char b32[32];
|
||||
int ret = 1;
|
||||
|
||||
if (blind32) {
|
||||
secp256k1_scalar blind;
|
||||
secp256k1_scalar_set_b32(&blind, blind32, &overflow);
|
||||
ret = !overflow;
|
||||
CHECK(ret);
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &accum, &blind);
|
||||
}
|
||||
|
||||
secp256k1_sha256_initialize(&sha256);
|
||||
secp256k1_sha256_write(&sha256, prefix1, 16);
|
||||
secp256k1_sha256_write(&sha256, key32, 32);
|
||||
secp256k1_sha256_finalize(&sha256, b32);
|
||||
ret &= secp256k1_fe_set_b32(&t, b32);
|
||||
CHECK(ret);
|
||||
shallue_van_de_woestijne(&add, &t);
|
||||
if (blind32) {
|
||||
secp256k1_gej_add_ge(&accum, &accum, &add);
|
||||
} else {
|
||||
secp256k1_gej_set_ge(&accum, &add);
|
||||
}
|
||||
|
||||
secp256k1_sha256_initialize(&sha256);
|
||||
secp256k1_sha256_write(&sha256, prefix2, 16);
|
||||
secp256k1_sha256_write(&sha256, key32, 32);
|
||||
secp256k1_sha256_finalize(&sha256, b32);
|
||||
ret &= secp256k1_fe_set_b32(&t, b32);
|
||||
CHECK(ret);
|
||||
shallue_van_de_woestijne(&add, &t);
|
||||
secp256k1_gej_add_ge(&accum, &accum, &add);
|
||||
|
||||
secp256k1_ge_set_gej(&add, &accum);
|
||||
secp256k1_generator_save(gen, &add);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_generator_generate(const secp256k1_context* ctx, secp256k1_generator* gen, const unsigned char *key32) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(gen != NULL);
|
||||
ARG_CHECK(key32 != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
return secp256k1_generator_generate_internal(ctx, gen, key32, NULL);
|
||||
}
|
||||
|
||||
int secp256k1_generator_generate_blinded(const secp256k1_context* ctx, secp256k1_generator* gen, const unsigned char *key32, const unsigned char *blind32) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(gen != NULL);
|
||||
ARG_CHECK(key32 != NULL);
|
||||
ARG_CHECK(blind32 != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
return secp256k1_generator_generate_internal(ctx, gen, key32, blind32);
|
||||
}
|
||||
|
||||
#endif
|
||||
139
src/secp256k1/src/modules/generator/tests_impl.h
Normal file
139
src/secp256k1/src/modules/generator/tests_impl.h
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2016 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_GENERATOR_TESTS
|
||||
#define SECP256K1_MODULE_GENERATOR_TESTS
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
#include "testrand.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "include/secp256k1_generator.h"
|
||||
|
||||
void test_shallue_van_de_woestijne(void) {
|
||||
/* Matches with the output of the shallue_van_de_woestijne.sage SAGE program */
|
||||
static const secp256k1_ge_storage results[32] = {
|
||||
SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0x0225f529, 0xee75acaf, 0xccfc4560, 0x26c5e46b, 0xf80237a3, 0x3924655a, 0x16f90e88, 0x085ed52a),
|
||||
SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0xfdda0ad6, 0x118a5350, 0x3303ba9f, 0xd93a1b94, 0x07fdc85c, 0xc6db9aa5, 0xe906f176, 0xf7a12705),
|
||||
SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0x56716069, 0x6818286b, 0x72f01a3e, 0x5e8caca7, 0x36249160, 0xc7ded69d, 0xd51913c3, 0x03a2fa97),
|
||||
SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0xa98e9f96, 0x97e7d794, 0x8d0fe5c1, 0xa1735358, 0xc9db6e9f, 0x38212962, 0x2ae6ec3b, 0xfc5d0198),
|
||||
SECP256K1_GE_STORAGE_CONST(0x531f7239, 0xaebc780e, 0x179fbf8d, 0x412a1b01, 0x511f0abc, 0xe0c46151, 0x8b38db84, 0xcc2467f3, 0x82387d45, 0xec7bd5cc, 0x61fcb9df, 0x41cddd7b, 0x217d8114, 0x3577dc8f, 0x23de356a, 0x7e97704e),
|
||||
SECP256K1_GE_STORAGE_CONST(0x531f7239, 0xaebc780e, 0x179fbf8d, 0x412a1b01, 0x511f0abc, 0xe0c46151, 0x8b38db84, 0xcc2467f3, 0x7dc782ba, 0x13842a33, 0x9e034620, 0xbe322284, 0xde827eeb, 0xca882370, 0xdc21ca94, 0x81688be1),
|
||||
SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0x56716069, 0x6818286b, 0x72f01a3e, 0x5e8caca7, 0x36249160, 0xc7ded69d, 0xd51913c3, 0x03a2fa97),
|
||||
SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0xa98e9f96, 0x97e7d794, 0x8d0fe5c1, 0xa1735358, 0xc9db6e9f, 0x38212962, 0x2ae6ec3b, 0xfc5d0198),
|
||||
SECP256K1_GE_STORAGE_CONST(0x5e5936b1, 0x81db0b65, 0x8e33a8c6, 0x1aa687dd, 0x31d11e15, 0x85e35664, 0x6b4c2071, 0xcde7e942, 0x88bb5332, 0xa8e05654, 0x78d4f60c, 0x0cd979ec, 0x938558f2, 0xcac11216, 0x7c387a56, 0xe3a6d5f3),
|
||||
SECP256K1_GE_STORAGE_CONST(0x5e5936b1, 0x81db0b65, 0x8e33a8c6, 0x1aa687dd, 0x31d11e15, 0x85e35664, 0x6b4c2071, 0xcde7e942, 0x7744accd, 0x571fa9ab, 0x872b09f3, 0xf3268613, 0x6c7aa70d, 0x353eede9, 0x83c785a8, 0x1c59263c),
|
||||
SECP256K1_GE_STORAGE_CONST(0x657d438f, 0xfac34a50, 0x463fd07c, 0x3f09f320, 0x4c98e8ed, 0x6927e330, 0xc0c7735f, 0x76d32f6d, 0x577c2b11, 0xcaca2f6f, 0xd60bcaf0, 0x3e7cebe9, 0x5da6e1f4, 0xbb557f12, 0x2a397331, 0x81df897f),
|
||||
SECP256K1_GE_STORAGE_CONST(0x657d438f, 0xfac34a50, 0x463fd07c, 0x3f09f320, 0x4c98e8ed, 0x6927e330, 0xc0c7735f, 0x76d32f6d, 0xa883d4ee, 0x3535d090, 0x29f4350f, 0xc1831416, 0xa2591e0b, 0x44aa80ed, 0xd5c68ccd, 0x7e2072b0),
|
||||
SECP256K1_GE_STORAGE_CONST(0xbe0bc11b, 0x2bc639cb, 0xc28f72a8, 0xd07c21cc, 0xbc06cfa7, 0x4c2ff25e, 0x630c9740, 0x23128eab, 0x6f062fc8, 0x75148197, 0xd10375c3, 0xcc3fadb6, 0x20277e9c, 0x00579c55, 0xeddd7f95, 0xe95604db),
|
||||
SECP256K1_GE_STORAGE_CONST(0xbe0bc11b, 0x2bc639cb, 0xc28f72a8, 0xd07c21cc, 0xbc06cfa7, 0x4c2ff25e, 0x630c9740, 0x23128eab, 0x90f9d037, 0x8aeb7e68, 0x2efc8a3c, 0x33c05249, 0xdfd88163, 0xffa863aa, 0x12228069, 0x16a9f754),
|
||||
SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0xfdda0ad6, 0x118a5350, 0x3303ba9f, 0xd93a1b94, 0x07fdc85c, 0xc6db9aa5, 0xe906f176, 0xf7a12705),
|
||||
SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0x0225f529, 0xee75acaf, 0xccfc4560, 0x26c5e46b, 0xf80237a3, 0x3924655a, 0x16f90e88, 0x085ed52a),
|
||||
SECP256K1_GE_STORAGE_CONST(0xaee172d4, 0xce7c5010, 0xdb20a88f, 0x469598c1, 0xd7f7926f, 0xabb85cb5, 0x339f1403, 0x87e6b494, 0x38065980, 0x4de81b35, 0x098c7190, 0xe3380f9d, 0x95b2ed6c, 0x6c869e85, 0xc772bc5a, 0x7bc3d9d5),
|
||||
SECP256K1_GE_STORAGE_CONST(0xaee172d4, 0xce7c5010, 0xdb20a88f, 0x469598c1, 0xd7f7926f, 0xabb85cb5, 0x339f1403, 0x87e6b494, 0xc7f9a67f, 0xb217e4ca, 0xf6738e6f, 0x1cc7f062, 0x6a4d1293, 0x9379617a, 0x388d43a4, 0x843c225a),
|
||||
SECP256K1_GE_STORAGE_CONST(0xc28f5c28, 0xf5c28f5c, 0x28f5c28f, 0x5c28f5c2, 0x8f5c28f5, 0xc28f5c28, 0xf5c28f5b, 0x6666635a, 0x0c4da840, 0x1b2cf5be, 0x4604e6ec, 0xf92b2780, 0x063a5351, 0xe294bf65, 0xbb2f8b61, 0x00902db7),
|
||||
SECP256K1_GE_STORAGE_CONST(0xc28f5c28, 0xf5c28f5c, 0x28f5c28f, 0x5c28f5c2, 0x8f5c28f5, 0xc28f5c28, 0xf5c28f5b, 0x6666635a, 0xf3b257bf, 0xe4d30a41, 0xb9fb1913, 0x06d4d87f, 0xf9c5acae, 0x1d6b409a, 0x44d0749d, 0xff6fce78),
|
||||
SECP256K1_GE_STORAGE_CONST(0xecf56be6, 0x9c8fde26, 0x152832c6, 0xe043b3d5, 0xaf9a723f, 0x789854a0, 0xcb1b810d, 0xe2614ece, 0x66127ae4, 0xe4c17a75, 0x60a727e6, 0xffd2ea7f, 0xaed99088, 0xbec465c6, 0xbde56791, 0x37ed5572),
|
||||
SECP256K1_GE_STORAGE_CONST(0xecf56be6, 0x9c8fde26, 0x152832c6, 0xe043b3d5, 0xaf9a723f, 0x789854a0, 0xcb1b810d, 0xe2614ece, 0x99ed851b, 0x1b3e858a, 0x9f58d819, 0x002d1580, 0x51266f77, 0x413b9a39, 0x421a986d, 0xc812a6bd),
|
||||
SECP256K1_GE_STORAGE_CONST(0xba72860f, 0x10fcd142, 0x23f71e3c, 0x228deb9a, 0xc46c5ff5, 0x90b884e5, 0xcc60d51e, 0x0629d16e, 0x67999f31, 0x5a74ada3, 0x526832cf, 0x76b9fec3, 0xa348cc97, 0x33c3aa67, 0x02bd2516, 0x7814f635),
|
||||
SECP256K1_GE_STORAGE_CONST(0xba72860f, 0x10fcd142, 0x23f71e3c, 0x228deb9a, 0xc46c5ff5, 0x90b884e5, 0xcc60d51e, 0x0629d16e, 0x986660ce, 0xa58b525c, 0xad97cd30, 0x8946013c, 0x5cb73368, 0xcc3c5598, 0xfd42dae8, 0x87eb05fa),
|
||||
SECP256K1_GE_STORAGE_CONST(0x92ef5657, 0xdba51cc7, 0xf3e1b442, 0xa6a0916b, 0x8ce03079, 0x2ef5657d, 0xba51cc7e, 0xab2beb65, 0x782c65d2, 0x3f1e0eb2, 0x9179a994, 0xe5e8ff80, 0x5a0d50d9, 0xdeeaed90, 0xcec96ca5, 0x973e2ad3),
|
||||
SECP256K1_GE_STORAGE_CONST(0x92ef5657, 0xdba51cc7, 0xf3e1b442, 0xa6a0916b, 0x8ce03079, 0x2ef5657d, 0xba51cc7e, 0xab2beb65, 0x87d39a2d, 0xc0e1f14d, 0x6e86566b, 0x1a17007f, 0xa5f2af26, 0x2115126f, 0x31369359, 0x68c1d15c),
|
||||
SECP256K1_GE_STORAGE_CONST(0x9468ad22, 0xf921fc78, 0x8de3f1b0, 0x586c58eb, 0x5e6f0270, 0xe950b602, 0x7ada90d9, 0xd71ae323, 0x922a0c6a, 0x9ccc31d9, 0xc3bf87fd, 0x88381739, 0x35fe393f, 0xa64dfdec, 0x29f2846d, 0x12918d86),
|
||||
SECP256K1_GE_STORAGE_CONST(0x9468ad22, 0xf921fc78, 0x8de3f1b0, 0x586c58eb, 0x5e6f0270, 0xe950b602, 0x7ada90d9, 0xd71ae323, 0x6dd5f395, 0x6333ce26, 0x3c407802, 0x77c7e8c6, 0xca01c6c0, 0x59b20213, 0xd60d7b91, 0xed6e6ea9),
|
||||
SECP256K1_GE_STORAGE_CONST(0x76ddc7f5, 0xe029e59e, 0x22b0e54f, 0xa811db94, 0x5a209c4f, 0x5e912ca2, 0x8b4da6a7, 0x4c1e00a2, 0x1e8f516c, 0x91c20437, 0x50f6e24e, 0x8c2cf202, 0xacf68291, 0xbf8b66eb, 0xf7335b62, 0xec2c88fe),
|
||||
SECP256K1_GE_STORAGE_CONST(0x76ddc7f5, 0xe029e59e, 0x22b0e54f, 0xa811db94, 0x5a209c4f, 0x5e912ca2, 0x8b4da6a7, 0x4c1e00a2, 0xe170ae93, 0x6e3dfbc8, 0xaf091db1, 0x73d30dfd, 0x53097d6e, 0x40749914, 0x08cca49c, 0x13d37331),
|
||||
SECP256K1_GE_STORAGE_CONST(0xf75763bc, 0x2907e79b, 0x125e33c3, 0x9a027f48, 0x0f8c6409, 0x2153432f, 0x967bc2b1, 0x1d1f5cf0, 0xb4a8edc6, 0x36391b39, 0x9bc219c0, 0x3d033128, 0xdbcd463e, 0xd2506394, 0x061b87a5, 0x9e510235),
|
||||
SECP256K1_GE_STORAGE_CONST(0xf75763bc, 0x2907e79b, 0x125e33c3, 0x9a027f48, 0x0f8c6409, 0x2153432f, 0x967bc2b1, 0x1d1f5cf0, 0x4b571239, 0xc9c6e4c6, 0x643de63f, 0xc2fcced7, 0x2432b9c1, 0x2daf9c6b, 0xf9e47859, 0x61aef9fa),
|
||||
};
|
||||
|
||||
secp256k1_ge ge;
|
||||
secp256k1_fe fe;
|
||||
secp256k1_ge_storage ges;
|
||||
int i, s;
|
||||
for (i = 1; i <= 16; i++) {
|
||||
secp256k1_fe_set_int(&fe, i);
|
||||
|
||||
for (s = 0; s < 2; s++) {
|
||||
if (s) {
|
||||
secp256k1_fe_negate(&fe, &fe, 1);
|
||||
secp256k1_fe_normalize(&fe);
|
||||
}
|
||||
shallue_van_de_woestijne(&ge, &fe);
|
||||
secp256k1_ge_to_storage(&ges, &ge);
|
||||
|
||||
CHECK(memcmp(&ges, &results[i * 2 + s - 2], sizeof(secp256k1_ge_storage)) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_generator_generate(void) {
|
||||
static const secp256k1_ge_storage results[32] = {
|
||||
SECP256K1_GE_STORAGE_CONST(0x806cd8ed, 0xd6c153e3, 0x4aa9b9a0, 0x8755c4be, 0x4718b1ef, 0xb26cb93f, 0xfdd99e1b, 0x21f2af8e, 0xc7062208, 0xcc649a03, 0x1bdc1a33, 0x9d01f115, 0x4bcd0dca, 0xfe0b875d, 0x62f35f73, 0x28673006),
|
||||
SECP256K1_GE_STORAGE_CONST(0xd91b15ec, 0x47a811f4, 0xaa189561, 0xd13f5c4d, 0x4e81f10d, 0xc7dc551f, 0x4fea9b84, 0x610314c4, 0x9b0ada1e, 0xb38efd67, 0x8bff0b6c, 0x7d7315f7, 0xb49b8cc5, 0xa679fad4, 0xc94f9dc6, 0x9da66382),
|
||||
SECP256K1_GE_STORAGE_CONST(0x11c00de6, 0xf885035e, 0x76051430, 0xa3c38b2a, 0x5f86ab8c, 0xf66dae58, 0x04ea7307, 0x348b19bf, 0xe0858ae7, 0x61dcb1ba, 0xff247e37, 0xd38fcd88, 0xf3bd7911, 0xaa4ed6e0, 0x28d792dd, 0x3ee1ac09),
|
||||
SECP256K1_GE_STORAGE_CONST(0x986b99eb, 0x3130e7f0, 0xe779f674, 0xb85cb514, 0x46a676bf, 0xb1dfb603, 0x4c4bb639, 0x7c406210, 0xdf900609, 0x8b3ef1e0, 0x30e32fb0, 0xd97a4329, 0xff98aed0, 0xcd278c3f, 0xe6078467, 0xfbd12f35),
|
||||
SECP256K1_GE_STORAGE_CONST(0xae528146, 0x03fdf91e, 0xc592977e, 0x12461dc7, 0xb9e038f8, 0x048dcb62, 0xea264756, 0xd459ae42, 0x80ef658d, 0x92becb84, 0xdba8e4f9, 0x560d7a72, 0xbaf4c393, 0xfbcf6007, 0x11039f1c, 0x224faaad),
|
||||
SECP256K1_GE_STORAGE_CONST(0x00df3d91, 0x35975eee, 0x91fab903, 0xe3128e4a, 0xca071dde, 0x270814e5, 0xcbda69ec, 0xcad58f46, 0x11b590aa, 0x92d89969, 0x2dbd932f, 0x08013b8b, 0x45afabc6, 0x43677db2, 0x143e0c0f, 0x5865fb03),
|
||||
SECP256K1_GE_STORAGE_CONST(0x1168155b, 0x987e9bc8, 0x84c5f3f4, 0x92ebf784, 0xcc8c6735, 0x39d8e5e8, 0xa967115a, 0x2949da9b, 0x0858a470, 0xf403ca97, 0xb1827f6f, 0x544c2c67, 0x08f6cb83, 0xc510c317, 0x96c981ed, 0xb9f61780),
|
||||
SECP256K1_GE_STORAGE_CONST(0xe8d7c0cf, 0x2bb4194c, 0x97bf2a36, 0xbd115ba0, 0x81a9afe8, 0x7663fa3c, 0x9c3cd253, 0x79fe2571, 0x2028ad04, 0xefa00119, 0x5a25d598, 0x67e79502, 0x49de7c61, 0x4751cd9d, 0x4fb317f6, 0xf76f1110),
|
||||
SECP256K1_GE_STORAGE_CONST(0x9532c491, 0xa64851dd, 0xcd0d3e5a, 0x93e17267, 0xa10aca95, 0xa23781aa, 0x5087f340, 0xc45fecc3, 0xb691ddc2, 0x3143a7b6, 0x09969302, 0x258affb8, 0x5bbf8666, 0xe1192319, 0xeb174d88, 0x308bd57a),
|
||||
SECP256K1_GE_STORAGE_CONST(0x6b20b6e2, 0x1ba6cc44, 0x3f2c3a0c, 0x5283ba44, 0xbee43a0a, 0x2799a6cf, 0xbecc0f8a, 0xf8c583ac, 0xf7021e76, 0xd51291a6, 0xf9396215, 0x686f25aa, 0xbec36282, 0x5e11eeea, 0x6e51a6e6, 0xd7d7c006),
|
||||
SECP256K1_GE_STORAGE_CONST(0xde27e6ff, 0x219b3ab1, 0x2b0a9e4e, 0x51fc6092, 0x96e55af6, 0xc6f717d6, 0x12cd6cce, 0x65d6c8f2, 0x48166884, 0x4dc13fd2, 0xed7a7d81, 0x66a0839a, 0x8a960863, 0xfe0001c1, 0x35d206fd, 0x63b87c09),
|
||||
SECP256K1_GE_STORAGE_CONST(0x79a96fb8, 0xd88a08d3, 0x055d38d1, 0x3346b0d4, 0x47d838ca, 0xfcc8fa40, 0x6d3a7157, 0xef84e7e3, 0x6bab9c45, 0x2871b51d, 0xb0df2369, 0xe7860e01, 0x2e37ffea, 0x6689fd1a, 0x9c6fe9cf, 0xb940acea),
|
||||
SECP256K1_GE_STORAGE_CONST(0x06c4d4cb, 0xd32c0ddb, 0x67e988c6, 0x2bdbe6ad, 0xa39b80cc, 0x61afb347, 0x234abe27, 0xa689618c, 0x5b355949, 0xf904fe08, 0x569b2313, 0xe8f19f8d, 0xc5b79e27, 0x70da0832, 0x5fb7a229, 0x238ca6b6),
|
||||
SECP256K1_GE_STORAGE_CONST(0x7027e566, 0x3e727c28, 0x42aa14e5, 0x52c2d2ec, 0x1d8beaa9, 0x8a22ceab, 0x15ccafc3, 0xb4f06249, 0x9b3dffbc, 0xdbd5e045, 0x6931fd03, 0x8b1c6a9b, 0x4c168c6d, 0xa6553897, 0xfe11ce49, 0xac728139),
|
||||
SECP256K1_GE_STORAGE_CONST(0xee3520c3, 0x9f2b954d, 0xf8e15547, 0xdaeb6cc8, 0x04c8f3b0, 0x9301f53e, 0xe0c11ea1, 0xeace539d, 0x244ff873, 0x7e060c98, 0xe843c353, 0xcd35d2e4, 0x3cd8b082, 0xcffbc9ae, 0x81eafa70, 0x332f9748),
|
||||
SECP256K1_GE_STORAGE_CONST(0xdaecd756, 0xf5b706a4, 0xc14e1095, 0x3e2f70df, 0xa81276e7, 0x71806b89, 0x4d8a5502, 0xa0ef4998, 0xbac906c0, 0x948b1d48, 0xe023f439, 0xfd3770b8, 0x837f60cc, 0x40552a51, 0x433d0b79, 0x6610da27),
|
||||
SECP256K1_GE_STORAGE_CONST(0x55e1ca28, 0x750fe2d0, 0x57f7449b, 0x3f49d999, 0x3b9616dd, 0x5387bc2e, 0x6e6698f8, 0xc4ea49f4, 0xe339e0e9, 0xa4c7fa99, 0xd063e062, 0x6582bce2, 0x33c6b1ee, 0x17a5b47f, 0x6d43ecf8, 0x98b40120),
|
||||
SECP256K1_GE_STORAGE_CONST(0xdd82cac2, 0x9e0e0135, 0x4964d3bc, 0x27469233, 0xf13bbd5e, 0xd7aff24b, 0x4902fca8, 0x17294b12, 0x561ab1d6, 0xcd9bcb6e, 0x805585cf, 0x3df8714c, 0x1bfa6304, 0x5efbf122, 0x1a3d8fd9, 0x3827764a),
|
||||
SECP256K1_GE_STORAGE_CONST(0xda5cbfb7, 0x3522e9c7, 0xcb594436, 0x83677038, 0x0eaa64a9, 0x2eca3888, 0x0fe4c9d6, 0xdeb22dbf, 0x4f46de68, 0x0447c780, 0xc54a314b, 0x5389a926, 0xbba8910b, 0x869fc6cd, 0x42ee82e8, 0x5895e42a),
|
||||
SECP256K1_GE_STORAGE_CONST(0x4e09830e, 0xc8894c58, 0x4e6278de, 0x167a96b0, 0x20d60463, 0xee48f788, 0x4974d66e, 0x871e35e9, 0x21259c4d, 0x332ca932, 0x2e187df9, 0xe7afbc23, 0x9d171ebc, 0x7d9e2560, 0x503f50b1, 0x9fe45834),
|
||||
SECP256K1_GE_STORAGE_CONST(0xabfff6ca, 0x41dcfd17, 0x03cae629, 0x9d127971, 0xf19ee000, 0x2db332e6, 0x5cc209a3, 0xc21b8f54, 0x65991d60, 0xee54f5cc, 0xddf7a732, 0xa76b0303, 0xb9f519a6, 0x22ea0390, 0x8af23ffa, 0x35ae6632),
|
||||
SECP256K1_GE_STORAGE_CONST(0xc6c9b92c, 0x91e045a5, 0xa1913277, 0x44d6fce2, 0x11b12c7c, 0x9b3112d6, 0xc61e14a6, 0xd6b1ae12, 0x04ab0396, 0xebdc4c6a, 0xc213cc3e, 0x077a2e80, 0xb4ba7b2b, 0x33907d56, 0x2c98ccf7, 0xb82a2e9f),
|
||||
SECP256K1_GE_STORAGE_CONST(0x66f6e6d9, 0xc4bb9a5f, 0x99085781, 0x83cb9362, 0x2ea437d8, 0xccd31969, 0xffadca3a, 0xff1d3935, 0x50a5b06e, 0x39e039d7, 0x1dfb2723, 0x18db74e5, 0x5af64da1, 0xdfc34586, 0x6aac3bd0, 0x5792a890),
|
||||
SECP256K1_GE_STORAGE_CONST(0x58ded03c, 0x98e1a890, 0x63fc7793, 0xe3ecd896, 0x235e75c9, 0x82e7008f, 0xddbf3ca8, 0x5b7e9ecb, 0x34594776, 0x58ab6821, 0xaf43a453, 0xa946fda9, 0x13d24999, 0xccf22df8, 0xd291ef59, 0xb08975c0),
|
||||
SECP256K1_GE_STORAGE_CONST(0x74557864, 0x4f2b0486, 0xd5beea7c, 0x2d258ccb, 0x78a870e1, 0x848982d8, 0xed3f91a4, 0x9db83a36, 0xd84e940e, 0x1d33c28a, 0x62398ec8, 0xc493aee7, 0x7c2ba722, 0x42dee7ae, 0x3c35c256, 0xad00cf42),
|
||||
SECP256K1_GE_STORAGE_CONST(0x7fc7963a, 0x16abc8fb, 0x5d61eb61, 0x0fc50a68, 0x754470d2, 0xf43df3be, 0x52228f66, 0x522fe61b, 0x499f9e7f, 0x462c6545, 0x29687af4, 0x9f7c732d, 0x48801ce5, 0x21acd546, 0xc6fb903c, 0x7c265032),
|
||||
SECP256K1_GE_STORAGE_CONST(0xb2f6257c, 0xc58df82f, 0xb9ba4f36, 0x7ededf03, 0xf8ea10f3, 0x104d7ae6, 0x233b7ac4, 0x725e11de, 0x9c7a32df, 0x4842f33d, 0xaad84f0b, 0x62e88b40, 0x46ddcbde, 0xbbeec6f8, 0x93bfde27, 0x0561dc73),
|
||||
SECP256K1_GE_STORAGE_CONST(0xe2cdfd27, 0x8a8e22be, 0xabf08b79, 0x1bc6ae38, 0x41d22a9a, 0x9472e266, 0x1a7c6e83, 0xa2f74725, 0x0e26c103, 0xe0dd93b2, 0x3724f3b7, 0x8bb7366e, 0x2c245768, 0xd64f3283, 0xd8316e8a, 0x1383b977),
|
||||
SECP256K1_GE_STORAGE_CONST(0x757c13e7, 0xe866017e, 0xe6af61d7, 0x161d208a, 0xc438f712, 0x242fcd23, 0x63a10e59, 0xd67e41fb, 0xb550c6a9, 0x4ddb15f3, 0xfeea4bfe, 0xd2faa19f, 0x2aa2fbd3, 0x0c6ae785, 0xe357f365, 0xb30d12e0),
|
||||
SECP256K1_GE_STORAGE_CONST(0x528d525e, 0xac30095b, 0x5e5f83ca, 0x4d3dea63, 0xeb608f2d, 0x18dd25a7, 0x2529c8e5, 0x1ae5f9f1, 0xfde2860b, 0x492a4106, 0x9f356c05, 0x3ebc045e, 0x4ad08b79, 0x3e264935, 0xf25785a9, 0x8690b5ee),
|
||||
SECP256K1_GE_STORAGE_CONST(0x150df593, 0x5b6956a0, 0x0cfed843, 0xb9d6ffce, 0x4f790022, 0xea18730f, 0xc495111d, 0x91568e55, 0x6700a2ca, 0x9ff4ed32, 0xc1697312, 0x4eb51ce3, 0x5656344b, 0x65a1e3d5, 0xd6c1f7ce, 0x29233f82),
|
||||
SECP256K1_GE_STORAGE_CONST(0x38e02eaf, 0x2c8774fd, 0x58b8b373, 0x732457f1, 0x16dbe53b, 0xea5683d9, 0xada20dd7, 0x14ce20a6, 0x6ac5362e, 0xbb425416, 0x8250f43f, 0xa4ee2b63, 0x0406324f, 0x1c876d60, 0xebe5be2c, 0x6eb1515b),
|
||||
};
|
||||
secp256k1_generator gen;
|
||||
secp256k1_ge ge;
|
||||
secp256k1_ge_storage ges;
|
||||
int i;
|
||||
unsigned char v[32];
|
||||
static const unsigned char s[32] = {0};
|
||||
secp256k1_scalar sc;
|
||||
secp256k1_scalar_set_b32(&sc, s, NULL);
|
||||
for (i = 1; i <= 32; i++) {
|
||||
memset(v, 0, 31);
|
||||
v[31] = i;
|
||||
CHECK(secp256k1_generator_generate_blinded(ctx, &gen, v, s));
|
||||
secp256k1_generator_load(&ge, &gen);
|
||||
secp256k1_ge_to_storage(&ges, &ge);
|
||||
CHECK(memcmp(&ges, &results[i - 1], sizeof(secp256k1_ge_storage)) == 0);
|
||||
CHECK(secp256k1_generator_generate(ctx, &gen, v));
|
||||
secp256k1_generator_load(&ge, &gen);
|
||||
secp256k1_ge_to_storage(&ges, &ge);
|
||||
CHECK(memcmp(&ges, &results[i - 1], sizeof(secp256k1_ge_storage)) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
void run_generator_tests(void) {
|
||||
test_shallue_van_de_woestijne();
|
||||
test_generator_generate();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -15,10 +15,10 @@
|
|||
#include "ecmult_gen.h"
|
||||
|
||||
int secp256k1_borromean_verify(const secp256k1_ecmult_context* ecmult_ctx, secp256k1_scalar *evalues, const unsigned char *e0, const secp256k1_scalar *s,
|
||||
const secp256k1_gej *pubs, const int *rsizes, int nrings, const unsigned char *m, int mlen);
|
||||
const secp256k1_gej *pubs, const size_t *rsizes, size_t nrings, const unsigned char *m, size_t mlen);
|
||||
|
||||
int secp256k1_borromean_sign(const secp256k1_ecmult_context* ecmult_ctx, const secp256k1_ecmult_gen_context *ecmult_gen_ctx,
|
||||
unsigned char *e0, secp256k1_scalar *s, const secp256k1_gej *pubs, const secp256k1_scalar *k, const secp256k1_scalar *sec,
|
||||
const int *rsizes, const int *secidx, int nrings, const unsigned char *m, int mlen);
|
||||
const size_t *rsizes, const size_t *secidx, size_t nrings, const unsigned char *m, size_t mlen);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -11,11 +11,14 @@
|
|||
#include "scalar.h"
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
#include "hash.h"
|
||||
#include "eckey.h"
|
||||
#include "ecmult.h"
|
||||
#include "ecmult_gen.h"
|
||||
#include "borromean.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define BE32(x) (x)
|
||||
|
|
@ -23,8 +26,8 @@
|
|||
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
|
||||
#endif
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_borromean_hash(unsigned char *hash, const unsigned char *m, int mlen, const unsigned char *e, int elen,
|
||||
int ridx, int eidx) {
|
||||
SECP256K1_INLINE static void secp256k1_borromean_hash(unsigned char *hash, const unsigned char *m, size_t mlen, const unsigned char *e, size_t elen,
|
||||
size_t ridx, size_t eidx) {
|
||||
uint32_t ring;
|
||||
uint32_t epos;
|
||||
secp256k1_sha256_t sha256_en;
|
||||
|
|
@ -53,15 +56,15 @@ SECP256K1_INLINE static void secp256k1_borromean_hash(unsigned char *hash, const
|
|||
* | return e_0 ==== H(r_{0..i}||m)
|
||||
*/
|
||||
int secp256k1_borromean_verify(const secp256k1_ecmult_context* ecmult_ctx, secp256k1_scalar *evalues, const unsigned char *e0,
|
||||
const secp256k1_scalar *s, const secp256k1_gej *pubs, const int *rsizes, int nrings, const unsigned char *m, int mlen) {
|
||||
const secp256k1_scalar *s, const secp256k1_gej *pubs, const size_t *rsizes, size_t nrings, const unsigned char *m, size_t mlen) {
|
||||
secp256k1_gej rgej;
|
||||
secp256k1_ge rge;
|
||||
secp256k1_scalar ens;
|
||||
secp256k1_sha256_t sha256_e0;
|
||||
unsigned char tmp[33];
|
||||
int i;
|
||||
int j;
|
||||
int count;
|
||||
size_t i;
|
||||
size_t j;
|
||||
size_t count;
|
||||
size_t size;
|
||||
int overflow;
|
||||
VERIFY_CHECK(ecmult_ctx != NULL);
|
||||
|
|
@ -108,15 +111,15 @@ int secp256k1_borromean_verify(const secp256k1_ecmult_context* ecmult_ctx, secp2
|
|||
|
||||
int secp256k1_borromean_sign(const secp256k1_ecmult_context* ecmult_ctx, const secp256k1_ecmult_gen_context *ecmult_gen_ctx,
|
||||
unsigned char *e0, secp256k1_scalar *s, const secp256k1_gej *pubs, const secp256k1_scalar *k, const secp256k1_scalar *sec,
|
||||
const int *rsizes, const int *secidx, int nrings, const unsigned char *m, int mlen) {
|
||||
const size_t *rsizes, const size_t *secidx, size_t nrings, const unsigned char *m, size_t mlen) {
|
||||
secp256k1_gej rgej;
|
||||
secp256k1_ge rge;
|
||||
secp256k1_scalar ens;
|
||||
secp256k1_sha256_t sha256_e0;
|
||||
unsigned char tmp[33];
|
||||
int i;
|
||||
int j;
|
||||
int count;
|
||||
size_t i;
|
||||
size_t j;
|
||||
size_t count;
|
||||
size_t size;
|
||||
int overflow;
|
||||
VERIFY_CHECK(ecmult_ctx != NULL);
|
||||
|
|
|
|||
|
|
@ -7,34 +7,82 @@
|
|||
#ifndef SECP256K1_MODULE_RANGEPROOF_MAIN
|
||||
#define SECP256K1_MODULE_RANGEPROOF_MAIN
|
||||
|
||||
#include "group.h"
|
||||
|
||||
#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* ctx) {
|
||||
secp256k1_pedersen_context_build(&ctx->pedersen_ctx, &ctx->error_callback);
|
||||
/** 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' % (11 - G2.xy()[1].is_square(), G2.xy()[0])
|
||||
*/
|
||||
static const secp256k1_generator secp256k1_generator_h_internal = {{
|
||||
0x11,
|
||||
0x50, 0x92, 0x9b, 0x74, 0xc1, 0xa0, 0x49, 0x54, 0xb7, 0x8b, 0x4b, 0x60, 0x35, 0xe9, 0x7a, 0x5e,
|
||||
0x07, 0x8a, 0x5a, 0x0f, 0x28, 0xec, 0x96, 0xd5, 0x47, 0xbf, 0xee, 0x9a, 0xce, 0x80, 0x3a, 0xc0
|
||||
}};
|
||||
|
||||
const secp256k1_generator *secp256k1_generator_h = &secp256k1_generator_h_internal;
|
||||
|
||||
static void secp256k1_pedersen_commitment_load(secp256k1_ge* ge, const secp256k1_pedersen_commitment* commit) {
|
||||
secp256k1_fe fe;
|
||||
secp256k1_fe_set_b32(&fe, &commit->data[1]);
|
||||
secp256k1_ge_set_xquad(ge, &fe);
|
||||
if (commit->data[0] & 1) {
|
||||
secp256k1_ge_neg(ge, ge);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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* ctx, unsigned char *commit, unsigned char *blind, uint64_t value) {
|
||||
static void secp256k1_pedersen_commitment_save(secp256k1_pedersen_commitment* commit, secp256k1_ge* ge) {
|
||||
secp256k1_fe_normalize(&ge->x);
|
||||
secp256k1_fe_get_b32(&commit->data[1], &ge->x);
|
||||
commit->data[0] = 9 ^ secp256k1_fe_is_quad_var(&ge->y);
|
||||
}
|
||||
|
||||
int secp256k1_pedersen_commitment_parse(const secp256k1_context* ctx, secp256k1_pedersen_commitment* commit, const unsigned char *input) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(input != NULL);
|
||||
(void) ctx;
|
||||
if ((input[0] & 0xFE) != 8) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(commit->data, input, sizeof(commit->data));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_pedersen_commitment_serialize(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pedersen_commitment* commit) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
memcpy(output, commit->data, sizeof(commit->data));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generates a pedersen commitment: *commit = blind * G + value * G2. The blinding factor is 32 bytes.*/
|
||||
int secp256k1_pedersen_commit(const secp256k1_context* ctx, secp256k1_pedersen_commitment *commit, const unsigned char *blind, uint64_t value, const secp256k1_generator* gen) {
|
||||
secp256k1_ge genp;
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge r;
|
||||
secp256k1_scalar sec;
|
||||
size_t sz;
|
||||
int overflow;
|
||||
int ret = 0;
|
||||
ARG_CHECK(ctx != NULL);
|
||||
VERIFY_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);
|
||||
ARG_CHECK(gen != NULL);
|
||||
secp256k1_generator_load(&genp, gen);
|
||||
secp256k1_scalar_set_b32(&sec, blind, &overflow);
|
||||
if (!overflow) {
|
||||
secp256k1_pedersen_ecmult(&ctx->ecmult_gen_ctx, &ctx->pedersen_ctx, &rj, &sec, value);
|
||||
secp256k1_pedersen_ecmult(&ctx->ecmult_gen_ctx, &rj, &sec, value, &genp);
|
||||
if (!secp256k1_gej_is_infinity(&rj)) {
|
||||
secp256k1_ge_set_gej(&r, &rj);
|
||||
sz = 33;
|
||||
ret = secp256k1_eckey_pubkey_serialize(&r, commit, &sz, 1);
|
||||
secp256k1_pedersen_commitment_save(commit, &r);
|
||||
ret = 1;
|
||||
}
|
||||
secp256k1_gej_clear(&rj);
|
||||
secp256k1_ge_clear(&r);
|
||||
|
|
@ -46,14 +94,16 @@ int secp256k1_pedersen_commit(const secp256k1_context* ctx, unsigned char *commi
|
|||
/** 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* ctx, unsigned char *blind_out, const unsigned char * const *blinds, int n, int npositive) {
|
||||
int secp256k1_pedersen_blind_sum(const secp256k1_context* ctx, unsigned char *blind_out, const unsigned char * const *blinds, size_t n, size_t npositive) {
|
||||
secp256k1_scalar acc;
|
||||
secp256k1_scalar x;
|
||||
int i;
|
||||
size_t i;
|
||||
int overflow;
|
||||
ARG_CHECK(ctx != NULL);
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(blind_out != NULL);
|
||||
ARG_CHECK(blinds != NULL);
|
||||
ARG_CHECK(npositive <= n);
|
||||
(void) ctx;
|
||||
secp256k1_scalar_set_int(&acc, 0);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_set_b32(&x, blinds[i], &overflow);
|
||||
|
|
@ -71,55 +121,91 @@ int secp256k1_pedersen_blind_sum(const secp256k1_context* ctx, unsigned char *bl
|
|||
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* ctx, const unsigned char * const *commits, int pcnt,
|
||||
const unsigned char * const *ncommits, int ncnt, int64_t excess) {
|
||||
/* Takes two lists of 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* ctx, const secp256k1_pedersen_commitment * const* commits, size_t pcnt, const secp256k1_pedersen_commitment * const* ncommits, size_t ncnt) {
|
||||
secp256k1_gej accj;
|
||||
secp256k1_ge add;
|
||||
int i;
|
||||
ARG_CHECK(ctx != NULL);
|
||||
size_t i;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(!pcnt || (commits != NULL));
|
||||
ARG_CHECK(!ncnt || (ncommits != NULL));
|
||||
ARG_CHECK(secp256k1_pedersen_context_is_built(&ctx->pedersen_ctx));
|
||||
(void) 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_pedersen_commitment_load(&add, ncommits[i]);
|
||||
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_pedersen_commitment_load(&add, commits[i]);
|
||||
secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL);
|
||||
}
|
||||
return secp256k1_gej_is_infinity(&accj);
|
||||
}
|
||||
|
||||
void secp256k1_rangeproof_context_initialize(secp256k1_context* ctx) {
|
||||
secp256k1_rangeproof_context_build(&ctx->rangeproof_ctx, &ctx->error_callback);
|
||||
int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, const uint64_t *value, const unsigned char* const* generator_blind, unsigned char* const* blinding_factor, size_t n_total, size_t n_inputs) {
|
||||
secp256k1_scalar sum;
|
||||
secp256k1_scalar tmp;
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(n_total == 0 || value != NULL);
|
||||
ARG_CHECK(n_total == 0 || generator_blind != NULL);
|
||||
ARG_CHECK(n_total == 0 || blinding_factor != NULL);
|
||||
ARG_CHECK(n_total > n_inputs);
|
||||
(void) ctx;
|
||||
|
||||
if (n_total == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_int(&sum, 0);
|
||||
for (i = 0; i < n_total; i++) {
|
||||
int overflow = 0;
|
||||
secp256k1_scalar addend;
|
||||
secp256k1_scalar_set_u64(&addend, value[i]); /* s = v */
|
||||
|
||||
secp256k1_scalar_set_b32(&tmp, generator_blind[i], &overflow);
|
||||
if (overflow == 1) {
|
||||
secp256k1_scalar_clear(&tmp);
|
||||
secp256k1_scalar_clear(&addend);
|
||||
secp256k1_scalar_clear(&sum);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_mul(&addend, &addend, &tmp); /* s = vr */
|
||||
|
||||
secp256k1_scalar_set_b32(&tmp, blinding_factor[i], &overflow);
|
||||
if (overflow == 1) {
|
||||
secp256k1_scalar_clear(&tmp);
|
||||
secp256k1_scalar_clear(&addend);
|
||||
secp256k1_scalar_clear(&sum);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_add(&addend, &addend, &tmp); /* s = vr + r' */
|
||||
secp256k1_scalar_cond_negate(&addend, i < n_inputs); /* s is negated if it's an input */
|
||||
secp256k1_scalar_add(&sum, &sum, &addend); /* sum += s */
|
||||
secp256k1_scalar_clear(&addend);
|
||||
}
|
||||
|
||||
/* Right now tmp has the last pedersen blinding factor. Subtract the sum from it. */
|
||||
secp256k1_scalar_negate(&sum, &sum);
|
||||
secp256k1_scalar_add(&tmp, &tmp, &sum);
|
||||
secp256k1_scalar_get_b32(blinding_factor[n_total - 1], &tmp);
|
||||
|
||||
secp256k1_scalar_clear(&tmp);
|
||||
secp256k1_scalar_clear(&sum);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_rangeproof_info(const secp256k1_context* ctx, int *exp, int *mantissa,
|
||||
uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, int plen) {
|
||||
int offset;
|
||||
uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, size_t plen) {
|
||||
size_t offset;
|
||||
uint64_t scale;
|
||||
ARG_CHECK(exp != NULL);
|
||||
ARG_CHECK(mantissa != NULL);
|
||||
ARG_CHECK(min_value != NULL);
|
||||
ARG_CHECK(max_value != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
offset = 0;
|
||||
scale = 1;
|
||||
(void)ctx;
|
||||
|
|
@ -127,50 +213,66 @@ int secp256k1_rangeproof_info(const secp256k1_context* ctx, int *exp, int *manti
|
|||
}
|
||||
|
||||
int secp256k1_rangeproof_rewind(const secp256k1_context* ctx,
|
||||
unsigned char *blind_out, uint64_t *value_out, unsigned char *message_out, int *outlen, const unsigned char *nonce,
|
||||
unsigned char *blind_out, uint64_t *value_out, unsigned char *message_out, size_t *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);
|
||||
const secp256k1_pedersen_commitment *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_generator* gen) {
|
||||
secp256k1_ge commitp;
|
||||
secp256k1_ge genp;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
ARG_CHECK(min_value != NULL);
|
||||
ARG_CHECK(max_value != NULL);
|
||||
ARG_CHECK(message_out != NULL || outlen == NULL);
|
||||
ARG_CHECK(nonce != NULL);
|
||||
ARG_CHECK(extra_commit != NULL || extra_commit_len == 0);
|
||||
ARG_CHECK(gen != 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);
|
||||
secp256k1_pedersen_commitment_load(&commitp, commit);
|
||||
secp256k1_generator_load(&genp, gen);
|
||||
return secp256k1_rangeproof_verify_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx,
|
||||
blind_out, value_out, message_out, outlen, nonce, min_value, max_value, &commitp, proof, plen, extra_commit, extra_commit_len, &genp);
|
||||
}
|
||||
|
||||
int secp256k1_rangeproof_verify(const secp256k1_context* ctx, uint64_t *min_value, uint64_t *max_value,
|
||||
const unsigned char *commit, const unsigned char *proof, int plen) {
|
||||
ARG_CHECK(ctx != NULL);
|
||||
const secp256k1_pedersen_commitment *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_generator* gen) {
|
||||
secp256k1_ge commitp;
|
||||
secp256k1_ge genp;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
ARG_CHECK(min_value != NULL);
|
||||
ARG_CHECK(max_value != NULL);
|
||||
ARG_CHECK(extra_commit != NULL || extra_commit_len == 0);
|
||||
ARG_CHECK(gen != 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);
|
||||
secp256k1_pedersen_commitment_load(&commitp, commit);
|
||||
secp256k1_generator_load(&genp, gen);
|
||||
return secp256k1_rangeproof_verify_impl(&ctx->ecmult_ctx, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, min_value, max_value, &commitp, proof, plen, extra_commit, extra_commit_len, &genp);
|
||||
}
|
||||
|
||||
int secp256k1_rangeproof_sign(const secp256k1_context* 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);
|
||||
int secp256k1_rangeproof_sign(const secp256k1_context* ctx, unsigned char *proof, size_t *plen, uint64_t min_value,
|
||||
const secp256k1_pedersen_commitment *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value,
|
||||
const unsigned char *message, size_t msg_len, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_generator* gen){
|
||||
secp256k1_ge commitp;
|
||||
secp256k1_ge genp;
|
||||
VERIFY_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(message != NULL || msg_len == 0);
|
||||
ARG_CHECK(extra_commit != NULL || extra_commit_len == 0);
|
||||
ARG_CHECK(gen != 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);
|
||||
secp256k1_pedersen_commitment_load(&commitp, commit);
|
||||
secp256k1_generator_load(&genp, gen);
|
||||
return secp256k1_rangeproof_sign_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx,
|
||||
proof, plen, min_value, &commitp, blind, nonce, exp, min_bits, value, message, msg_len, extra_commit, extra_commit_len, &genp);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -7,28 +7,16 @@
|
|||
#ifndef _SECP256K1_PEDERSEN_H_
|
||||
#define _SECP256K1_PEDERSEN_H_
|
||||
|
||||
#include "ecmult_gen.h"
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
secp256k1_ge_storage (*prec)[16][16]; /* prec[j][i] = 16^j * i * G + U_i */
|
||||
} secp256k1_pedersen_context;
|
||||
|
||||
static void secp256k1_pedersen_context_init(secp256k1_pedersen_context* ctx);
|
||||
static void secp256k1_pedersen_context_build(secp256k1_pedersen_context* ctx, const secp256k1_callback* cb);
|
||||
static void secp256k1_pedersen_context_clone(secp256k1_pedersen_context *dst,
|
||||
const secp256k1_pedersen_context* src, const secp256k1_callback* cb);
|
||||
static void secp256k1_pedersen_context_clear(secp256k1_pedersen_context* ctx);
|
||||
|
||||
static int secp256k1_pedersen_context_is_built(const secp256k1_pedersen_context* ctx);
|
||||
|
||||
/** Multiply a small number with the generator: r = gn*G2 */
|
||||
static void secp256k1_pedersen_ecmult_small(const secp256k1_pedersen_context *ctx, secp256k1_gej *r, uint64_t gn);
|
||||
static void secp256k1_pedersen_ecmult_small(secp256k1_gej *r, uint64_t gn, const secp256k1_ge* genp);
|
||||
|
||||
/* sec * G + value * G2. */
|
||||
static void secp256k1_pedersen_ecmult(const secp256k1_ecmult_gen_context *ecmult_gen_ctx,
|
||||
const secp256k1_pedersen_context *pedersen_ctx, secp256k1_gej *rj, const secp256k1_scalar *sec, uint64_t value);
|
||||
static void secp256k1_pedersen_ecmult(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_gej *rj, const secp256k1_scalar *sec, uint64_t value, const secp256k1_ge* genp);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -7,130 +7,42 @@
|
|||
#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 secp256k1_ge_const_g2 = SECP256K1_GE_CONST(
|
||||
0x50929b74UL, 0xc1a04954UL, 0xb78b4b60UL, 0x35e97a5eUL,
|
||||
0x078a5a0fUL, 0x28ec96d5UL, 0x47bfee9aUL, 0xce803ac0UL,
|
||||
0x31d3c686UL, 0x3973926eUL, 0x049e637cUL, 0xb1b5f40aUL,
|
||||
0x36dac28aUL, 0xf1766968UL, 0xc30c2313UL, 0xf3a38904UL
|
||||
);
|
||||
#include <string.h>
|
||||
|
||||
static void secp256k1_pedersen_context_init(secp256k1_pedersen_context *ctx) {
|
||||
ctx->prec = NULL;
|
||||
#include "eckey.h"
|
||||
#include "ecmult_const.h"
|
||||
#include "ecmult_gen.h"
|
||||
#include "group.h"
|
||||
#include "field.h"
|
||||
#include "scalar.h"
|
||||
#include "util.h"
|
||||
|
||||
static void secp256k1_pedersen_scalar_set_u64(secp256k1_scalar *sec, uint64_t value) {
|
||||
unsigned char data[32];
|
||||
int i;
|
||||
for (i = 0; i < 24; i++) {
|
||||
data[i] = 0;
|
||||
}
|
||||
for (; i < 32; i++) {
|
||||
data[i] = value >> 56;
|
||||
value <<= 8;
|
||||
}
|
||||
secp256k1_scalar_set_b32(sec, data, NULL);
|
||||
memset(data, 0, 32);
|
||||
}
|
||||
|
||||
static void secp256k1_pedersen_context_build(secp256k1_pedersen_context *ctx, const secp256k1_callback *cb) {
|
||||
secp256k1_ge prec[256];
|
||||
secp256k1_gej gj;
|
||||
secp256k1_gej nums_gej;
|
||||
int i, j;
|
||||
|
||||
if (ctx->prec != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->prec = (secp256k1_ge_storage (*)[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 nums_x;
|
||||
secp256k1_ge 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 precj[256]; /* Jacobian versions of prec. */
|
||||
secp256k1_gej gbase;
|
||||
secp256k1_gej 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* ctx) {
|
||||
return ctx->prec != NULL;
|
||||
}
|
||||
|
||||
static void secp256k1_pedersen_context_clone(secp256k1_pedersen_context *dst,
|
||||
const secp256k1_pedersen_context *src, const secp256k1_callback *cb) {
|
||||
if (src->prec == NULL) {
|
||||
dst->prec = NULL;
|
||||
} else {
|
||||
dst->prec = (secp256k1_ge_storage (*)[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 *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 *ctx, secp256k1_gej *r, uint64_t gn) {
|
||||
secp256k1_ge add;
|
||||
secp256k1_ge_storage 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);
|
||||
static void secp256k1_pedersen_ecmult_small(secp256k1_gej *r, uint64_t gn, const secp256k1_ge* genp) {
|
||||
secp256k1_scalar s;
|
||||
secp256k1_pedersen_scalar_set_u64(&s, gn);
|
||||
secp256k1_ecmult_const(r, genp, &s, 64);
|
||||
secp256k1_scalar_clear(&s);
|
||||
}
|
||||
|
||||
/* sec * G + value * G2. */
|
||||
SECP256K1_INLINE static void secp256k1_pedersen_ecmult(const secp256k1_ecmult_gen_context *ecmult_gen_ctx,
|
||||
const secp256k1_pedersen_context *pedersen_ctx, secp256k1_gej *rj, const secp256k1_scalar *sec, uint64_t value) {
|
||||
SECP256K1_INLINE static void secp256k1_pedersen_ecmult(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_gej *rj, const secp256k1_scalar *sec, uint64_t value, const secp256k1_ge* genp) {
|
||||
secp256k1_gej vj;
|
||||
secp256k1_ecmult_gen(ecmult_gen_ctx, rj, sec);
|
||||
secp256k1_pedersen_ecmult_small(pedersen_ctx, &vj, value);
|
||||
secp256k1_pedersen_ecmult_small(&vj, value, genp);
|
||||
/* FIXME: constant time. */
|
||||
secp256k1_gej_add_var(rj, rj, &vj, NULL);
|
||||
secp256k1_gej_clear(&vj);
|
||||
|
|
|
|||
|
|
@ -9,23 +9,13 @@
|
|||
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_ge_storage (*prec)[1005];
|
||||
} secp256k1_rangeproof_context;
|
||||
|
||||
|
||||
static void secp256k1_rangeproof_context_init(secp256k1_rangeproof_context* ctx);
|
||||
static void secp256k1_rangeproof_context_build(secp256k1_rangeproof_context* ctx, const secp256k1_callback* cb);
|
||||
static void secp256k1_rangeproof_context_clone(secp256k1_rangeproof_context *dst,
|
||||
const secp256k1_rangeproof_context* src, const secp256k1_callback* cb);
|
||||
static void secp256k1_rangeproof_context_clear(secp256k1_rangeproof_context* ctx);
|
||||
static int secp256k1_rangeproof_context_is_built(const secp256k1_rangeproof_context* ctx);
|
||||
#include "ecmult.h"
|
||||
#include "ecmult_gen.h"
|
||||
|
||||
static int secp256k1_rangeproof_verify_impl(const secp256k1_ecmult_context* ecmult_ctx,
|
||||
const secp256k1_ecmult_gen_context* ecmult_gen_ctx,
|
||||
const secp256k1_pedersen_context* pedersen_ctx, const secp256k1_rangeproof_context* 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);
|
||||
unsigned char *blindout, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce,
|
||||
uint64_t *min_value, uint64_t *max_value, const secp256k1_ge *commit, const unsigned char *proof, size_t plen,
|
||||
const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_ge* genp);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -7,150 +7,76 @@
|
|||
#ifndef _SECP256K1_RANGEPROOF_IMPL_H_
|
||||
#define _SECP256K1_RANGEPROOF_IMPL_H_
|
||||
|
||||
#include "eckey.h"
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
#include "rangeproof.h"
|
||||
#include "hash_impl.h"
|
||||
#include "pedersen_impl.h"
|
||||
#include "util.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,
|
||||
996, 1005,
|
||||
};
|
||||
|
||||
static void secp256k1_rangeproof_context_init(secp256k1_rangeproof_context *ctx) {
|
||||
ctx->prec = NULL;
|
||||
}
|
||||
|
||||
static void secp256k1_rangeproof_context_build(secp256k1_rangeproof_context *ctx, const secp256k1_callback* cb) {
|
||||
secp256k1_ge *prec;
|
||||
secp256k1_gej *precj;
|
||||
secp256k1_gej gj;
|
||||
secp256k1_gej one;
|
||||
int i, pos;
|
||||
|
||||
if (ctx->prec != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
precj = (secp256k1_gej (*))checked_malloc(cb, sizeof(*precj) * 1005);
|
||||
if (precj == NULL) {
|
||||
return;
|
||||
}
|
||||
prec = (secp256k1_ge (*))checked_malloc(cb, sizeof(*prec) * 1005);
|
||||
if (prec == NULL) {
|
||||
free(precj);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get the generator */
|
||||
secp256k1_gej_set_ge(&one, &secp256k1_ge_const_g2);
|
||||
secp256k1_gej_neg(&one, &one);
|
||||
|
||||
/* compute prec. */
|
||||
pos = 0;
|
||||
for (i = 0; i < 19; i++) {
|
||||
int pmax;
|
||||
pmax = secp256k1_rangeproof_offsets[i + 1];
|
||||
gj = one;
|
||||
while (pos < pmax) {
|
||||
precj[pos] = gj;
|
||||
pos++;
|
||||
secp256k1_gej_double_var(&precj[pos], &gj, NULL);
|
||||
pos++;
|
||||
secp256k1_gej_add_var(&precj[pos], &precj[pos - 1], &gj, NULL);
|
||||
pos++;
|
||||
if (pos < pmax - 1) {
|
||||
secp256k1_gej_double_var(&gj, &precj[pos - 2], NULL);
|
||||
}
|
||||
}
|
||||
if (i < 18) {
|
||||
secp256k1_gej_double_var(&gj, &one, NULL);
|
||||
one = gj;
|
||||
secp256k1_gej_double_var(&gj, &gj, NULL);
|
||||
secp256k1_gej_double_var(&gj, &gj, NULL);
|
||||
secp256k1_gej_add_var(&one, &one, &gj, NULL);
|
||||
}
|
||||
}
|
||||
VERIFY_CHECK(pos == 1005);
|
||||
secp256k1_ge_set_all_gej_var(1005, prec, precj, cb);
|
||||
|
||||
free(precj);
|
||||
|
||||
ctx->prec = (secp256k1_ge_storage (*)[1005])checked_malloc(cb, sizeof(*ctx->prec));
|
||||
if (ctx->prec == NULL) {
|
||||
free(prec);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 1005; i++) {
|
||||
secp256k1_ge_to_storage(&(*ctx->prec)[i], &prec[i]);
|
||||
}
|
||||
free(prec);
|
||||
}
|
||||
|
||||
|
||||
static int secp256k1_rangeproof_context_is_built(const secp256k1_rangeproof_context* ctx) {
|
||||
return ctx->prec != NULL;
|
||||
}
|
||||
|
||||
static void secp256k1_rangeproof_context_clone(secp256k1_rangeproof_context *dst,
|
||||
const secp256k1_rangeproof_context *src, const secp256k1_callback* cb) {
|
||||
if (src->prec == NULL) {
|
||||
dst->prec = NULL;
|
||||
} else {
|
||||
dst->prec = (secp256k1_ge_storage (*)[1005])checked_malloc(cb, sizeof(*dst->prec));
|
||||
memcpy(dst->prec, src->prec, sizeof(*dst->prec));
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_rangeproof_context_clear(secp256k1_rangeproof_context *ctx) {
|
||||
free(ctx->prec);
|
||||
ctx->prec = NULL;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_rangeproof_pub_expand(const secp256k1_rangeproof_context *ctx, secp256k1_gej *pubs,
|
||||
int exp, int *rsizes, int rings) {
|
||||
secp256k1_ge ge;
|
||||
secp256k1_ge_storage *basis;
|
||||
int i;
|
||||
int j;
|
||||
int npub;
|
||||
SECP256K1_INLINE static void secp256k1_rangeproof_pub_expand(secp256k1_gej *pubs,
|
||||
int exp, size_t *rsizes, size_t rings, const secp256k1_ge* genp) {
|
||||
secp256k1_gej base;
|
||||
size_t i;
|
||||
size_t j;
|
||||
size_t npub;
|
||||
VERIFY_CHECK(exp < 19);
|
||||
if (exp < 0) {
|
||||
exp = 0;
|
||||
}
|
||||
basis = &(*ctx->prec)[secp256k1_rangeproof_offsets[exp]];
|
||||
secp256k1_gej_set_ge(&base, genp);
|
||||
secp256k1_gej_neg(&base, &base);
|
||||
while (exp--) {
|
||||
/* Multiplication by 10 */
|
||||
secp256k1_gej tmp;
|
||||
secp256k1_gej_double_var(&tmp, &base, NULL);
|
||||
secp256k1_gej_double_var(&base, &tmp, NULL);
|
||||
secp256k1_gej_double_var(&base, &base, NULL);
|
||||
secp256k1_gej_add_var(&base, &base, &tmp, NULL);
|
||||
}
|
||||
npub = 0;
|
||||
for (i = 0; i < rings; i++) {
|
||||
for (j = 1; j < rsizes[i]; j++) {
|
||||
secp256k1_ge_from_storage(&ge, &basis[i * 3 + j - 1]);
|
||||
secp256k1_gej_add_ge_var(&pubs[npub + j], &pubs[npub], &ge, NULL);
|
||||
secp256k1_gej_add_var(&pubs[npub + j], &pubs[npub + j - 1], &base, NULL);
|
||||
}
|
||||
if (i < rings - 1) {
|
||||
secp256k1_gej_double_var(&base, &base, NULL);
|
||||
secp256k1_gej_double_var(&base, &base, NULL);
|
||||
}
|
||||
npub += rsizes[i];
|
||||
}
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_rangeproof_serialize_point(unsigned char* data, const secp256k1_ge *point) {
|
||||
secp256k1_fe pointx;
|
||||
pointx = point->x;
|
||||
secp256k1_fe_normalize(&pointx);
|
||||
data[0] = !secp256k1_fe_is_quad_var(&point->y);
|
||||
secp256k1_fe_get_b32(data + 1, &pointx);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_rangeproof_genrand(secp256k1_scalar *sec, secp256k1_scalar *s, unsigned char *message,
|
||||
int *rsizes, int rings, const unsigned char *nonce, const unsigned char *commit, const unsigned char *proof, int len) {
|
||||
size_t *rsizes, size_t rings, const unsigned char *nonce, const secp256k1_ge *commit, const unsigned char *proof, size_t len, const secp256k1_ge* genp) {
|
||||
unsigned char tmp[32];
|
||||
unsigned char rngseed[32 + 33 + 10];
|
||||
unsigned char rngseed[32 + 33 + 33 + 10];
|
||||
secp256k1_rfc6979_hmac_sha256_t rng;
|
||||
secp256k1_scalar acc;
|
||||
int overflow;
|
||||
int ret;
|
||||
int i;
|
||||
int j;
|
||||
size_t i;
|
||||
size_t j;
|
||||
int b;
|
||||
int npub;
|
||||
size_t npub;
|
||||
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_rangeproof_serialize_point(rngseed + 32, commit);
|
||||
secp256k1_rangeproof_serialize_point(rngseed + 32 + 33, genp);
|
||||
memcpy(rngseed + 33 + 33 + 32, proof, len);
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, rngseed, 32 + 33 + 33 + len);
|
||||
secp256k1_scalar_clear(&acc);
|
||||
npub = 0;
|
||||
ret = 1;
|
||||
|
|
@ -185,9 +111,9 @@ SECP256K1_INLINE static int secp256k1_rangeproof_genrand(secp256k1_scalar *sec,
|
|||
return ret;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_range_proveparams(uint64_t *v, int *rings, int *rsizes, int *npub, int *secidx, uint64_t *min_value,
|
||||
SECP256K1_INLINE static int secp256k1_range_proveparams(uint64_t *v, size_t *rings, size_t *rsizes, size_t *npub, size_t *secidx, uint64_t *min_value,
|
||||
int *mantissa, uint64_t *scale, int *exp, int *min_bits, uint64_t value) {
|
||||
int i;
|
||||
size_t i;
|
||||
*rings = 1;
|
||||
rsizes[0] = 1;
|
||||
secidx[0] = 0;
|
||||
|
|
@ -221,13 +147,13 @@ SECP256K1_INLINE static int secp256k1_range_proveparams(uint64_t *v, int *rings,
|
|||
*v = value - *min_value;
|
||||
/* If the user has asked for more bits of proof then there is room for in the exponent, reduce the exponent. */
|
||||
v2 = *min_bits ? (UINT64_MAX>>(64-*min_bits)) : 0;
|
||||
for (i = 0; i < *exp && (v2 <= UINT64_MAX / 10); i++) {
|
||||
for (i = 0; (int) i < *exp && (v2 <= UINT64_MAX / 10); i++) {
|
||||
*v /= 10;
|
||||
v2 *= 10;
|
||||
}
|
||||
*exp = i;
|
||||
v2 = *v;
|
||||
for (i = 0; i < *exp; i++) {
|
||||
for (i = 0; (int) i < *exp; i++) {
|
||||
v2 *= 10;
|
||||
*scale *= 10;
|
||||
}
|
||||
|
|
@ -264,9 +190,10 @@ 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* ecmult_ctx,
|
||||
const secp256k1_ecmult_gen_context* ecmult_gen_ctx, const secp256k1_pedersen_context* pedersen_ctx,
|
||||
const secp256k1_rangeproof_context* 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){
|
||||
const secp256k1_ecmult_gen_context* ecmult_gen_ctx,
|
||||
unsigned char *proof, size_t *plen, uint64_t min_value,
|
||||
const secp256k1_ge *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value,
|
||||
const unsigned char *message, size_t msg_len, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_ge* genp){
|
||||
secp256k1_gej pubs[128]; /* Candidate digits for our proof, most inferred. */
|
||||
secp256k1_scalar s[128]; /* Signatures in our proof, most forged. */
|
||||
secp256k1_scalar sec[32]; /* Blinding factors for the correct digits. */
|
||||
|
|
@ -279,13 +206,13 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul
|
|||
uint64_t v;
|
||||
uint64_t scale; /* scale = 10^exp. */
|
||||
int mantissa; /* Number of bits proven in the blinded value. */
|
||||
int rings; /* How many digits will our proof cover. */
|
||||
int rsizes[32]; /* How many possible values there are for each place. */
|
||||
int secidx[32]; /* Which digit is the correct one. */
|
||||
int len; /* Number of bytes used so far. */
|
||||
int i;
|
||||
size_t rings; /* How many digits will our proof cover. */
|
||||
size_t rsizes[32]; /* How many possible values there are for each place. */
|
||||
size_t secidx[32]; /* Which digit is the correct one. */
|
||||
size_t len; /* Number of bytes used so far. */
|
||||
size_t i;
|
||||
int overflow;
|
||||
int npub;
|
||||
size_t npub;
|
||||
len = 0;
|
||||
if (*plen < 65 || min_value > value || min_bits > 64 || min_bits < 0 || exp < -1 || exp > 18) {
|
||||
return 0;
|
||||
|
|
@ -306,18 +233,31 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul
|
|||
}
|
||||
len += 8;
|
||||
}
|
||||
/* Do we have enough room in the proof for the message? Each ring gives us 128 bytes, but the
|
||||
* final ring is used to encode the blinding factor and the value, so we can't use that. (Well,
|
||||
* technically there are 64 bytes available if we avoided the other data, but this is difficult
|
||||
* because it's not always in the same place. */
|
||||
if (msg_len > 0 && msg_len > 128 * (rings - 1)) {
|
||||
return 0;
|
||||
}
|
||||
/* Do we have enough room for the proof? */
|
||||
if (*plen - len < 32 * (npub + rings - 1) + 32 + ((rings+6) >> 3)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_initialize(&sha256_m);
|
||||
secp256k1_sha256_write(&sha256_m, commit, 33);
|
||||
secp256k1_rangeproof_serialize_point(tmp, commit);
|
||||
secp256k1_sha256_write(&sha256_m, tmp, 33);
|
||||
secp256k1_rangeproof_serialize_point(tmp, genp);
|
||||
secp256k1_sha256_write(&sha256_m, tmp, 33);
|
||||
secp256k1_sha256_write(&sha256_m, proof, len);
|
||||
|
||||
memset(prep, 0, 4096);
|
||||
if (message != NULL) {
|
||||
memcpy(prep, message, msg_len);
|
||||
}
|
||||
/* Note, the data corresponding to the blinding factors must be zero. */
|
||||
if (rsizes[rings - 1] > 1) {
|
||||
int idx;
|
||||
size_t idx;
|
||||
/* Value encoding sidechannel. */
|
||||
idx = rsizes[rings - 1] - 1;
|
||||
idx -= secidx[rings - 1] == idx;
|
||||
|
|
@ -328,7 +268,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul
|
|||
}
|
||||
prep[idx] = 128;
|
||||
}
|
||||
if (!secp256k1_rangeproof_genrand(sec, s, prep, rsizes, rings, nonce, commit, proof, len)) {
|
||||
if (!secp256k1_rangeproof_genrand(sec, s, prep, rsizes, rings, nonce, commit, proof, len, genp)) {
|
||||
return 0;
|
||||
}
|
||||
memset(prep, 0, 4096);
|
||||
|
|
@ -357,26 +297,30 @@ 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_pedersen_ecmult(ecmult_gen_ctx, pedersen_ctx, &pubs[npub], &sec[i], ((uint64_t)secidx[i] * scale) << (i*2));
|
||||
secp256k1_pedersen_ecmult(ecmult_gen_ctx, &pubs[npub], &sec[i], ((uint64_t)secidx[i] * scale) << (i*2), genp);
|
||||
if (secp256k1_gej_is_infinity(&pubs[npub])) {
|
||||
return 0;
|
||||
}
|
||||
if (i < rings - 1) {
|
||||
size_t size = 33;
|
||||
unsigned char tmpc[33];
|
||||
secp256k1_ge c;
|
||||
unsigned char quadness;
|
||||
/*OPT: split loop and batch invert.*/
|
||||
/*OPT: do not compute full pubs[npub] in ge form; we only need x */
|
||||
secp256k1_ge_set_gej_var(&c, &pubs[npub]);
|
||||
if(!secp256k1_eckey_pubkey_serialize(&c, tmp, &size, 1)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_write(&sha256_m, tmp, 33);
|
||||
signs[i>>3] |= (tmp[0] == 3) << (i&7);
|
||||
memcpy(&proof[len], &tmp[1], 32);
|
||||
secp256k1_rangeproof_serialize_point(tmpc, &c);
|
||||
quadness = tmpc[0];
|
||||
secp256k1_sha256_write(&sha256_m, tmpc, 33);
|
||||
signs[i>>3] |= quadness << (i&7);
|
||||
memcpy(&proof[len], tmpc + 1, 32);
|
||||
len += 32;
|
||||
}
|
||||
npub += rsizes[i];
|
||||
}
|
||||
secp256k1_rangeproof_pub_expand(rangeproof_ctx, pubs, exp, rsizes, rings);
|
||||
secp256k1_rangeproof_pub_expand(pubs, exp, rsizes, rings, genp);
|
||||
if (extra_commit != NULL) {
|
||||
secp256k1_sha256_write(&sha256_m, extra_commit, extra_commit_len);
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha256_m, tmp);
|
||||
if (!secp256k1_borromean_sign(ecmult_ctx, ecmult_gen_ctx, &proof[len], s, pubs, k, sec, rsizes, secidx, rings, tmp, 32)) {
|
||||
return 0;
|
||||
|
|
@ -418,27 +362,27 @@ SECP256K1_INLINE static void secp256k1_rangeproof_ch32xor(unsigned char *x, cons
|
|||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_rangeproof_rewind_inner(secp256k1_scalar *blind, uint64_t *v,
|
||||
unsigned char *m, int *mlen, secp256k1_scalar *ev, secp256k1_scalar *s,
|
||||
int *rsizes, int rings, const unsigned char *nonce, const unsigned char *commit, const unsigned char *proof, int len) {
|
||||
unsigned char *m, size_t *mlen, secp256k1_scalar *ev, secp256k1_scalar *s,
|
||||
size_t *rsizes, size_t rings, const unsigned char *nonce, const secp256k1_ge *commit, const unsigned char *proof, size_t len, const secp256k1_ge *genp) {
|
||||
secp256k1_scalar s_orig[128];
|
||||
secp256k1_scalar sec[32];
|
||||
secp256k1_scalar stmp;
|
||||
unsigned char prep[4096];
|
||||
unsigned char tmp[32];
|
||||
uint64_t value;
|
||||
int offset;
|
||||
int i;
|
||||
int j;
|
||||
size_t offset;
|
||||
size_t i;
|
||||
size_t j;
|
||||
int b;
|
||||
int skip1;
|
||||
int skip2;
|
||||
int npub;
|
||||
size_t skip1;
|
||||
size_t skip2;
|
||||
size_t npub;
|
||||
npub = ((rings - 1) << 2) + rsizes[rings-1];
|
||||
VERIFY_CHECK(npub <= 128);
|
||||
VERIFY_CHECK(npub >= 1);
|
||||
memset(prep, 0, 4096);
|
||||
/* Reconstruct the provers random values. */
|
||||
secp256k1_rangeproof_genrand(sec, s_orig, prep, rsizes, rings, nonce, commit, proof, len);
|
||||
secp256k1_rangeproof_genrand(sec, s_orig, prep, rsizes, rings, nonce, commit, proof, len, genp);
|
||||
*v = UINT64_MAX;
|
||||
secp256k1_scalar_clear(blind);
|
||||
if (rings == 1 && rsizes[0] == 1) {
|
||||
|
|
@ -454,7 +398,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_rewind_inner(secp256k1_scalar *
|
|||
}
|
||||
npub = (rings - 1) << 2;
|
||||
for (j = 0; j < 2; j++) {
|
||||
int idx;
|
||||
size_t idx;
|
||||
/* Look for a value encoding in the last ring. */
|
||||
idx = npub + rsizes[rings - 1] - 1 - j;
|
||||
secp256k1_scalar_get_b32(tmp, &s[idx]);
|
||||
|
|
@ -503,7 +447,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_rewind_inner(secp256k1_scalar *
|
|||
offset = 0;
|
||||
npub = 0;
|
||||
for (i = 0; i < rings; i++) {
|
||||
int idx;
|
||||
size_t idx;
|
||||
idx = (value >> (i << 1)) & 3;
|
||||
for (j = 0; j < rsizes[i]; j++) {
|
||||
if (npub == skip1 || npub == skip2) {
|
||||
|
|
@ -540,8 +484,8 @@ SECP256K1_INLINE static int secp256k1_rangeproof_rewind_inner(secp256k1_scalar *
|
|||
return 1;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_rangeproof_getheader_impl(int *offset, int *exp, int *mantissa, uint64_t *scale,
|
||||
uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, int plen) {
|
||||
SECP256K1_INLINE static int secp256k1_rangeproof_getheader_impl(size_t *offset, int *exp, int *mantissa, uint64_t *scale,
|
||||
uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, size_t plen) {
|
||||
int i;
|
||||
int has_nz_range;
|
||||
int has_min;
|
||||
|
|
@ -593,28 +537,26 @@ SECP256K1_INLINE static int secp256k1_rangeproof_getheader_impl(int *offset, int
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* 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.*/
|
||||
/* Verifies range proof (len plen) for 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* ecmult_ctx,
|
||||
const secp256k1_ecmult_gen_context* ecmult_gen_ctx,
|
||||
const secp256k1_pedersen_context* pedersen_ctx, const secp256k1_rangeproof_context* 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) {
|
||||
unsigned char *blindout, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce,
|
||||
uint64_t *min_value, uint64_t *max_value, const secp256k1_ge *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_ge* genp) {
|
||||
secp256k1_gej accj;
|
||||
secp256k1_gej pubs[128];
|
||||
secp256k1_ge c;
|
||||
secp256k1_scalar s[128];
|
||||
secp256k1_scalar evalues[128]; /* Challenges, only used during proof rewind. */
|
||||
secp256k1_sha256_t sha256_m;
|
||||
int rsizes[32];
|
||||
size_t rsizes[32];
|
||||
int ret;
|
||||
int i;
|
||||
size_t size;
|
||||
size_t i;
|
||||
int exp;
|
||||
int mantissa;
|
||||
int offset;
|
||||
int rings;
|
||||
size_t offset;
|
||||
size_t rings;
|
||||
int overflow;
|
||||
int npub;
|
||||
size_t npub;
|
||||
int offset_post_header;
|
||||
uint64_t scale;
|
||||
unsigned char signs[31];
|
||||
|
|
@ -645,7 +587,10 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm
|
|||
return 0;
|
||||
}
|
||||
secp256k1_sha256_initialize(&sha256_m);
|
||||
secp256k1_sha256_write(&sha256_m, commit, 33);
|
||||
secp256k1_rangeproof_serialize_point(m, commit);
|
||||
secp256k1_sha256_write(&sha256_m, m, 33);
|
||||
secp256k1_rangeproof_serialize_point(m, genp);
|
||||
secp256k1_sha256_write(&sha256_m, m, 33);
|
||||
secp256k1_sha256_write(&sha256_m, proof, offset);
|
||||
for(i = 0; i < rings - 1; i++) {
|
||||
signs[i] = (proof[offset + ( i>> 3)] & (1 << (i & 7))) != 0;
|
||||
|
|
@ -660,29 +605,30 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm
|
|||
npub = 0;
|
||||
secp256k1_gej_set_infinity(&accj);
|
||||
if (*min_value) {
|
||||
secp256k1_pedersen_ecmult_small(pedersen_ctx, &accj, *min_value);
|
||||
secp256k1_pedersen_ecmult_small(&accj, *min_value, genp);
|
||||
}
|
||||
for(i = 0; i < rings - 1; i++) {
|
||||
memcpy(&m[1], &proof[offset], 32);
|
||||
m[0] = 2 + signs[i];
|
||||
if (!secp256k1_eckey_pubkey_parse(&c, m, 33)) {
|
||||
return 0;
|
||||
secp256k1_fe fe;
|
||||
secp256k1_fe_set_b32(&fe, &proof[offset]);
|
||||
secp256k1_ge_set_xquad(&c, &fe);
|
||||
if (signs[i]) {
|
||||
secp256k1_ge_neg(&c, &c);
|
||||
}
|
||||
secp256k1_sha256_write(&sha256_m, m, 33);
|
||||
/* Not using secp256k1_rangeproof_serialize_point as we almost have it
|
||||
* serialized form already. */
|
||||
secp256k1_sha256_write(&sha256_m, &signs[i], 1);
|
||||
secp256k1_sha256_write(&sha256_m, &proof[offset], 32);
|
||||
secp256k1_gej_set_ge(&pubs[npub], &c);
|
||||
secp256k1_gej_add_ge_var(&accj, &accj, &c, NULL);
|
||||
offset += 32;
|
||||
npub += rsizes[i];
|
||||
}
|
||||
secp256k1_gej_neg(&accj, &accj);
|
||||
if (!secp256k1_eckey_pubkey_parse(&c, commit, 33)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_add_ge_var(&pubs[npub], &accj, &c, NULL);
|
||||
secp256k1_gej_add_ge_var(&pubs[npub], &accj, commit, NULL);
|
||||
if (secp256k1_gej_is_infinity(&pubs[npub])) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_rangeproof_pub_expand(rangeproof_ctx, pubs, exp, rsizes, rings);
|
||||
secp256k1_rangeproof_pub_expand(pubs, exp, rsizes, rings, genp);
|
||||
npub += rsizes[rings - 1];
|
||||
e0 = &proof[offset];
|
||||
offset += 32;
|
||||
|
|
@ -697,30 +643,31 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm
|
|||
/*Extra data found, reject.*/
|
||||
return 0;
|
||||
}
|
||||
if (extra_commit != NULL) {
|
||||
secp256k1_sha256_write(&sha256_m, extra_commit, extra_commit_len);
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha256_m, m);
|
||||
ret = secp256k1_borromean_verify(ecmult_ctx, nonce ? evalues : NULL, e0, s, pubs, rsizes, rings, m, 32);
|
||||
if (ret && nonce) {
|
||||
/* Given the nonce, try rewinding the witness to recover its initial state. */
|
||||
secp256k1_scalar blind;
|
||||
unsigned char commitrec[33];
|
||||
uint64_t vv;
|
||||
if (!ecmult_gen_ctx) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_rangeproof_rewind_inner(&blind, &vv, message_out, outlen, evalues, s, rsizes, rings, nonce, commit, proof, offset_post_header)) {
|
||||
if (!secp256k1_rangeproof_rewind_inner(&blind, &vv, message_out, outlen, evalues, s, rsizes, rings, nonce, commit, proof, offset_post_header, genp)) {
|
||||
return 0;
|
||||
}
|
||||
/* 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_pedersen_ecmult(ecmult_gen_ctx, pedersen_ctx, &accj, &blind, vv);
|
||||
secp256k1_pedersen_ecmult(ecmult_gen_ctx, &accj, &blind, vv, genp);
|
||||
if (secp256k1_gej_is_infinity(&accj)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej(&c, &accj);
|
||||
size = 33;
|
||||
secp256k1_eckey_pubkey_serialize(&c, commitrec, &size, 1);
|
||||
if (size != 33 || memcmp(commitrec, commit, 33) != 0) {
|
||||
secp256k1_gej_neg(&accj, &accj);
|
||||
secp256k1_gej_add_ge_var(&accj, &accj, commit, NULL);
|
||||
if (!secp256k1_gej_is_infinity(&accj)) {
|
||||
return 0;
|
||||
}
|
||||
if (blindout) {
|
||||
|
|
|
|||
|
|
@ -7,11 +7,261 @@
|
|||
#ifndef SECP256K1_MODULE_RANGEPROOF_TESTS
|
||||
#define SECP256K1_MODULE_RANGEPROOF_TESTS
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
#include "testrand.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "include/secp256k1_rangeproof.h"
|
||||
|
||||
void test_pedersen(void) {
|
||||
unsigned char commits[33*19];
|
||||
const unsigned char *cptr[19];
|
||||
static void test_pedersen_api(const secp256k1_context *none, const secp256k1_context *sign, const secp256k1_context *vrfy, const int32_t *ecount) {
|
||||
secp256k1_pedersen_commitment commit;
|
||||
const secp256k1_pedersen_commitment *commit_ptr = &commit;
|
||||
unsigned char blind[32];
|
||||
unsigned char blind_out[32];
|
||||
const unsigned char *blind_ptr = blind;
|
||||
unsigned char *blind_out_ptr = blind_out;
|
||||
uint64_t val = secp256k1_rand32();
|
||||
|
||||
secp256k1_rand256(blind);
|
||||
CHECK(secp256k1_pedersen_commit(none, &commit, blind, val, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 1);
|
||||
CHECK(secp256k1_pedersen_commit(vrfy, &commit, blind, val, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 2);
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 2);
|
||||
|
||||
CHECK(secp256k1_pedersen_commit(sign, NULL, blind, val, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 3);
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, NULL, val, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 4);
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, NULL) == 0);
|
||||
CHECK(*ecount == 5);
|
||||
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 1, 1) != 0);
|
||||
CHECK(*ecount == 5);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, NULL, &blind_ptr, 1, 1) == 0);
|
||||
CHECK(*ecount == 6);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, NULL, 1, 1) == 0);
|
||||
CHECK(*ecount == 7);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 1) == 0);
|
||||
CHECK(*ecount == 8);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 0) != 0);
|
||||
CHECK(*ecount == 8);
|
||||
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, &commit_ptr, 1) != 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, &commit_ptr, 1) == 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 0) == 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, NULL, 0) != 0);
|
||||
CHECK(*ecount == 8);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 1, &commit_ptr, 1) == 0);
|
||||
CHECK(*ecount == 9);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 1) == 0);
|
||||
CHECK(*ecount == 10);
|
||||
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 0) != 0);
|
||||
CHECK(*ecount == 10);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 1) == 0);
|
||||
CHECK(*ecount == 11);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 0, 0) == 0);
|
||||
CHECK(*ecount == 12);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, NULL, &blind_ptr, &blind_out_ptr, 1, 0) == 0);
|
||||
CHECK(*ecount == 13);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, NULL, &blind_out_ptr, 1, 0) == 0);
|
||||
CHECK(*ecount == 14);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, NULL, 1, 0) == 0);
|
||||
CHECK(*ecount == 15);
|
||||
}
|
||||
|
||||
static void test_rangeproof_api(const secp256k1_context *none, const secp256k1_context *sign, const secp256k1_context *vrfy, const secp256k1_context *both, const int32_t *ecount) {
|
||||
unsigned char proof[5134];
|
||||
unsigned char blind[32];
|
||||
secp256k1_pedersen_commitment commit;
|
||||
uint64_t vmin = secp256k1_rand32();
|
||||
uint64_t val = vmin + secp256k1_rand32();
|
||||
size_t len = sizeof(proof);
|
||||
/* we'll switch to dylan thomas for this one */
|
||||
const unsigned char message[68] = "My tears are like the quiet drift / Of petals from some magic rose;";
|
||||
size_t mlen = sizeof(message);
|
||||
const unsigned char ext_commit[72] = "And all my grief flows from the rift / Of unremembered skies and snows.";
|
||||
size_t ext_commit_len = sizeof(ext_commit);
|
||||
|
||||
secp256k1_rand256(blind);
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, val, secp256k1_generator_h));
|
||||
|
||||
CHECK(secp256k1_rangeproof_sign(none, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 1);
|
||||
CHECK(secp256k1_rangeproof_sign(sign, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 2);
|
||||
CHECK(secp256k1_rangeproof_sign(vrfy, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 3);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 3);
|
||||
|
||||
CHECK(secp256k1_rangeproof_sign(both, NULL, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 4);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, NULL, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 5);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, NULL, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 6);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, NULL, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 7);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, NULL, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 8);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, vmin - 1, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 8);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 9);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 9);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 10);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, 0, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 10);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, 0, NULL) == 0);
|
||||
CHECK(*ecount == 11);
|
||||
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
{
|
||||
int exp;
|
||||
int mantissa;
|
||||
uint64_t min_value;
|
||||
uint64_t max_value;
|
||||
CHECK(secp256k1_rangeproof_info(none, &exp, &mantissa, &min_value, &max_value, proof, len) != 0);
|
||||
CHECK(exp == 0);
|
||||
CHECK(((uint64_t) 1 << mantissa) > val - vmin);
|
||||
CHECK(((uint64_t) 1 << (mantissa - 1)) <= val - vmin);
|
||||
CHECK(min_value == vmin);
|
||||
CHECK(max_value >= val);
|
||||
|
||||
CHECK(secp256k1_rangeproof_info(none, NULL, &mantissa, &min_value, &max_value, proof, len) == 0);
|
||||
CHECK(*ecount == 12);
|
||||
CHECK(secp256k1_rangeproof_info(none, &exp, NULL, &min_value, &max_value, proof, len) == 0);
|
||||
CHECK(*ecount == 13);
|
||||
CHECK(secp256k1_rangeproof_info(none, &exp, &mantissa, NULL, &max_value, proof, len) == 0);
|
||||
CHECK(*ecount == 14);
|
||||
CHECK(secp256k1_rangeproof_info(none, &exp, &mantissa, &min_value, NULL, proof, len) == 0);
|
||||
CHECK(*ecount == 15);
|
||||
CHECK(secp256k1_rangeproof_info(none, &exp, &mantissa, &min_value, &max_value, NULL, len) == 0);
|
||||
CHECK(*ecount == 16);
|
||||
CHECK(secp256k1_rangeproof_info(none, &exp, &mantissa, &min_value, &max_value, proof, 0) == 0);
|
||||
CHECK(*ecount == 16);
|
||||
}
|
||||
{
|
||||
uint64_t min_value;
|
||||
uint64_t max_value;
|
||||
CHECK(secp256k1_rangeproof_verify(none, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 17);
|
||||
CHECK(secp256k1_rangeproof_verify(sign, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 18);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 18);
|
||||
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, NULL, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 19);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, NULL, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 20);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, NULL, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 21);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, NULL, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 22);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, 0, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 22);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, NULL, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 23);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, NULL, 0, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 23);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, NULL, 0, NULL) == 0);
|
||||
CHECK(*ecount == 24);
|
||||
}
|
||||
{
|
||||
unsigned char blind_out[32];
|
||||
unsigned char message_out[68];
|
||||
uint64_t value_out;
|
||||
uint64_t min_value;
|
||||
uint64_t max_value;
|
||||
size_t message_len = sizeof(message_out);
|
||||
|
||||
CHECK(secp256k1_rangeproof_rewind(none, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 25);
|
||||
CHECK(secp256k1_rangeproof_rewind(sign, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 26);
|
||||
CHECK(secp256k1_rangeproof_rewind(vrfy, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 27);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 27);
|
||||
|
||||
CHECK(min_value == vmin);
|
||||
CHECK(max_value >= val);
|
||||
CHECK(value_out == val);
|
||||
CHECK(message_len == sizeof(message_out));
|
||||
CHECK(memcmp(message, message_out, sizeof(message_out)) == 0);
|
||||
|
||||
CHECK(secp256k1_rangeproof_rewind(both, NULL, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 27); /* blindout may be NULL */
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, NULL, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 27); /* valueout may be NULL */
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 28);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 28);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, NULL, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 29);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, NULL, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 30);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, NULL, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 31);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, NULL, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 32);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, NULL, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 33);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, 0, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 33);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 34);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, 0, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 34);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, 0, NULL) == 0);
|
||||
CHECK(*ecount == 35);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_api(void) {
|
||||
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
|
||||
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
int32_t ecount;
|
||||
int i;
|
||||
|
||||
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ecount = 0;
|
||||
test_pedersen_api(none, sign, vrfy, &ecount);
|
||||
ecount = 0;
|
||||
test_rangeproof_api(none, sign, vrfy, both, &ecount);
|
||||
}
|
||||
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(vrfy);
|
||||
secp256k1_context_destroy(both);
|
||||
}
|
||||
|
||||
static void test_pedersen(void) {
|
||||
secp256k1_pedersen_commitment commits[19];
|
||||
const secp256k1_pedersen_commitment *cptr[19];
|
||||
unsigned char blinds[32*19];
|
||||
const unsigned char *bptr[19];
|
||||
secp256k1_scalar s;
|
||||
|
|
@ -25,7 +275,7 @@ void test_pedersen(void) {
|
|||
outputs = (secp256k1_rand32() & 7) + 2;
|
||||
total = inputs + outputs;
|
||||
for (i = 0; i < 19; i++) {
|
||||
cptr[i] = &commits[i * 33];
|
||||
cptr[i] = &commits[i];
|
||||
bptr[i] = &blinds[i * 32];
|
||||
}
|
||||
totalv = 0;
|
||||
|
|
@ -33,33 +283,25 @@ void test_pedersen(void) {
|
|||
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 < outputs - 1; i++) {
|
||||
values[i + inputs] = secp256k1_rands64(0, totalv);
|
||||
totalv -= values[i + inputs];
|
||||
}
|
||||
values[total - 1] = totalv;
|
||||
|
||||
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_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
|
||||
}
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs));
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[inputs], outputs, cptr, inputs));
|
||||
if (inputs > 0 && values[0] > 0) {
|
||||
CHECK(!secp256k1_pedersen_verify_tally(ctx, cptr, inputs - 1, &cptr[inputs], outputs));
|
||||
}
|
||||
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);
|
||||
|
|
@ -68,17 +310,13 @@ void test_pedersen(void) {
|
|||
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_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
|
||||
}
|
||||
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));
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1));
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1));
|
||||
}
|
||||
|
||||
void test_borromean(void) {
|
||||
static void test_borromean(void) {
|
||||
unsigned char e0[32];
|
||||
secp256k1_scalar s[64];
|
||||
secp256k1_gej pubs[64];
|
||||
|
|
@ -87,11 +325,11 @@ void test_borromean(void) {
|
|||
secp256k1_ge ge;
|
||||
secp256k1_scalar one;
|
||||
unsigned char m[32];
|
||||
int rsizes[8];
|
||||
int secidx[8];
|
||||
int nrings;
|
||||
int i;
|
||||
int j;
|
||||
size_t rsizes[8];
|
||||
size_t secidx[8];
|
||||
size_t nrings;
|
||||
size_t i;
|
||||
size_t j;
|
||||
int c;
|
||||
secp256k1_rand256_test(m);
|
||||
nrings = 1 + (secp256k1_rand32()&7);
|
||||
|
|
@ -143,35 +381,60 @@ void test_borromean(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void test_rangeproof(void) {
|
||||
static 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];
|
||||
secp256k1_pedersen_commitment commit;
|
||||
secp256k1_pedersen_commitment commit2;
|
||||
unsigned char proof[5134];
|
||||
unsigned char blind[32];
|
||||
unsigned char blindout[32];
|
||||
unsigned char message[4096];
|
||||
int mlen;
|
||||
size_t mlen;
|
||||
uint64_t v;
|
||||
uint64_t vout;
|
||||
uint64_t vmin;
|
||||
uint64_t minv;
|
||||
uint64_t maxv;
|
||||
int len;
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
size_t len;
|
||||
size_t i;
|
||||
size_t j;
|
||||
size_t k;
|
||||
/* Short message is a Simone de Beauvoir quote */
|
||||
const unsigned char message_short[120] = "When I see my own likeness in the depths of someone else's consciousness, I always experience a moment of panic.";
|
||||
/* Long message is 0xA5 with a bunch of this quote in the middle */
|
||||
unsigned char message_long[3968];
|
||||
memset(message_long, 0xa5, sizeof(message_long));
|
||||
for (i = 1200; i < 3600; i += 120) {
|
||||
memcpy(&message_long[i], message_short, sizeof(message_short));
|
||||
}
|
||||
|
||||
secp256k1_rand256(blind);
|
||||
for (i = 0; i < 11; i++) {
|
||||
v = testvs[i];
|
||||
CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v));
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
|
||||
for (vmin = 0; vmin < (i<9 && i > 0 ? 2 : 1); vmin++) {
|
||||
const unsigned char *input_message = NULL;
|
||||
size_t input_message_len = 0;
|
||||
/* vmin is always either 0 or 1; if it is 1, then we have no room for a message.
|
||||
* If it's 0, we use "minimum encoding" and only have room for a small message when
|
||||
* `testvs[i]` is >= 4; for a large message when it's >= 2^32. */
|
||||
if (vmin == 0 && i > 2) {
|
||||
input_message = message_short;
|
||||
input_message_len = sizeof(message_short);
|
||||
}
|
||||
if (vmin == 0 && i > 7) {
|
||||
input_message = message_long;
|
||||
input_message_len = sizeof(message_long);
|
||||
}
|
||||
len = 5134;
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, commit, blind, commit, 0, 0, v));
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, 0, 0, v, input_message, input_message_len, NULL, 0, secp256k1_generator_h));
|
||||
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(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
if (input_message != NULL) {
|
||||
CHECK(memcmp(message, input_message, input_message_len) == 0);
|
||||
}
|
||||
for (j = input_message_len; j < mlen; j++) {
|
||||
CHECK(message[j] == 0);
|
||||
}
|
||||
CHECK(mlen <= 4096);
|
||||
|
|
@ -180,9 +443,21 @@ void test_rangeproof(void) {
|
|||
CHECK(minv <= v);
|
||||
CHECK(maxv >= v);
|
||||
len = 5134;
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v, commit, blind, commit, -1, 64, v));
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, -1, 64, v, NULL, 0, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(len <= 73);
|
||||
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit, &minv, &maxv, commit, proof, len));
|
||||
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(memcmp(blindout, blind, 32) == 0);
|
||||
CHECK(vout == v);
|
||||
CHECK(minv == v);
|
||||
CHECK(maxv == v);
|
||||
|
||||
/* Check with a committed message */
|
||||
len = 5134;
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, -1, 64, v, NULL, 0, message_short, sizeof(message_short), secp256k1_generator_h));
|
||||
CHECK(len <= 73);
|
||||
CHECK(!secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(!secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, message_long, sizeof(message_long), secp256k1_generator_h));
|
||||
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, message_short, sizeof(message_short), secp256k1_generator_h));
|
||||
CHECK(memcmp(blindout, blind, 32) == 0);
|
||||
CHECK(vout == v);
|
||||
CHECK(minv == v);
|
||||
|
|
@ -191,34 +466,36 @@ void test_rangeproof(void) {
|
|||
}
|
||||
secp256k1_rand256(blind);
|
||||
v = INT64_MAX - 1;
|
||||
CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v));
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
|
||||
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(secp256k1_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, i, 0, v, NULL, 0, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(len <= 5134);
|
||||
CHECK(minv <= v);
|
||||
CHECK(maxv >= v);
|
||||
/* Make sure it fails when validating with a committed message */
|
||||
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, message_short, sizeof(message_short), secp256k1_generator_h));
|
||||
}
|
||||
secp256k1_rand256(blind);
|
||||
{
|
||||
/*Malleability test.*/
|
||||
v = secp256k1_rands64(0, 255);
|
||||
CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v));
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
|
||||
len = 5134;
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, commit, blind, commit, 0, 3, v));
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, 0, 3, v, NULL, 0, NULL, 0, secp256k1_generator_h));
|
||||
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));
|
||||
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
proof[i >> 3] ^= 1 << (i & 7);
|
||||
}
|
||||
CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit, proof, len));
|
||||
CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(minv <= v);
|
||||
CHECK(maxv >= v);
|
||||
}
|
||||
memcpy(commit2, commit, 33);
|
||||
for (i = 0; i < 10 * count; i++) {
|
||||
memcpy(&commit2, &commit, sizeof(commit));
|
||||
for (i = 0; i < 10 * (size_t) count; i++) {
|
||||
int exp;
|
||||
int min_bits;
|
||||
v = secp256k1_rands64(0, UINT64_MAX >> (secp256k1_rand32()&63));
|
||||
|
|
@ -227,7 +504,7 @@ void test_rangeproof(void) {
|
|||
vmin = secp256k1_rands64(0, v);
|
||||
}
|
||||
secp256k1_rand256(blind);
|
||||
CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v));
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
|
||||
len = 5134;
|
||||
exp = (int)secp256k1_rands64(0,18)-(int)secp256k1_rands64(0,18);
|
||||
if (exp < 0) {
|
||||
|
|
@ -237,10 +514,10 @@ void test_rangeproof(void) {
|
|||
if (min_bits < 0) {
|
||||
min_bits = -min_bits;
|
||||
}
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, commit, blind, commit, exp, min_bits, v));
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, exp, min_bits, v, NULL, 0, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(len <= 5134);
|
||||
mlen = 4096;
|
||||
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit, &minv, &maxv, commit, proof, len));
|
||||
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
for (j = 0; j < mlen; j++) {
|
||||
CHECK(message[j] == 0);
|
||||
}
|
||||
|
|
@ -249,8 +526,8 @@ void test_rangeproof(void) {
|
|||
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);
|
||||
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
memcpy(&commit2, &commit, sizeof(commit));
|
||||
}
|
||||
for (j = 0; j < 10; j++) {
|
||||
for (i = 0; i < 96; i++) {
|
||||
|
|
@ -258,17 +535,78 @@ void test_rangeproof(void) {
|
|||
}
|
||||
for (k = 0; k < 128; k++) {
|
||||
len = k;
|
||||
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit2, proof, len));
|
||||
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit2, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
}
|
||||
len = secp256k1_rands64(0, 3072);
|
||||
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit2, proof, len));
|
||||
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit2, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_N_GENS 30
|
||||
void test_multiple_generators(void) {
|
||||
const size_t n_inputs = (secp256k1_rand32() % (MAX_N_GENS / 2)) + 1;
|
||||
const size_t n_outputs = (secp256k1_rand32() % (MAX_N_GENS / 2)) + 1;
|
||||
const size_t n_generators = n_inputs + n_outputs;
|
||||
unsigned char *generator_blind[MAX_N_GENS];
|
||||
unsigned char *pedersen_blind[MAX_N_GENS];
|
||||
secp256k1_generator generator[MAX_N_GENS];
|
||||
secp256k1_pedersen_commitment commit[MAX_N_GENS];
|
||||
const secp256k1_pedersen_commitment *commit_ptr[MAX_N_GENS];
|
||||
size_t i;
|
||||
int64_t total_value;
|
||||
uint64_t value[MAX_N_GENS];
|
||||
|
||||
secp256k1_scalar s;
|
||||
|
||||
unsigned char generator_seed[32];
|
||||
random_scalar_order(&s);
|
||||
secp256k1_scalar_get_b32(generator_seed, &s);
|
||||
/* Create all the needed generators */
|
||||
for (i = 0; i < n_generators; i++) {
|
||||
generator_blind[i] = (unsigned char*) malloc(32);
|
||||
pedersen_blind[i] = (unsigned char*) malloc(32);
|
||||
|
||||
random_scalar_order(&s);
|
||||
secp256k1_scalar_get_b32(generator_blind[i], &s);
|
||||
random_scalar_order(&s);
|
||||
secp256k1_scalar_get_b32(pedersen_blind[i], &s);
|
||||
|
||||
CHECK(secp256k1_generator_generate_blinded(ctx, &generator[i], generator_seed, generator_blind[i]));
|
||||
|
||||
commit_ptr[i] = &commit[i];
|
||||
}
|
||||
|
||||
/* Compute all the values -- can be positive or negative */
|
||||
total_value = 0;
|
||||
for (i = 0; i < n_outputs; i++) {
|
||||
value[n_inputs + i] = secp256k1_rands64(0, INT64_MAX - total_value);
|
||||
total_value += value[n_inputs + i];
|
||||
}
|
||||
for (i = 0; i < n_inputs - 1; i++) {
|
||||
value[i] = secp256k1_rands64(0, total_value);
|
||||
total_value -= value[i];
|
||||
}
|
||||
value[i] = total_value;
|
||||
|
||||
/* Correct for blinding factors and do the commitments */
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(ctx, value, (const unsigned char * const *) generator_blind, pedersen_blind, n_generators, n_inputs));
|
||||
for (i = 0; i < n_generators; i++) {
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commit[i], pedersen_blind[i], value[i], &generator[i]));
|
||||
}
|
||||
|
||||
/* Verify */
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &commit_ptr[0], n_inputs, &commit_ptr[n_inputs], n_outputs));
|
||||
|
||||
/* Cleanup */
|
||||
for (i = 0; i < n_generators; i++) {
|
||||
free(generator_blind[i]);
|
||||
free(pedersen_blind[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void run_rangeproof_tests(void) {
|
||||
int i;
|
||||
secp256k1_pedersen_context_initialize(ctx);
|
||||
secp256k1_rangeproof_context_initialize(ctx);
|
||||
test_api();
|
||||
for (i = 0; i < 10*count; i++) {
|
||||
test_pedersen();
|
||||
}
|
||||
|
|
@ -276,6 +614,7 @@ void run_rangeproof_tests(void) {
|
|||
test_borromean();
|
||||
}
|
||||
test_rangeproof();
|
||||
test_multiple_generators();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubk
|
|||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature);
|
||||
ARG_CHECK(recid >= 0 && recid < 4);
|
||||
VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */
|
||||
secp256k1_scalar_set_b32(&m, msg32, NULL);
|
||||
if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) {
|
||||
secp256k1_pubkey_save(pubkey, &q);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,146 @@
|
|||
#ifndef _SECP256K1_MODULE_RECOVERY_TESTS_
|
||||
#define _SECP256K1_MODULE_RECOVERY_TESTS_
|
||||
|
||||
static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
|
||||
(void) msg32;
|
||||
(void) key32;
|
||||
(void) algo16;
|
||||
(void) data;
|
||||
|
||||
/* On the first run, return 0 to force a second run */
|
||||
if (counter == 0) {
|
||||
memset(nonce32, 0, 32);
|
||||
return 1;
|
||||
}
|
||||
/* On the second run, return an overflow to force a third run */
|
||||
if (counter == 1) {
|
||||
memset(nonce32, 0xff, 32);
|
||||
return 1;
|
||||
}
|
||||
/* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */
|
||||
memset(nonce32, 1, 32);
|
||||
return secp256k1_rand_bits(1);
|
||||
}
|
||||
|
||||
void test_ecdsa_recovery_api(void) {
|
||||
/* Setup contexts that just count errors */
|
||||
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
|
||||
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_pubkey recpubkey;
|
||||
secp256k1_ecdsa_signature normal_sig;
|
||||
secp256k1_ecdsa_recoverable_signature recsig;
|
||||
unsigned char privkey[32] = { 1 };
|
||||
unsigned char message[32] = { 2 };
|
||||
int32_t ecount = 0;
|
||||
int recid = 0;
|
||||
unsigned char sig[74];
|
||||
unsigned char zero_privkey[32] = { 0 };
|
||||
unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
|
||||
|
||||
/* Construct and verify corresponding public key. */
|
||||
CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
|
||||
|
||||
/* Check bad contexts and NULLs for signing */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0);
|
||||
CHECK(ecount == 5);
|
||||
/* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */
|
||||
secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL);
|
||||
CHECK(ecount == 5);
|
||||
/* These will all fail, but not in ARG_CHECK way */
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0);
|
||||
/* This one will succeed. */
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
|
||||
CHECK(ecount == 5);
|
||||
|
||||
/* Check signing with a goofy nonce function */
|
||||
|
||||
/* Check bad contexts and NULLs for recovery */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_ecdsa_recover(none, &recpubkey, &recsig, message) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdsa_recover(sign, &recpubkey, &recsig, message) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, message) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_recover(both, NULL, &recsig, message) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_ecdsa_recover(both, &recpubkey, NULL, message) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0);
|
||||
CHECK(ecount == 5);
|
||||
|
||||
/* Check NULLs for conversion */
|
||||
CHECK(secp256k1_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1);
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1);
|
||||
|
||||
/* Check NULLs for de/serialization */
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1);
|
||||
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0);
|
||||
CHECK(ecount == 6);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0);
|
||||
CHECK(ecount == 7);
|
||||
/* overflow in signature will fail but not affect ecount */
|
||||
memcpy(sig, over_privkey, 32);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0);
|
||||
CHECK(ecount == 7);
|
||||
|
||||
/* cleanup */
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(vrfy);
|
||||
secp256k1_context_destroy(both);
|
||||
}
|
||||
|
||||
void test_ecdsa_recovery_end_to_end(void) {
|
||||
unsigned char extra[32] = {0x00};
|
||||
unsigned char privkey[32];
|
||||
|
|
@ -241,6 +381,9 @@ void test_ecdsa_recovery_edge_cases(void) {
|
|||
|
||||
void run_recovery_tests(void) {
|
||||
int i;
|
||||
for (i = 0; i < count; i++) {
|
||||
test_ecdsa_recovery_api();
|
||||
}
|
||||
for (i = 0; i < 64*count; i++) {
|
||||
test_ecdsa_recovery_end_to_end();
|
||||
}
|
||||
|
|
|
|||
6
src/secp256k1/src/modules/surjection/Makefile.am.include
Normal file
6
src/secp256k1/src/modules/surjection/Makefile.am.include
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
include_HEADERS += include/secp256k1_surjectionproof.h
|
||||
noinst_HEADERS += src/modules/surjection/main_impl.h
|
||||
noinst_HEADERS += src/modules/surjection/surjection.h
|
||||
noinst_HEADERS += src/modules/surjection/surjection_impl.h
|
||||
noinst_HEADERS += src/modules/surjection/tests_impl.h
|
||||
|
||||
338
src/secp256k1/src/modules/surjection/main_impl.h
Normal file
338
src/secp256k1/src/modules/surjection/main_impl.h
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2016 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
#ifndef SECP256K1_MODULE_SURJECTION_MAIN
|
||||
#define SECP256K1_MODULE_SURJECTION_MAIN
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "modules/rangeproof/borromean.h"
|
||||
#include "modules/surjection/surjection_impl.h"
|
||||
#include "hash.h"
|
||||
#include "include/secp256k1_rangeproof.h"
|
||||
#include "include/secp256k1_surjectionproof.h"
|
||||
|
||||
static size_t secp256k1_count_bits_set(const unsigned char* data, size_t count) {
|
||||
size_t ret = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < count; i++) {
|
||||
#ifdef HAVE_BUILTIN_POPCOUNT
|
||||
ret += __builtin_popcount(data[i]);
|
||||
#else
|
||||
ret += !!(data[i] & 0x1);
|
||||
ret += !!(data[i] & 0x2);
|
||||
ret += !!(data[i] & 0x4);
|
||||
ret += !!(data[i] & 0x8);
|
||||
ret += !!(data[i] & 0x10);
|
||||
ret += !!(data[i] & 0x20);
|
||||
ret += !!(data[i] & 0x40);
|
||||
ret += !!(data[i] & 0x80);
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_surjectionproof_parse(const secp256k1_context* ctx, secp256k1_surjectionproof *proof, const unsigned char *input, size_t inputlen) {
|
||||
size_t n_inputs;
|
||||
size_t signature_len;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
ARG_CHECK(input != NULL);
|
||||
(void) ctx;
|
||||
|
||||
if (inputlen < 2) {
|
||||
return 0;
|
||||
}
|
||||
n_inputs = ((size_t) (input[1] << 8)) + input[0];
|
||||
if (n_inputs > SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) {
|
||||
return 0;
|
||||
}
|
||||
if (inputlen < 2 + (n_inputs + 7) / 8) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
signature_len = 32 * (1 + secp256k1_count_bits_set(&input[2], (n_inputs + 7) / 8));
|
||||
if (inputlen < 2 + (n_inputs + 7) / 8 + signature_len) {
|
||||
return 0;
|
||||
}
|
||||
proof->n_inputs = n_inputs;
|
||||
memcpy(proof->used_inputs, &input[2], (n_inputs + 7) / 8);
|
||||
memcpy(proof->data, &input[2 + (n_inputs + 7) / 8], signature_len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_surjectionproof_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_surjectionproof *proof) {
|
||||
size_t signature_len;
|
||||
size_t serialized_len;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output != NULL);
|
||||
ARG_CHECK(outputlen != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
(void) ctx;
|
||||
|
||||
signature_len = 32 * (1 + secp256k1_count_bits_set(proof->used_inputs, (proof->n_inputs + 7) / 8));
|
||||
serialized_len = 2 + (proof->n_inputs + 7) / 8 + signature_len;
|
||||
if (*outputlen < serialized_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
output[0] = proof->n_inputs % 0x100;
|
||||
output[1] = proof->n_inputs / 0x100;
|
||||
memcpy(&output[2], proof->used_inputs, (proof->n_inputs + 7) / 8);
|
||||
memcpy(&output[2 + (proof->n_inputs + 7) / 8], proof->data, signature_len);
|
||||
*outputlen = serialized_len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t secp256k1_surjectionproof_n_total_inputs(const secp256k1_context* ctx, const secp256k1_surjectionproof* proof) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
(void) ctx;
|
||||
return proof->n_inputs;
|
||||
}
|
||||
|
||||
size_t secp256k1_surjectionproof_n_used_inputs(const secp256k1_context* ctx, const secp256k1_surjectionproof* proof) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
(void) ctx;
|
||||
return secp256k1_count_bits_set(proof->used_inputs, (proof->n_inputs + 7) / 8);
|
||||
}
|
||||
|
||||
size_t secp256k1_surjectionproof_serialized_size(const secp256k1_context* ctx, const secp256k1_surjectionproof* proof) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
return 2 + (proof->n_inputs + 7) / 8 + 32 * (1 + secp256k1_surjectionproof_n_used_inputs(ctx, proof));
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
unsigned char state[32];
|
||||
size_t state_i;
|
||||
} secp256k1_surjectionproof_csprng;
|
||||
|
||||
static void secp256k1_surjectionproof_csprng_init(secp256k1_surjectionproof_csprng *csprng, const unsigned char* state) {
|
||||
memcpy(csprng->state, state, 32);
|
||||
csprng->state_i = 0;
|
||||
}
|
||||
|
||||
static size_t secp256k1_surjectionproof_csprng_next(secp256k1_surjectionproof_csprng *csprng, size_t rand_max) {
|
||||
/* The number of random bytes to read for each random sample */
|
||||
const size_t increment = rand_max > 256 ? 2 : 1;
|
||||
/* The maximum value expressable by the number of random bytes we read */
|
||||
const size_t selection_range = rand_max > 256 ? 0xffff : 0xff;
|
||||
/* The largest multiple of rand_max that fits within selection_range */
|
||||
const size_t limit = ((selection_range + 1) / rand_max) * rand_max;
|
||||
|
||||
while (1) {
|
||||
size_t val;
|
||||
if (csprng->state_i + increment >= 32) {
|
||||
secp256k1_sha256_t sha;
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, csprng->state, 32);
|
||||
secp256k1_sha256_finalize(&sha, csprng->state);
|
||||
csprng->state_i = 0;
|
||||
}
|
||||
val = csprng->state[csprng->state_i];
|
||||
if (increment > 1) {
|
||||
val = (val << 8) + csprng->state[csprng->state_i + 1];
|
||||
}
|
||||
csprng->state_i += increment;
|
||||
/* Accept only values below our limit. Values equal to or above the limit are
|
||||
* biased because they comprise only a subset of the range (0, rand_max - 1) */
|
||||
if (val < limit) {
|
||||
return val % rand_max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int secp256k1_surjectionproof_initialize(const secp256k1_context* ctx, secp256k1_surjectionproof* proof, size_t *input_index, const secp256k1_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, const secp256k1_fixed_asset_tag* fixed_output_tag, const size_t n_max_iterations, const unsigned char *random_seed32) {
|
||||
secp256k1_surjectionproof_csprng csprng;
|
||||
size_t n_iterations = 0;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
ARG_CHECK(input_index != NULL);
|
||||
ARG_CHECK(fixed_input_tags != NULL);
|
||||
ARG_CHECK(fixed_output_tag != NULL);
|
||||
ARG_CHECK(random_seed32 != NULL);
|
||||
ARG_CHECK(n_input_tags <= SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS);
|
||||
ARG_CHECK(n_input_tags_to_use <= n_input_tags);
|
||||
(void) ctx;
|
||||
|
||||
secp256k1_surjectionproof_csprng_init(&csprng, random_seed32);
|
||||
memset(proof->data, 0, sizeof(proof->data));
|
||||
proof->n_inputs = n_input_tags;
|
||||
|
||||
while (1) {
|
||||
int has_output_tag = 0;
|
||||
size_t i;
|
||||
|
||||
/* obtain a random set of indices */
|
||||
memset(proof->used_inputs, 0, sizeof(proof->used_inputs));
|
||||
for (i = 0; i < n_input_tags_to_use; i++) {
|
||||
while (1) {
|
||||
size_t next_input_index;
|
||||
next_input_index = secp256k1_surjectionproof_csprng_next(&csprng, n_input_tags);
|
||||
if (memcmp(&fixed_input_tags[next_input_index], fixed_output_tag, sizeof(*fixed_output_tag)) == 0) {
|
||||
*input_index = next_input_index;
|
||||
has_output_tag = 1;
|
||||
}
|
||||
|
||||
if (!(proof->used_inputs[next_input_index / 8] & (1 << (next_input_index % 8)))) {
|
||||
proof->used_inputs[next_input_index / 8] |= (1 << (next_input_index % 8));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we succeeded */
|
||||
n_iterations++;
|
||||
if (has_output_tag) {
|
||||
#ifdef VERIFY
|
||||
proof->initialized = 1;
|
||||
#endif
|
||||
return n_iterations;
|
||||
}
|
||||
if (n_iterations >= n_max_iterations) {
|
||||
#ifdef VERIFY
|
||||
proof->initialized = 0;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_surjectionproof* proof, const secp256k1_generator* ephemeral_input_tags, size_t n_ephemeral_input_tags, const secp256k1_generator* ephemeral_output_tag, size_t input_index, const unsigned char *input_blinding_key, const unsigned char *output_blinding_key) {
|
||||
secp256k1_scalar blinding_key;
|
||||
secp256k1_scalar tmps;
|
||||
secp256k1_scalar nonce;
|
||||
int overflow = 0;
|
||||
size_t rsizes[1]; /* array needed for borromean sig API */
|
||||
size_t indices[1]; /* array needed for borromean sig API */
|
||||
size_t i;
|
||||
size_t n_total_pubkeys;
|
||||
size_t n_used_pubkeys;
|
||||
size_t ring_input_index = 0;
|
||||
secp256k1_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
||||
secp256k1_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
||||
secp256k1_ge inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
||||
secp256k1_ge output;
|
||||
unsigned char msg32[32];
|
||||
|
||||
VERIFY_CHECK(ctx != 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(proof != NULL);
|
||||
ARG_CHECK(ephemeral_input_tags != NULL);
|
||||
ARG_CHECK(ephemeral_output_tag != NULL);
|
||||
ARG_CHECK(input_blinding_key != NULL);
|
||||
ARG_CHECK(output_blinding_key != NULL);
|
||||
#ifdef VERIFY
|
||||
CHECK(proof->initialized == 1);
|
||||
#endif
|
||||
|
||||
/* Compute secret key */
|
||||
secp256k1_scalar_set_b32(&tmps, input_blinding_key, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&blinding_key, output_blinding_key, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
/* The only time the input may equal the output is if neither one was blinded in the first place,
|
||||
* i.e. both blinding keys are zero. Otherwise this is a privacy leak. */
|
||||
if (secp256k1_scalar_eq(&tmps, &blinding_key) && !secp256k1_scalar_is_zero(&blinding_key)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_negate(&tmps, &tmps);
|
||||
secp256k1_scalar_add(&blinding_key, &blinding_key, &tmps);
|
||||
|
||||
/* Compute public keys */
|
||||
n_total_pubkeys = secp256k1_surjectionproof_n_total_inputs(ctx, proof);
|
||||
n_used_pubkeys = secp256k1_surjectionproof_n_used_inputs(ctx, proof);
|
||||
if (n_used_pubkeys > n_total_pubkeys || n_total_pubkeys != n_ephemeral_input_tags) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_generator_load(&output, ephemeral_output_tag);
|
||||
for (i = 0; i < n_total_pubkeys; i++) {
|
||||
secp256k1_generator_load(&inputs[i], &ephemeral_input_tags[i]);
|
||||
}
|
||||
|
||||
secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, inputs, n_total_pubkeys, proof->used_inputs, &output, input_index, &ring_input_index);
|
||||
|
||||
/* Produce signature */
|
||||
rsizes[0] = (int) n_used_pubkeys;
|
||||
indices[0] = (int) ring_input_index;
|
||||
secp256k1_surjection_genmessage(msg32, inputs, n_total_pubkeys, &output);
|
||||
if (secp256k1_surjection_genrand(borromean_s, n_used_pubkeys, &blinding_key) == 0) {
|
||||
return 0;
|
||||
}
|
||||
/* Borromean sign will overwrite one of the s values we just generated, so use
|
||||
* it as a nonce instead. This avoids extra random generation and also is an
|
||||
* homage to the rangeproof code which does this very cleverly to encode messages. */
|
||||
nonce = borromean_s[ring_input_index];
|
||||
secp256k1_scalar_clear(&borromean_s[ring_input_index]);
|
||||
if (secp256k1_borromean_sign(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, &proof->data[0], borromean_s, ring_pubkeys, &nonce, &blinding_key, rsizes, indices, 1, msg32, 32) == 0) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < n_used_pubkeys; i++) {
|
||||
secp256k1_scalar_get_b32(&proof->data[32 + 32 * i], &borromean_s[i]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_surjectionproof_verify(const secp256k1_context* ctx, const secp256k1_surjectionproof* proof, const secp256k1_generator* ephemeral_input_tags, size_t n_ephemeral_input_tags, const secp256k1_generator* ephemeral_output_tag) {
|
||||
size_t rsizes[1]; /* array needed for borromean sig API */
|
||||
size_t i;
|
||||
size_t n_total_pubkeys;
|
||||
size_t n_used_pubkeys;
|
||||
secp256k1_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
||||
secp256k1_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
||||
secp256k1_ge inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
||||
secp256k1_ge output;
|
||||
unsigned char msg32[32];
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(proof != NULL);
|
||||
ARG_CHECK(ephemeral_input_tags != NULL);
|
||||
ARG_CHECK(ephemeral_output_tag != NULL);
|
||||
|
||||
/* Compute public keys */
|
||||
n_total_pubkeys = secp256k1_surjectionproof_n_total_inputs(ctx, proof);
|
||||
n_used_pubkeys = secp256k1_surjectionproof_n_used_inputs(ctx, proof);
|
||||
if (n_used_pubkeys == 0 || n_used_pubkeys > n_total_pubkeys || n_total_pubkeys != n_ephemeral_input_tags) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_generator_load(&output, ephemeral_output_tag);
|
||||
for (i = 0; i < n_total_pubkeys; i++) {
|
||||
secp256k1_generator_load(&inputs[i], &ephemeral_input_tags[i]);
|
||||
}
|
||||
|
||||
if (secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, inputs, n_total_pubkeys, proof->used_inputs, &output, 0, NULL) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Verify signature */
|
||||
rsizes[0] = (int) n_used_pubkeys;
|
||||
for (i = 0; i < n_used_pubkeys; i++) {
|
||||
int overflow = 0;
|
||||
secp256k1_scalar_set_b32(&borromean_s[i], &proof->data[32 + 32 * i], &overflow);
|
||||
if (overflow == 1) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
secp256k1_surjection_genmessage(msg32, inputs, n_total_pubkeys, &output);
|
||||
return secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, &proof->data[0], borromean_s, ring_pubkeys, rsizes, 1, msg32, 32);
|
||||
}
|
||||
|
||||
#endif
|
||||
19
src/secp256k1/src/modules/surjection/surjection.h
Normal file
19
src/secp256k1/src/modules/surjection/surjection.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2016 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_SURJECTION_H_
|
||||
#define _SECP256K1_SURJECTION_H_
|
||||
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_surjection_genmessage(unsigned char *msg32, secp256k1_ge *ephemeral_input_tags, size_t n_input_tags, secp256k1_ge *ephemeral_output_tag);
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_surjection_genrand(secp256k1_scalar *s, size_t ns, const secp256k1_scalar *blinding_key);
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_surjection_compute_public_keys(secp256k1_gej *pubkeys, size_t n_pubkeys, const secp256k1_ge *input_tags, size_t n_input_tags, const unsigned char *used_tags, const secp256k1_ge *output_tag, size_t input_index, size_t *ring_input_index);
|
||||
|
||||
#endif
|
||||
108
src/secp256k1/src/modules/surjection/surjection.md
Normal file
108
src/secp256k1/src/modules/surjection/surjection.md
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
Surjection Proof Module
|
||||
===========================
|
||||
|
||||
This module implements a scheme by which a given point can be proven to be
|
||||
equal to one of a set of points, plus a known difference. This is used in
|
||||
Confidential Assets when reblinding "asset commitments", which are NUMS
|
||||
points, to prove that the underlying NUMS point does not change during
|
||||
reblinding.
|
||||
|
||||
Assets are represented, in general, by a 32-byte seed (a hash of some
|
||||
transaction data) which is hashed to form a NUMS generator, which appears
|
||||
on the blockchain only in blinded form. We refer to the seed as an
|
||||
"asset ID" and the blinded generator as an "(ephemeral) asset commitment".
|
||||
These asset commitments are unique per-output, and their NUMS components
|
||||
are in general known only to the holder of the output.
|
||||
|
||||
The result is that within a transaction, all outputs are able to have
|
||||
a new uniformly-random asset commitment which cannot be associated with
|
||||
any individual input asset id, but verifiers are nonetheless assured that
|
||||
all assets coming out of a transaction are ones that went in.
|
||||
|
||||
### Terminology
|
||||
|
||||
Assets are identified by a 32-byte "asset ID". In this library these IDs
|
||||
are used as input to a point-valued hash function `H`. We usually refer
|
||||
to the hash output as `A`, since this output is the only thing that appears
|
||||
in the algebra.
|
||||
|
||||
Then transaction outputs have "asset commitments", which are curvepoints
|
||||
of the form `A + rG`, where `A` is the hash of the asset ID and `r` is
|
||||
some random "blinding factor".
|
||||
|
||||
### Design Rationale
|
||||
|
||||
Confidential Assets essentially works by replacing the second NUMS generator
|
||||
`H` in Confidental Transactions with a per-asset unique NUMS generator. This
|
||||
allows the same verification equation (the sum of all blinded inputs must
|
||||
equal the sum of all blinded outputs) to imply that quantity of *every* asset
|
||||
type is preserved in each transaction.
|
||||
|
||||
It turns out that even if outputs are reblinded by the addition of `rG` for
|
||||
some known `r`, this verification equation has the same meaning, with one
|
||||
caveat: verifiers must be assured that the reblinding preserves the original
|
||||
generators (and does not, for example, negate them).
|
||||
|
||||
This assurance is what surjection proofs provide.
|
||||
|
||||
### Limitations
|
||||
|
||||
The naive scheme works as follows: every output asset is shown to have come
|
||||
from some input asset. However, the proofs scale with the number of input
|
||||
assets, so for all outputs the total size of all surjection proofs is `O(mn)`
|
||||
for `m`, `n` the number of inputs and outputs.
|
||||
|
||||
We therefore restrict the number of inputs that each output may have come
|
||||
from to 3 (well, some fixed number, which is passed into the API), which
|
||||
provides a weaker form of blinding, but gives `O(n)` scaling. Over many
|
||||
transactions, the privacy afforded by this increases exponentially.
|
||||
|
||||
### Our Scheme
|
||||
|
||||
Our scheme works as follows. Proofs are generated in two steps, "initialization"
|
||||
which selects a subset of inputs and "generation" which does the mathematical
|
||||
part of proof generation.
|
||||
|
||||
Every input has an asset commitment for which we know the blinding key and
|
||||
underlying asset ID.
|
||||
|
||||
#### Initialization
|
||||
|
||||
The initialization function takes a list of input asset IDs and one output
|
||||
asset ID. It chooses an input subset of some fixed size repeatedly until it
|
||||
the output ID appears at least once in its subset.
|
||||
|
||||
It stores a bitmap representing this subset in the proof object and returns
|
||||
the number of iterations it needed to choose the subset. The reciprocal of
|
||||
this represents the probability that a uniformly random input-output
|
||||
mapping would correspond to the actual input-output mapping, and therefore
|
||||
gives a measure of privacy. (Lower iteration counts are better.)
|
||||
|
||||
It also informs the caller the index of the input whose ID matches the output.
|
||||
|
||||
As the API works on only a single output at a time, the total probability
|
||||
should be computed by multiplying together the counts for each output.
|
||||
|
||||
#### Generation
|
||||
|
||||
The generation function takes a list of input asset commitments, an output
|
||||
asset commitment, the input index returned by the initialization step, and
|
||||
blinding keys for (a) the output commitment, (b) the input commitment. Here
|
||||
"the input commitment" refers specifically to the input whose index was
|
||||
chosen during initialization.
|
||||
|
||||
Next, it computes a ring signature over the differences between the output
|
||||
commitment and every input commitment chosen during initialization. Since
|
||||
the discrete log of one of these is the difference between the output and
|
||||
input blinding keys, it is possible to create a ring signature over every
|
||||
differences will be the blinding factor of the output. We create such a
|
||||
signature, which completes the proof.
|
||||
|
||||
#### Verification
|
||||
|
||||
Verification takes a surjection proof object, a list of input commitments,
|
||||
and an output commitment. The proof object contains a ring signature and
|
||||
a bitmap describing which input commitments to use, and verification
|
||||
succeeds iff the signature verifies.
|
||||
|
||||
|
||||
86
src/secp256k1/src/modules/surjection/surjection_impl.h
Normal file
86
src/secp256k1/src/modules/surjection/surjection_impl.h
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2016 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_SURJECTION_IMPL_H_
|
||||
#define _SECP256K1_SURJECTION_IMPL_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "eckey.h"
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
#include "hash.h"
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_surjection_genmessage(unsigned char *msg32, secp256k1_ge *ephemeral_input_tags, size_t n_input_tags, secp256k1_ge *ephemeral_output_tag) {
|
||||
/* compute message */
|
||||
size_t i;
|
||||
unsigned char pk_ser[33];
|
||||
size_t pk_len = sizeof(pk_ser);
|
||||
secp256k1_sha256_t sha256_en;
|
||||
|
||||
secp256k1_sha256_initialize(&sha256_en);
|
||||
for (i = 0; i < n_input_tags; i++) {
|
||||
secp256k1_eckey_pubkey_serialize(&ephemeral_input_tags[i], pk_ser, &pk_len, 1);
|
||||
assert(pk_len == sizeof(pk_ser));
|
||||
secp256k1_sha256_write(&sha256_en, pk_ser, pk_len);
|
||||
}
|
||||
secp256k1_eckey_pubkey_serialize(ephemeral_output_tag, pk_ser, &pk_len, 1);
|
||||
assert(pk_len == sizeof(pk_ser));
|
||||
secp256k1_sha256_write(&sha256_en, pk_ser, pk_len);
|
||||
secp256k1_sha256_finalize(&sha256_en, msg32);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_surjection_genrand(secp256k1_scalar *s, size_t ns, const secp256k1_scalar *blinding_key) {
|
||||
size_t i;
|
||||
unsigned char sec_input[36];
|
||||
secp256k1_sha256_t sha256_en;
|
||||
|
||||
/* compute s values */
|
||||
secp256k1_scalar_get_b32(&sec_input[4], blinding_key);
|
||||
for (i = 0; i < ns; i++) {
|
||||
int overflow = 0;
|
||||
sec_input[0] = i;
|
||||
sec_input[1] = i >> 8;
|
||||
sec_input[2] = i >> 16;
|
||||
sec_input[3] = i >> 24;
|
||||
|
||||
secp256k1_sha256_initialize(&sha256_en);
|
||||
secp256k1_sha256_write(&sha256_en, sec_input, 36);
|
||||
secp256k1_sha256_finalize(&sha256_en, sec_input);
|
||||
secp256k1_scalar_set_b32(&s[i], sec_input, &overflow);
|
||||
if (overflow == 1) {
|
||||
memset(sec_input, 0, 32);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
memset(sec_input, 0, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_surjection_compute_public_keys(secp256k1_gej *pubkeys, size_t n_pubkeys, const secp256k1_ge *input_tags, size_t n_input_tags, const unsigned char *used_tags, const secp256k1_ge *output_tag, size_t input_index, size_t *ring_input_index) {
|
||||
size_t i;
|
||||
size_t j = 0;
|
||||
for (i = 0; i < n_input_tags; i++) {
|
||||
if (used_tags[i / 8] & (1 << (i % 8))) {
|
||||
secp256k1_ge tmpge;
|
||||
secp256k1_ge_neg(&tmpge, &input_tags[i]);
|
||||
secp256k1_gej_set_ge(&pubkeys[j], &tmpge);
|
||||
secp256k1_gej_add_ge_var(&pubkeys[j], &pubkeys[j], output_tag, NULL);
|
||||
if (ring_input_index != NULL && input_index == i) {
|
||||
*ring_input_index = j;
|
||||
}
|
||||
j++;
|
||||
if (j > n_pubkeys) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
487
src/secp256k1/src/modules/surjection/tests_impl.h
Normal file
487
src/secp256k1/src/modules/surjection/tests_impl.h
Normal file
|
|
@ -0,0 +1,487 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2016 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_SURJECTIONPROOF_TESTS
|
||||
#define SECP256K1_MODULE_SURJECTIONPROOF_TESTS
|
||||
|
||||
#include "testrand.h"
|
||||
#include "group.h"
|
||||
#include "include/secp256k1_generator.h"
|
||||
#include "include/secp256k1_rangeproof.h"
|
||||
#include "include/secp256k1_surjectionproof.h"
|
||||
|
||||
static void test_surjectionproof_api(void) {
|
||||
unsigned char seed[32];
|
||||
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
|
||||
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
secp256k1_fixed_asset_tag fixed_input_tags[10];
|
||||
secp256k1_fixed_asset_tag fixed_output_tag;
|
||||
secp256k1_generator ephemeral_input_tags[10];
|
||||
secp256k1_generator ephemeral_output_tag;
|
||||
unsigned char input_blinding_key[10][32];
|
||||
unsigned char output_blinding_key[32];
|
||||
unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX];
|
||||
size_t serialized_len;
|
||||
secp256k1_surjectionproof proof;
|
||||
size_t n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]);
|
||||
size_t input_index;
|
||||
int32_t ecount = 0;
|
||||
size_t i;
|
||||
|
||||
secp256k1_rand256(seed);
|
||||
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
|
||||
|
||||
for (i = 0; i < n_inputs; i++) {
|
||||
secp256k1_rand256(input_blinding_key[i]);
|
||||
secp256k1_rand256(fixed_input_tags[i].data);
|
||||
CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_input_tags[i], fixed_input_tags[i].data, input_blinding_key[i]));
|
||||
}
|
||||
secp256k1_rand256(output_blinding_key);
|
||||
memcpy(&fixed_output_tag, &fixed_input_tags[0], sizeof(fixed_input_tags[0]));
|
||||
CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_output_tag, fixed_output_tag.data, output_blinding_key));
|
||||
|
||||
/* check initialize */
|
||||
CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, seed) == 0);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_surjectionproof_initialize(none, NULL, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_surjectionproof_initialize(none, &proof, NULL, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, NULL, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS + 1, 3, &fixed_input_tags[0], 100, seed) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs, &fixed_input_tags[0], 100, seed) != 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs + 1, &fixed_input_tags[0], 100, seed) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 3, NULL, 100, seed) == 0);
|
||||
CHECK(ecount == 6);
|
||||
CHECK((secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 0, seed) & 1) == 0);
|
||||
CHECK(ecount == 6);
|
||||
CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, NULL) == 0);
|
||||
CHECK(ecount == 7);
|
||||
|
||||
CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0);
|
||||
/* check generate */
|
||||
CHECK(secp256k1_surjectionproof_generate(none, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
|
||||
CHECK(ecount == 8);
|
||||
CHECK(secp256k1_surjectionproof_generate(vrfy, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
|
||||
CHECK(ecount == 9);
|
||||
|
||||
CHECK(secp256k1_surjectionproof_generate(sign, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
|
||||
CHECK(ecount == 10);
|
||||
CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) != 0);
|
||||
CHECK(ecount == 10);
|
||||
|
||||
CHECK(secp256k1_surjectionproof_generate(both, NULL, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
|
||||
CHECK(ecount == 11);
|
||||
CHECK(secp256k1_surjectionproof_generate(both, &proof, NULL, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
|
||||
CHECK(ecount == 12);
|
||||
CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs + 1, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
|
||||
CHECK(ecount == 12);
|
||||
CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs - 1, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
|
||||
CHECK(ecount == 12);
|
||||
CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, 0, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
|
||||
CHECK(ecount == 12);
|
||||
CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, NULL, 0, input_blinding_key[0], output_blinding_key) == 0);
|
||||
CHECK(ecount == 13);
|
||||
CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 1, input_blinding_key[0], output_blinding_key) != 0);
|
||||
CHECK(ecount == 13); /* the above line "succeeds" but generates an invalid proof as the input_index is wrong. it is fairly expensive to detect this. should we? */
|
||||
CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, n_inputs + 1, input_blinding_key[0], output_blinding_key) != 0);
|
||||
CHECK(ecount == 13);
|
||||
CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, NULL, output_blinding_key) == 0);
|
||||
CHECK(ecount == 14);
|
||||
CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], NULL) == 0);
|
||||
CHECK(ecount == 15);
|
||||
|
||||
CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) != 0);
|
||||
/* check verify */
|
||||
CHECK(secp256k1_surjectionproof_verify(none, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 0);
|
||||
CHECK(ecount == 16);
|
||||
CHECK(secp256k1_surjectionproof_verify(sign, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 0);
|
||||
CHECK(ecount == 17);
|
||||
CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) != 0);
|
||||
CHECK(ecount == 17);
|
||||
|
||||
CHECK(secp256k1_surjectionproof_verify(vrfy, NULL, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 0);
|
||||
CHECK(ecount == 18);
|
||||
CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, NULL, n_inputs, &ephemeral_output_tag) == 0);
|
||||
CHECK(ecount == 19);
|
||||
CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs - 1, &ephemeral_output_tag) == 0);
|
||||
CHECK(ecount == 19);
|
||||
CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs + 1, &ephemeral_output_tag) == 0);
|
||||
CHECK(ecount == 19);
|
||||
CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs, NULL) == 0);
|
||||
CHECK(ecount == 20);
|
||||
|
||||
/* Check serialize */
|
||||
serialized_len = sizeof(serialized_proof);
|
||||
CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, &serialized_len, &proof) != 0);
|
||||
CHECK(ecount == 20);
|
||||
serialized_len = sizeof(serialized_proof);
|
||||
CHECK(secp256k1_surjectionproof_serialize(none, NULL, &serialized_len, &proof) == 0);
|
||||
CHECK(ecount == 21);
|
||||
serialized_len = sizeof(serialized_proof);
|
||||
CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, NULL, &proof) == 0);
|
||||
CHECK(ecount == 22);
|
||||
serialized_len = sizeof(serialized_proof);
|
||||
CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, &serialized_len, NULL) == 0);
|
||||
CHECK(ecount == 23);
|
||||
|
||||
serialized_len = sizeof(serialized_proof);
|
||||
CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, &serialized_len, &proof) != 0);
|
||||
/* Check parse */
|
||||
CHECK(secp256k1_surjectionproof_parse(none, &proof, serialized_proof, serialized_len) != 0);
|
||||
CHECK(ecount == 23);
|
||||
CHECK(secp256k1_surjectionproof_parse(none, NULL, serialized_proof, serialized_len) == 0);
|
||||
CHECK(ecount == 24);
|
||||
CHECK(secp256k1_surjectionproof_parse(none, &proof, NULL, serialized_len) == 0);
|
||||
CHECK(ecount == 25);
|
||||
CHECK(secp256k1_surjectionproof_parse(none, &proof, serialized_proof, 0) == 0);
|
||||
CHECK(ecount == 25);
|
||||
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(vrfy);
|
||||
secp256k1_context_destroy(both);
|
||||
}
|
||||
|
||||
static void test_input_selection(size_t n_inputs) {
|
||||
unsigned char seed[32];
|
||||
size_t i;
|
||||
size_t result;
|
||||
size_t input_index;
|
||||
size_t try_count = n_inputs * 100;
|
||||
secp256k1_surjectionproof proof;
|
||||
secp256k1_fixed_asset_tag fixed_input_tags[1000];
|
||||
const size_t max_n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]) - 1;
|
||||
|
||||
CHECK(n_inputs < max_n_inputs);
|
||||
secp256k1_rand256(seed);
|
||||
|
||||
for (i = 0; i < n_inputs + 1; i++) {
|
||||
secp256k1_rand256(fixed_input_tags[i].data);
|
||||
}
|
||||
|
||||
/* cannot match output when told to use zero keys */
|
||||
result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], try_count, seed);
|
||||
CHECK(result == 0);
|
||||
CHECK(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == 0);
|
||||
CHECK(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs);
|
||||
CHECK(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 34 + (n_inputs + 7) / 8);
|
||||
if (n_inputs > 0) {
|
||||
/* succeed in 100*n_inputs tries (probability of failure e^-100) */
|
||||
result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 1, &fixed_input_tags[0], try_count, seed);
|
||||
CHECK(result > 0);
|
||||
CHECK(result < n_inputs * 10);
|
||||
CHECK(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == 1);
|
||||
CHECK(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs);
|
||||
CHECK(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 66 + (n_inputs + 7) / 8);
|
||||
CHECK(input_index == 0);
|
||||
}
|
||||
|
||||
if (n_inputs >= 3) {
|
||||
/* succeed in 10*n_inputs tries (probability of failure e^-10) */
|
||||
result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[1], try_count, seed);
|
||||
CHECK(result > 0);
|
||||
CHECK(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == 3);
|
||||
CHECK(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs);
|
||||
CHECK(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 130 + (n_inputs + 7) / 8);
|
||||
CHECK(input_index == 1);
|
||||
|
||||
/* fail, key not found */
|
||||
result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[n_inputs], try_count, seed);
|
||||
CHECK(result == 0);
|
||||
|
||||
/* succeed on first try when told to use all keys */
|
||||
result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs, &fixed_input_tags[0], try_count, seed);
|
||||
CHECK(result == 1);
|
||||
CHECK(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == n_inputs);
|
||||
CHECK(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs);
|
||||
CHECK(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 2 + 32 * (n_inputs + 1) + (n_inputs + 7) / 8);
|
||||
CHECK(input_index == 0);
|
||||
|
||||
/* succeed in less than 64 tries when told to use half keys. (probability of failure 2^-64) */
|
||||
result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs / 2, &fixed_input_tags[0], 64, seed);
|
||||
CHECK(result > 0);
|
||||
CHECK(result < 64);
|
||||
CHECK(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == n_inputs / 2);
|
||||
CHECK(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs);
|
||||
CHECK(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 2 + 32 * (n_inputs / 2 + 1) + (n_inputs + 7) / 8);
|
||||
CHECK(input_index == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/** Runs surjectionproof_initilize multiple times and records the number of times each input was used.
|
||||
*/
|
||||
static void test_input_selection_distribution_helper(const secp256k1_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, size_t *used_inputs) {
|
||||
secp256k1_surjectionproof proof;
|
||||
size_t input_index;
|
||||
size_t i;
|
||||
size_t j;
|
||||
unsigned char seed[32];
|
||||
size_t result;
|
||||
for (i = 0; i < n_input_tags; i++) {
|
||||
used_inputs[i] = 0;
|
||||
}
|
||||
for(j = 0; j < 10000; j++) {
|
||||
secp256k1_rand256(seed);
|
||||
result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_input_tags, n_input_tags_to_use, &fixed_input_tags[0], 64, seed);
|
||||
CHECK(result > 0);
|
||||
|
||||
for (i = 0; i < n_input_tags; i++) {
|
||||
if (proof.used_inputs[i / 8] & (1 << (i % 8))) {
|
||||
used_inputs[i] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Probabilistic test of the distribution of used_inputs after surjectionproof_initialize.
|
||||
* Each confidence interval assertion fails incorrectly with a probability of 2^-128.
|
||||
*/
|
||||
static void test_input_selection_distribution(void) {
|
||||
size_t i;
|
||||
size_t n_input_tags_to_use;
|
||||
const size_t n_inputs = 4;
|
||||
secp256k1_fixed_asset_tag fixed_input_tags[4];
|
||||
size_t used_inputs[4];
|
||||
|
||||
for (i = 0; i < n_inputs; i++) {
|
||||
secp256k1_rand256(fixed_input_tags[i].data);
|
||||
}
|
||||
|
||||
/* If there is one input tag to use, initialize must choose the one equal to fixed_output_tag. */
|
||||
n_input_tags_to_use = 1;
|
||||
test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs);
|
||||
CHECK(used_inputs[0] == 10000);
|
||||
CHECK(used_inputs[1] == 0);
|
||||
CHECK(used_inputs[2] == 0);
|
||||
CHECK(used_inputs[3] == 0);
|
||||
|
||||
n_input_tags_to_use = 2;
|
||||
/* The input equal to the fixed_output_tag must be included in all used_inputs sets.
|
||||
* For each fixed_input_tag != fixed_output_tag the probability that it's included
|
||||
* in the used_inputs set is P(used_input|not fixed_output_tag) = 1/3.
|
||||
*/
|
||||
test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs);
|
||||
CHECK(used_inputs[0] == 10000);
|
||||
CHECK(used_inputs[1] > 2725 && used_inputs[1] < 3961);
|
||||
CHECK(used_inputs[2] > 2725 && used_inputs[2] < 3961);
|
||||
CHECK(used_inputs[3] > 2725 && used_inputs[3] < 3961);
|
||||
|
||||
n_input_tags_to_use = 3;
|
||||
/* P(used_input|not fixed_output_tag) = 2/3 */
|
||||
test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs);
|
||||
CHECK(used_inputs[0] == 10000);
|
||||
CHECK(used_inputs[1] > 6039 && used_inputs[1] < 7275);
|
||||
CHECK(used_inputs[2] > 6039 && used_inputs[2] < 7275);
|
||||
CHECK(used_inputs[3] > 6039 && used_inputs[3] < 7275);
|
||||
|
||||
|
||||
n_input_tags_to_use = 1;
|
||||
/* Create second input tag that is equal to the output tag. Therefore, when using only
|
||||
* one input we have P(used_input|fixed_output_tag) = 1/2 and P(used_input|not fixed_output_tag) = 0
|
||||
*/
|
||||
memcpy(fixed_input_tags[0].data, fixed_input_tags[1].data, 32);
|
||||
test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs);
|
||||
CHECK(used_inputs[0] > 4345 && used_inputs[0] < 5655);
|
||||
CHECK(used_inputs[1] > 4345 && used_inputs[1] < 5655);
|
||||
CHECK(used_inputs[2] == 0);
|
||||
CHECK(used_inputs[3] == 0);
|
||||
|
||||
n_input_tags_to_use = 2;
|
||||
/* When choosing 2 inputs in initialization there are 5 possible combinations of
|
||||
* input indexes {(0, 1), (1, 2), (0, 3), (1, 3), (0, 2)}. Therefore we have
|
||||
* P(used_input|fixed_output_tag) = 3/5 and P(used_input|not fixed_output_tag) = 2/5.
|
||||
*/
|
||||
test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs);
|
||||
CHECK(used_inputs[0] > 5352 && used_inputs[0] < 6637);
|
||||
CHECK(used_inputs[1] > 5352 && used_inputs[1] < 6637);
|
||||
CHECK(used_inputs[2] > 3363 && used_inputs[2] < 4648);
|
||||
CHECK(used_inputs[3] > 3363 && used_inputs[3] < 4648);
|
||||
|
||||
n_input_tags_to_use = 3;
|
||||
/* There are 4 combinations, each with all inputs except one. Therefore we have
|
||||
* P(used_input|fixed_output_tag) = 3/4 and P(used_input|not fixed_output_tag) = 3/4.
|
||||
*/
|
||||
test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs);
|
||||
CHECK(used_inputs[0] > 6918 && used_inputs[0] < 8053);
|
||||
CHECK(used_inputs[1] > 6918 && used_inputs[1] < 8053);
|
||||
CHECK(used_inputs[2] > 6918 && used_inputs[2] < 8053);
|
||||
CHECK(used_inputs[3] > 6918 && used_inputs[3] < 8053);
|
||||
}
|
||||
|
||||
static void test_gen_verify(size_t n_inputs, size_t n_used) {
|
||||
unsigned char seed[32];
|
||||
secp256k1_surjectionproof proof;
|
||||
unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX];
|
||||
size_t serialized_len = SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX;
|
||||
secp256k1_fixed_asset_tag fixed_input_tags[1000];
|
||||
secp256k1_generator ephemeral_input_tags[1000];
|
||||
unsigned char *input_blinding_key[1000];
|
||||
const size_t max_n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]) - 1;
|
||||
size_t try_count = n_inputs * 100;
|
||||
size_t key_index;
|
||||
size_t input_index;
|
||||
size_t i;
|
||||
int result;
|
||||
|
||||
/* setup */
|
||||
CHECK(n_used <= n_inputs);
|
||||
CHECK(n_inputs < max_n_inputs);
|
||||
secp256k1_rand256(seed);
|
||||
|
||||
key_index = (((size_t) seed[0] << 8) + seed[1]) % n_inputs;
|
||||
|
||||
for (i = 0; i < n_inputs + 1; i++) {
|
||||
input_blinding_key[i] = malloc(32);
|
||||
secp256k1_rand256(input_blinding_key[i]);
|
||||
/* choose random fixed tag, except that for the output one copy from the key_index */
|
||||
if (i < n_inputs) {
|
||||
secp256k1_rand256(fixed_input_tags[i].data);
|
||||
} else {
|
||||
memcpy(&fixed_input_tags[i], &fixed_input_tags[key_index], sizeof(fixed_input_tags[i]));
|
||||
}
|
||||
CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_input_tags[i], fixed_input_tags[i].data, input_blinding_key[i]));
|
||||
}
|
||||
|
||||
/* test */
|
||||
result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, n_used, &fixed_input_tags[key_index], try_count, seed);
|
||||
if (n_used == 0) {
|
||||
CHECK(result == 0);
|
||||
return;
|
||||
}
|
||||
CHECK(result > 0);
|
||||
CHECK(input_index == key_index);
|
||||
|
||||
result = secp256k1_surjectionproof_generate(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs], input_index, input_blinding_key[input_index], input_blinding_key[n_inputs]);
|
||||
CHECK(result == 1);
|
||||
|
||||
CHECK(secp256k1_surjectionproof_serialize(ctx, serialized_proof, &serialized_len, &proof));
|
||||
CHECK(serialized_len == secp256k1_surjectionproof_serialized_size(ctx, &proof));
|
||||
CHECK(serialized_len == SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(n_inputs, n_used));
|
||||
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof, serialized_len));
|
||||
result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs]);
|
||||
CHECK(result == 1);
|
||||
/* various fail cases */
|
||||
if (n_inputs > 1) {
|
||||
result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs - 1]);
|
||||
CHECK(result == 0);
|
||||
|
||||
/* number of entries in ephemeral_input_tags array is less than proof.n_inputs */
|
||||
n_inputs -= 1;
|
||||
result = secp256k1_surjectionproof_generate(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs], input_index, input_blinding_key[input_index], input_blinding_key[n_inputs]);
|
||||
CHECK(result == 0);
|
||||
result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs - 1]);
|
||||
CHECK(result == 0);
|
||||
n_inputs += 1;
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
for (i = 0; i < n_inputs + 1; i++) {
|
||||
free(input_blinding_key[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* check that a proof with empty n_used_inputs is invalid */
|
||||
static void test_no_used_inputs_verify(void) {
|
||||
secp256k1_surjectionproof proof;
|
||||
secp256k1_fixed_asset_tag fixed_input_tag;
|
||||
secp256k1_fixed_asset_tag fixed_output_tag;
|
||||
secp256k1_generator ephemeral_input_tags[1];
|
||||
size_t n_ephemeral_input_tags = 1;
|
||||
secp256k1_generator ephemeral_output_tag;
|
||||
unsigned char blinding_key[32];
|
||||
secp256k1_ge inputs[1];
|
||||
secp256k1_ge output;
|
||||
secp256k1_sha256_t sha256_e0;
|
||||
int result;
|
||||
|
||||
/* Create proof that doesn't use inputs. secp256k1_surjectionproof_initialize
|
||||
* will not work here since it insists on selecting an input that matches the output. */
|
||||
proof.n_inputs = 1;
|
||||
memset(proof.used_inputs, 0, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS / 8);
|
||||
|
||||
/* create different fixed input and output tags */
|
||||
secp256k1_rand256(fixed_input_tag.data);
|
||||
secp256k1_rand256(fixed_output_tag.data);
|
||||
|
||||
/* blind fixed output tags with random blinding key */
|
||||
secp256k1_rand256(blinding_key);
|
||||
CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_input_tags[0], fixed_input_tag.data, blinding_key));
|
||||
CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_output_tag, fixed_output_tag.data, blinding_key));
|
||||
|
||||
/* create "borromean signature" which is just a hash of metadata (pubkeys, etc) in this case */
|
||||
secp256k1_generator_load(&output, &ephemeral_output_tag);
|
||||
secp256k1_generator_load(&inputs[0], &ephemeral_input_tags[0]);
|
||||
secp256k1_surjection_genmessage(proof.data, inputs, 1, &output);
|
||||
secp256k1_sha256_initialize(&sha256_e0);
|
||||
secp256k1_sha256_write(&sha256_e0, proof.data, 32);
|
||||
secp256k1_sha256_finalize(&sha256_e0, proof.data);
|
||||
|
||||
result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_ephemeral_input_tags, &ephemeral_output_tag);
|
||||
CHECK(result == 0);
|
||||
}
|
||||
|
||||
void test_bad_serialize(void) {
|
||||
secp256k1_surjectionproof proof;
|
||||
unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX];
|
||||
size_t serialized_len;
|
||||
|
||||
proof.n_inputs = 0;
|
||||
serialized_len = 2 + 31;
|
||||
/* e0 is one byte too short */
|
||||
CHECK(secp256k1_surjectionproof_serialize(ctx, serialized_proof, &serialized_len, &proof) == 0);
|
||||
}
|
||||
|
||||
void test_bad_parse(void) {
|
||||
secp256k1_surjectionproof proof;
|
||||
unsigned char serialized_proof0[] = { 0x00 };
|
||||
unsigned char serialized_proof1[] = { 0x01, 0x00 };
|
||||
unsigned char serialized_proof2[33] = { 0 };
|
||||
|
||||
/* Missing total input count */
|
||||
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof0, sizeof(serialized_proof0)) == 0);
|
||||
/* Missing bitmap */
|
||||
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof1, sizeof(serialized_proof1)) == 0);
|
||||
/* Missing e0 value */
|
||||
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof2, sizeof(serialized_proof2)) == 0);
|
||||
}
|
||||
|
||||
void run_surjection_tests(void) {
|
||||
int i;
|
||||
for (i = 0; i < count; i++) {
|
||||
test_surjectionproof_api();
|
||||
}
|
||||
|
||||
test_input_selection(0);
|
||||
test_input_selection(1);
|
||||
test_input_selection(5);
|
||||
test_input_selection(100);
|
||||
test_input_selection(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS);
|
||||
|
||||
test_input_selection_distribution();
|
||||
test_gen_verify(10, 3);
|
||||
test_gen_verify(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS);
|
||||
test_no_used_inputs_verify();
|
||||
test_bad_serialize();
|
||||
test_bad_parse();
|
||||
}
|
||||
|
||||
#endif
|
||||
3
src/secp256k1/src/modules/whitelist/Makefile.am.include
Normal file
3
src/secp256k1/src/modules/whitelist/Makefile.am.include
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
include_HEADERS += include/secp256k1_whitelist.h
|
||||
noinst_HEADERS += src/modules/whitelist/main_impl.h
|
||||
noinst_HEADERS += src/modules/whitelist/tests_impl.h
|
||||
164
src/secp256k1/src/modules/whitelist/main_impl.h
Normal file
164
src/secp256k1/src/modules/whitelist/main_impl.h
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2016 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_WHITELIST_MAIN
|
||||
#define SECP256K1_MODULE_WHITELIST_MAIN
|
||||
|
||||
#include "include/secp256k1_whitelist.h"
|
||||
#include "modules/whitelist/whitelist_impl.h"
|
||||
|
||||
#define MAX_KEYS SECP256K1_WHITELIST_MAX_N_KEYS /* shorter alias */
|
||||
|
||||
int secp256k1_whitelist_sign(const secp256k1_context* ctx, secp256k1_whitelist_signature *sig, const secp256k1_pubkey *online_pubkeys, const secp256k1_pubkey *offline_pubkeys, const size_t n_keys, const secp256k1_pubkey *sub_pubkey, const unsigned char *online_seckey, const unsigned char *summed_seckey, const size_t index, secp256k1_nonce_function noncefp, const void *noncedata) {
|
||||
secp256k1_gej pubs[MAX_KEYS];
|
||||
secp256k1_scalar s[MAX_KEYS];
|
||||
secp256k1_scalar sec, non;
|
||||
unsigned char msg32[32];
|
||||
int ret;
|
||||
|
||||
if (noncefp == NULL) {
|
||||
noncefp = secp256k1_nonce_function_default;
|
||||
}
|
||||
|
||||
/* Sanity checks */
|
||||
VERIFY_CHECK(ctx != 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(sig != NULL);
|
||||
ARG_CHECK(online_pubkeys != NULL);
|
||||
ARG_CHECK(offline_pubkeys != NULL);
|
||||
ARG_CHECK(n_keys <= MAX_KEYS);
|
||||
ARG_CHECK(sub_pubkey != NULL);
|
||||
ARG_CHECK(online_seckey != NULL);
|
||||
ARG_CHECK(summed_seckey != NULL);
|
||||
ARG_CHECK(index < n_keys);
|
||||
|
||||
/* Compute pubkeys: online_pubkey + tweaked(offline_pubkey + address), and message */
|
||||
ret = secp256k1_whitelist_compute_keys_and_message(ctx, msg32, pubs, online_pubkeys, offline_pubkeys, n_keys, sub_pubkey);
|
||||
|
||||
/* Compute signing key: online_seckey + tweaked(summed_seckey) */
|
||||
if (ret) {
|
||||
ret = secp256k1_whitelist_compute_tweaked_privkey(ctx, &sec, online_seckey, summed_seckey);
|
||||
}
|
||||
/* Compute nonce and random s-values */
|
||||
if (ret) {
|
||||
unsigned char seckey32[32];
|
||||
unsigned int count = 0;
|
||||
int overflow = 0;
|
||||
|
||||
secp256k1_scalar_get_b32(seckey32, &sec);
|
||||
while (1) {
|
||||
size_t i;
|
||||
unsigned char nonce32[32];
|
||||
int done;
|
||||
ret = noncefp(nonce32, msg32, seckey32, NULL, (void*)noncedata, count);
|
||||
if (!ret) {
|
||||
break;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
|
||||
memset(nonce32, 0, 32);
|
||||
if (overflow || secp256k1_scalar_is_zero(&non)) {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
done = 1;
|
||||
for (i = 0; i < n_keys; i++) {
|
||||
msg32[0] ^= i + 1;
|
||||
msg32[1] ^= (i + 1) / 0x100;
|
||||
ret = noncefp(&sig->data[32 * (i + 1)], msg32, seckey32, NULL, (void*)noncedata, count);
|
||||
if (!ret) {
|
||||
break;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&s[i], &sig->data[32 * (i + 1)], &overflow);
|
||||
msg32[0] ^= i + 1;
|
||||
msg32[1] ^= (i + 1) / 0x100;
|
||||
if (overflow || secp256k1_scalar_is_zero(&s[i])) {
|
||||
count++;
|
||||
done = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
memset(seckey32, 0, 32);
|
||||
}
|
||||
/* Actually sign */
|
||||
if (ret) {
|
||||
sig->n_keys = n_keys;
|
||||
ret = secp256k1_borromean_sign(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, &sig->data[0], s, pubs, &non, &sec, &n_keys, &index, 1, msg32, 32);
|
||||
/* Signing will change s[index], so update in the sig structure */
|
||||
secp256k1_scalar_get_b32(&sig->data[32 * (index + 1)], &s[index]);
|
||||
}
|
||||
|
||||
secp256k1_scalar_clear(&non);
|
||||
secp256k1_scalar_clear(&sec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_whitelist_verify(const secp256k1_context* ctx, const secp256k1_whitelist_signature *sig, const secp256k1_pubkey *online_pubkeys, const secp256k1_pubkey *offline_pubkeys, const secp256k1_pubkey *sub_pubkey) {
|
||||
secp256k1_scalar s[MAX_KEYS];
|
||||
secp256k1_gej pubs[MAX_KEYS];
|
||||
unsigned char msg32[32];
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(online_pubkeys != NULL);
|
||||
ARG_CHECK(offline_pubkeys != NULL);
|
||||
ARG_CHECK(sub_pubkey != NULL);
|
||||
|
||||
if (sig->n_keys > MAX_KEYS) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < sig->n_keys; i++) {
|
||||
int overflow = 0;
|
||||
secp256k1_scalar_set_b32(&s[i], &sig->data[32 * (i + 1)], &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&s[i])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute pubkeys: online_pubkey + tweaked(offline_pubkey + address), and message */
|
||||
if (!secp256k1_whitelist_compute_keys_and_message(ctx, msg32, pubs, online_pubkeys, offline_pubkeys, sig->n_keys, sub_pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
/* Do verification */
|
||||
return secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, &sig->data[0], s, pubs, &sig->n_keys, 1, msg32, 32);
|
||||
}
|
||||
|
||||
size_t secp256k1_whitelist_signature_n_keys(const secp256k1_whitelist_signature *sig) {
|
||||
return sig->n_keys;
|
||||
}
|
||||
|
||||
int secp256k1_whitelist_signature_parse(const secp256k1_context* ctx, secp256k1_whitelist_signature *sig, const unsigned char *input) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(input != NULL);
|
||||
|
||||
sig->n_keys = input[0];
|
||||
if (sig->n_keys >= MAX_KEYS) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(&sig->data[0], &input[1], 32 * (sig->n_keys + 1));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_whitelist_signature_serialize(const secp256k1_context* ctx, unsigned char *output, const secp256k1_whitelist_signature *sig) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
|
||||
output[0] = sig->n_keys;
|
||||
memcpy(&output[1], &sig->data[0], 32 * (sig->n_keys + 1));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
108
src/secp256k1/src/modules/whitelist/tests_impl.h
Normal file
108
src/secp256k1/src/modules/whitelist/tests_impl.h
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2014-2016 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_MODULE_WHITELIST_TESTS
|
||||
#define SECP256K1_MODULE_WHITELIST_TESTS
|
||||
|
||||
#include "include/secp256k1_whitelist.h"
|
||||
|
||||
void test_whitelist_end_to_end(const size_t n_keys) {
|
||||
unsigned char **online_seckey = (unsigned char **) malloc(n_keys * sizeof(*online_seckey));
|
||||
unsigned char **summed_seckey = (unsigned char **) malloc(n_keys * sizeof(*summed_seckey));
|
||||
secp256k1_pubkey *online_pubkeys = (secp256k1_pubkey *) malloc(n_keys * sizeof(*online_pubkeys));
|
||||
secp256k1_pubkey *offline_pubkeys = (secp256k1_pubkey *) malloc(n_keys * sizeof(*offline_pubkeys));
|
||||
|
||||
secp256k1_scalar ssub;
|
||||
unsigned char csub[32];
|
||||
secp256k1_pubkey sub_pubkey;
|
||||
|
||||
/* Generate random keys */
|
||||
size_t i;
|
||||
/* Start with subkey */
|
||||
random_scalar_order_test(&ssub);
|
||||
secp256k1_scalar_get_b32(csub, &ssub);
|
||||
CHECK(secp256k1_ec_seckey_verify(ctx, csub) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &sub_pubkey, csub) == 1);
|
||||
/* Then offline and online whitelist keys */
|
||||
for (i = 0; i < n_keys; i++) {
|
||||
secp256k1_scalar son, soff;
|
||||
|
||||
online_seckey[i] = (unsigned char *) malloc(32);
|
||||
summed_seckey[i] = (unsigned char *) malloc(32);
|
||||
|
||||
/* Create two keys */
|
||||
random_scalar_order_test(&son);
|
||||
secp256k1_scalar_get_b32(online_seckey[i], &son);
|
||||
CHECK(secp256k1_ec_seckey_verify(ctx, online_seckey[i]) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &online_pubkeys[i], online_seckey[i]) == 1);
|
||||
|
||||
random_scalar_order_test(&soff);
|
||||
secp256k1_scalar_get_b32(summed_seckey[i], &soff);
|
||||
CHECK(secp256k1_ec_seckey_verify(ctx, summed_seckey[i]) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &offline_pubkeys[i], summed_seckey[i]) == 1);
|
||||
|
||||
/* Make summed_seckey correspond to the sum of offline_pubkey and sub_pubkey */
|
||||
secp256k1_scalar_add(&soff, &soff, &ssub);
|
||||
secp256k1_scalar_get_b32(summed_seckey[i], &soff);
|
||||
CHECK(secp256k1_ec_seckey_verify(ctx, summed_seckey[i]) == 1);
|
||||
}
|
||||
|
||||
/* Sign/verify with each one */
|
||||
for (i = 0; i < n_keys; i++) {
|
||||
unsigned char serialized[32 + 4 + 32 * SECP256K1_WHITELIST_MAX_N_KEYS] = {0};
|
||||
secp256k1_whitelist_signature sig;
|
||||
secp256k1_whitelist_signature sig1;
|
||||
|
||||
CHECK(secp256k1_whitelist_sign(ctx, &sig, online_pubkeys, offline_pubkeys, n_keys, &sub_pubkey, online_seckey[i], summed_seckey[i], i, NULL, NULL));
|
||||
CHECK(secp256k1_whitelist_verify(ctx, &sig, online_pubkeys, offline_pubkeys, &sub_pubkey) == 1);
|
||||
/* Check that exchanging keys causes a failure */
|
||||
CHECK(secp256k1_whitelist_verify(ctx, &sig, offline_pubkeys, online_pubkeys, &sub_pubkey) != 1);
|
||||
/* Serialization round trip */
|
||||
CHECK(secp256k1_whitelist_signature_serialize(ctx, serialized, &sig) == 1);
|
||||
CHECK(secp256k1_whitelist_signature_parse(ctx, &sig1, serialized) == 1);
|
||||
CHECK(secp256k1_whitelist_verify(ctx, &sig1, online_pubkeys, offline_pubkeys, &sub_pubkey) == 1);
|
||||
CHECK(secp256k1_whitelist_verify(ctx, &sig1, offline_pubkeys, online_pubkeys, &sub_pubkey) != 1);
|
||||
/* Test n_keys */
|
||||
CHECK(secp256k1_whitelist_signature_n_keys(&sig) == n_keys);
|
||||
CHECK(secp256k1_whitelist_signature_n_keys(&sig1) == n_keys);
|
||||
}
|
||||
|
||||
for (i = 0; i < n_keys; i++) {
|
||||
free(online_seckey[i]);
|
||||
free(summed_seckey[i]);
|
||||
}
|
||||
free(online_seckey);
|
||||
free(summed_seckey);
|
||||
free(online_pubkeys);
|
||||
free(offline_pubkeys);
|
||||
}
|
||||
|
||||
void test_whitelist_bad_parse(void) {
|
||||
const unsigned char serialized[] = {
|
||||
/* Hash */
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
/* Length in excess of maximum */
|
||||
0x00, 0x00, 0x01, 0x00
|
||||
/* No room for s-values; parse should be rejected before reading past length */
|
||||
};
|
||||
secp256k1_whitelist_signature sig;
|
||||
|
||||
CHECK(secp256k1_whitelist_signature_parse(ctx, &sig, serialized) == 0);
|
||||
}
|
||||
|
||||
void run_whitelist_tests(void) {
|
||||
int i;
|
||||
for (i = 0; i < count; i++) {
|
||||
test_whitelist_end_to_end(1);
|
||||
test_whitelist_end_to_end(10);
|
||||
test_whitelist_end_to_end(50);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
96
src/secp256k1/src/modules/whitelist/whitelist.md
Normal file
96
src/secp256k1/src/modules/whitelist/whitelist.md
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
Address Whitelisting Module
|
||||
===========================
|
||||
|
||||
This module implements a scheme by which members of some group, having fixed
|
||||
signing keys, can prove control of an arbitrary other key without associating
|
||||
their own identity (only that they belong to the group) to the new key. The
|
||||
application is to patch ring-signature-like behaviour onto systems such as
|
||||
Bitcoin or PGP which do not directly support this.
|
||||
|
||||
We refer to such delegation as "whitelisting" because we expect it to be used
|
||||
to build a dynamic whitelist of authorized keys.
|
||||
|
||||
For example, imagine a private sidechain with a fixed membership set but
|
||||
stronger privacy properties than Bitcoin. When moving coins from this system
|
||||
to Bitcoin, it is desirable that the destination Bitcoin addresses be provably
|
||||
in control of some user of the sidechain. This prevents malicious or erroneous
|
||||
behaviour on the sidechain, which can likely be resolved by its participants,
|
||||
from translating to theft on the wider Bitcoin network, which is irreversible.
|
||||
|
||||
### Unused Schemes and Design Rationale
|
||||
|
||||
#### Direct Signing
|
||||
|
||||
An obvious scheme for such delegation is to simply have participants sign the
|
||||
key they want to whitelist. To avoid revealing their specific identity, they
|
||||
could use a ring signature. The problem with this is that it really only proves
|
||||
that a participant *signed off* on a key, not that they control it. Thus any
|
||||
security failure that allows text substitution could be used to subvert this
|
||||
and redirect coins to an attacker-controlled address.
|
||||
|
||||
#### Signing with Difference-of-Keys
|
||||
|
||||
A less obvious scheme is to have a participant sign an arbitrary message with
|
||||
the sum of her key `P` and the whitelisted key `W`. Such a signature with the key
|
||||
`P + W` proves knowledge of either (a) discrete logarithms of both `P` and `W`;
|
||||
or (b) neither. This makes directly attacking participants' signing schemes much
|
||||
harder, but allows an attacker to whitelist arbitrary "garbage" keys by computing
|
||||
`W` as the difference between an attacker-controlled key and `P`. For Bitcoin,
|
||||
the effect of garbage keys is to "burn" stolen coins, destroying them.
|
||||
|
||||
In an important sense, this "burning coins" attack is a good thing: it enables
|
||||
*offline delegation*. That is, the key `P` does not need to be available at the
|
||||
time of delegation. Instead, participants could choose `S = P + W`, sign with
|
||||
this to delegate, and only later compute the discrete logarithm of `W = P - S`.
|
||||
This allows `P` to be in cold storage or be otherwise inaccessible, improving
|
||||
the overall system security.
|
||||
|
||||
#### Signing with Tweaked-Difference-of-Keys
|
||||
|
||||
A modification of this scheme, which prevents this "garbage key" attack, is to
|
||||
instead have participants sign some message with the key `P + H(W)W`, for `H`
|
||||
some random-oracle hash that maps group elements to scalars. This key, and its
|
||||
discrete logarithm, cannot be known until after `W` is chosen, so `W` cannot
|
||||
be selected as the difference between it and `P`. (Note that `P` could still
|
||||
be some chosen difference; however `P` is a fixed key and must be verified
|
||||
out-of-band to have come from a legitimate participant anyway.)
|
||||
|
||||
This scheme is almost what we want, but it no longer supports offline
|
||||
delegation. However, we can get this back by introducing a new key, `P'`,
|
||||
and signing with the key `P + H(W + P')(W + P')`. This gives us the best
|
||||
of both worlds: `P'` does not need to be online to delegate, allowing it
|
||||
to be securely stored and preventing real-time attacks; `P` does need to
|
||||
be online, but its compromise only allows an attacker to whitelist "garbage
|
||||
keys", not attacker-controlled ones.
|
||||
|
||||
### Our Scheme
|
||||
|
||||
Our scheme works as follows: each participant `i` chooses two keys, `P_i` and `Q_i`.
|
||||
We refer to `P_i` as the "online key" and `Q_i` as the "offline key". To whitelist
|
||||
a key `W`, the participant computes the key `L_j = P_j + H(W + Q_j)(W + Q_j)` for
|
||||
every participant `j`. Then she will know the discrete logarithm of `L_i` for her
|
||||
own `i`.
|
||||
|
||||
Next, she signs a message containing every `P_i` and `Q_i` as well as `W` with
|
||||
a ring signature over all the keys `L_j`. This proves that she knows the discrete
|
||||
logarithm of some `L_i` (though it is zero-knowledge which one), and therefore
|
||||
knows:
|
||||
1. The discrete logarithms of all of `W`, `P_i` and `Q_i`; or
|
||||
2. The discrete logarithm of `P_i` but of *neither* `W` nor `Q_i`.
|
||||
In other words, compromise of the online key `P_i` allows an attacker to whitelist
|
||||
"garbage keys" for which nobody knows the discrete logarithm; to whitelist an
|
||||
attacker-controlled key, he must compromise both `P_i` and `Q_i`. This is difficult
|
||||
because by design, only the sum `S = W + Q_i` is used when signing; then by choosing
|
||||
`S` freely, a participant can delegate without the secret key to `Q_i` ever being online.
|
||||
(Later, when she wants to actually use `W`, she will need to compute its key as the
|
||||
difference between `S` and `Q_i`; but this can be done offline and much later
|
||||
and with more expensive security requirements.)
|
||||
|
||||
The message to be signed contains all public keys to prevent a class of attacks
|
||||
centered around choosing keys to match pre-computed signatures. In our proposed
|
||||
use case, whitelisted keys already must be computed before they are signed, and
|
||||
the remaining public keys are verified out-of-band when setting up the system,
|
||||
so there is no direct benefit to this. We do it only to reduce fragility and
|
||||
increase safety of unforeseen uses.
|
||||
|
||||
|
||||
129
src/secp256k1/src/modules/whitelist/whitelist_impl.h
Normal file
129
src/secp256k1/src/modules/whitelist/whitelist_impl.h
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2016 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_WHITELIST_IMPL_H_
|
||||
#define _SECP256K1_WHITELIST_IMPL_H_
|
||||
|
||||
static int secp256k1_whitelist_hash_pubkey(secp256k1_scalar* output, secp256k1_gej* pubkey) {
|
||||
unsigned char h[32];
|
||||
unsigned char c[33];
|
||||
secp256k1_sha256_t sha;
|
||||
int overflow = 0;
|
||||
size_t size = 33;
|
||||
secp256k1_ge ge;
|
||||
|
||||
secp256k1_ge_set_gej(&ge, pubkey);
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
if (!secp256k1_eckey_pubkey_serialize(&ge, c, &size, SECP256K1_EC_COMPRESSED)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_write(&sha, c, size);
|
||||
secp256k1_sha256_finalize(&sha, h);
|
||||
|
||||
secp256k1_scalar_set_b32(output, h, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(output)) {
|
||||
/* This return path is mathematically impossible to hit */
|
||||
secp256k1_scalar_clear(output);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_whitelist_tweak_pubkey(const secp256k1_context* ctx, secp256k1_gej* pub_tweaked) {
|
||||
secp256k1_scalar tweak;
|
||||
secp256k1_scalar zero;
|
||||
int ret;
|
||||
|
||||
secp256k1_scalar_set_int(&zero, 0);
|
||||
|
||||
ret = secp256k1_whitelist_hash_pubkey(&tweak, pub_tweaked);
|
||||
if (ret) {
|
||||
secp256k1_ecmult(&ctx->ecmult_ctx, pub_tweaked, pub_tweaked, &tweak, &zero);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int secp256k1_whitelist_compute_tweaked_privkey(const secp256k1_context* ctx, secp256k1_scalar* skey, const unsigned char *online_key, const unsigned char *summed_key) {
|
||||
secp256k1_scalar tweak;
|
||||
int ret = 1;
|
||||
int overflow = 0;
|
||||
|
||||
secp256k1_scalar_set_b32(skey, summed_key, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(skey)) {
|
||||
ret = 0;
|
||||
}
|
||||
if (ret) {
|
||||
secp256k1_gej pkeyj;
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pkeyj, skey);
|
||||
ret = secp256k1_whitelist_hash_pubkey(&tweak, &pkeyj);
|
||||
}
|
||||
if (ret) {
|
||||
secp256k1_scalar sonline;
|
||||
secp256k1_scalar_mul(skey, skey, &tweak);
|
||||
|
||||
secp256k1_scalar_set_b32(&sonline, online_key, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&sonline)) {
|
||||
ret = 0;
|
||||
}
|
||||
secp256k1_scalar_add(skey, skey, &sonline);
|
||||
secp256k1_scalar_clear(&sonline);
|
||||
secp256k1_scalar_clear(&tweak);
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
secp256k1_scalar_clear(skey);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Takes a list of pubkeys and combines them to form the public keys needed
|
||||
* for the ring signature; also produce a commitment to every one that will
|
||||
* be our "message". */
|
||||
static int secp256k1_whitelist_compute_keys_and_message(const secp256k1_context* ctx, unsigned char *msg32, secp256k1_gej *keys, const secp256k1_pubkey *online_pubkeys, const secp256k1_pubkey *offline_pubkeys, const int n_keys, const secp256k1_pubkey *sub_pubkey) {
|
||||
unsigned char c[33];
|
||||
size_t size = 33;
|
||||
secp256k1_sha256_t sha;
|
||||
int i;
|
||||
secp256k1_ge subkey_ge;
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_pubkey_load(ctx, &subkey_ge, sub_pubkey);
|
||||
|
||||
/* commit to sub-key */
|
||||
if (!secp256k1_eckey_pubkey_serialize(&subkey_ge, c, &size, SECP256K1_EC_COMPRESSED)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_write(&sha, c, size);
|
||||
for (i = 0; i < n_keys; i++) {
|
||||
secp256k1_ge offline_ge;
|
||||
secp256k1_ge online_ge;
|
||||
secp256k1_gej tweaked_gej;
|
||||
|
||||
/* commit to fixed keys */
|
||||
secp256k1_pubkey_load(ctx, &offline_ge, &offline_pubkeys[i]);
|
||||
if (!secp256k1_eckey_pubkey_serialize(&offline_ge, c, &size, SECP256K1_EC_COMPRESSED)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_write(&sha, c, size);
|
||||
secp256k1_pubkey_load(ctx, &online_ge, &online_pubkeys[i]);
|
||||
if (!secp256k1_eckey_pubkey_serialize(&online_ge, c, &size, SECP256K1_EC_COMPRESSED)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_write(&sha, c, size);
|
||||
|
||||
/* compute tweaked keys */
|
||||
secp256k1_gej_set_ge(&tweaked_gej, &offline_ge);
|
||||
secp256k1_gej_add_ge_var(&tweaked_gej, &tweaked_gej, &subkey_ge, NULL);
|
||||
secp256k1_whitelist_tweak_pubkey(ctx, &tweaked_gej);
|
||||
secp256k1_gej_add_ge_var(&keys[i], &tweaked_gej, &online_ge, NULL);
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha, msg32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -38,6 +38,9 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b
|
|||
/** Set a scalar to an unsigned integer. */
|
||||
static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v);
|
||||
|
||||
/** Set a scalar to an unsigned 64-bit integer */
|
||||
static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint64_t v);
|
||||
|
||||
/** Convert a scalar to a byte array. */
|
||||
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_
|
||||
#define _SECP256K1_SCALAR_REPR_IMPL_H_
|
||||
|
||||
#include "scalar.h"
|
||||
|
||||
/* Limbs of the secp256k1 order. */
|
||||
#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL)
|
||||
#define SECP256K1_N_1 ((uint64_t)0xBAAEDCE6AF48A03BULL)
|
||||
|
|
@ -38,6 +40,13 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig
|
|||
r->d[3] = 0;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint64_t v) {
|
||||
r->d[0] = v;
|
||||
r->d[1] = 0;
|
||||
r->d[2] = 0;
|
||||
r->d[3] = 0;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
|
||||
VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6);
|
||||
return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1);
|
||||
|
|
|
|||
|
|
@ -56,6 +56,17 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig
|
|||
r->d[7] = 0;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint64_t v) {
|
||||
r->d[0] = v;
|
||||
r->d[1] = v >> 32;
|
||||
r->d[2] = 0;
|
||||
r->d[3] = 0;
|
||||
r->d[4] = 0;
|
||||
r->d[5] = 0;
|
||||
r->d[6] = 0;
|
||||
r->d[7] = 0;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
|
||||
VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5);
|
||||
return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a)
|
|||
|
||||
SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; }
|
||||
SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; }
|
||||
SECP256K1_INLINE static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint64_t v) { *r = v % EXHAUSTIVE_TEST_ORDER; }
|
||||
|
||||
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
|
||||
if (offset < 32)
|
||||
|
|
|
|||
40
src/secp256k1/src/secp256k1.c
Executable file → Normal file
40
src/secp256k1/src/secp256k1.c
Executable file → Normal file
|
|
@ -18,7 +18,12 @@
|
|||
#include "eckey_impl.h"
|
||||
#include "hash_impl.h"
|
||||
|
||||
#ifdef ENABLE_MODULE_GENERATOR
|
||||
# include "include/secp256k1_generator.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_RANGEPROOF
|
||||
# include "include/secp256k1_rangeproof.h"
|
||||
# include "modules/rangeproof/pedersen.h"
|
||||
# include "modules/rangeproof/rangeproof.h"
|
||||
#endif
|
||||
|
|
@ -56,10 +61,6 @@ static const secp256k1_callback default_error_callback = {
|
|||
struct secp256k1_context_struct {
|
||||
secp256k1_ecmult_context ecmult_ctx;
|
||||
secp256k1_ecmult_gen_context ecmult_gen_ctx;
|
||||
#ifdef ENABLE_MODULE_RANGEPROOF
|
||||
secp256k1_pedersen_context pedersen_ctx;
|
||||
secp256k1_rangeproof_context rangeproof_ctx;
|
||||
#endif
|
||||
secp256k1_callback illegal_callback;
|
||||
secp256k1_callback error_callback;
|
||||
};
|
||||
|
|
@ -78,10 +79,6 @@ secp256k1_context* secp256k1_context_create(unsigned int flags) {
|
|||
|
||||
secp256k1_ecmult_context_init(&ret->ecmult_ctx);
|
||||
secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx);
|
||||
#ifdef ENABLE_MODULE_RANGEPROOF
|
||||
secp256k1_pedersen_context_init(&ret->pedersen_ctx);
|
||||
secp256k1_rangeproof_context_init(&ret->rangeproof_ctx);
|
||||
#endif
|
||||
|
||||
if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) {
|
||||
secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback);
|
||||
|
|
@ -99,10 +96,6 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
|
|||
ret->error_callback = ctx->error_callback;
|
||||
secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx, &ctx->error_callback);
|
||||
secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx, &ctx->error_callback);
|
||||
#ifdef ENABLE_MODULE_RANGEPROOF
|
||||
secp256k1_pedersen_context_clone(&ret->pedersen_ctx, &ctx->pedersen_ctx, &ctx->error_callback);
|
||||
secp256k1_rangeproof_context_clone(&ret->rangeproof_ctx, &ctx->rangeproof_ctx, &ctx->error_callback);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -110,10 +103,6 @@ void secp256k1_context_destroy(secp256k1_context* ctx) {
|
|||
if (ctx != NULL) {
|
||||
secp256k1_ecmult_context_clear(&ctx->ecmult_ctx);
|
||||
secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
|
||||
#ifdef ENABLE_MODULE_RANGEPROOF
|
||||
secp256k1_pedersen_context_clear(&ctx->pedersen_ctx);
|
||||
secp256k1_rangeproof_context_clear(&ctx->rangeproof_ctx);
|
||||
#endif
|
||||
|
||||
free(ctx);
|
||||
}
|
||||
|
|
@ -464,8 +453,11 @@ int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *p
|
|||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
ret = secp256k1_pubkey_load(ctx, &p, pubkey);
|
||||
secp256k1_ge_neg(&p, &p);
|
||||
secp256k1_pubkey_save(pubkey, &p);
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
if (ret) {
|
||||
secp256k1_ge_neg(&p, &p);
|
||||
secp256k1_pubkey_save(pubkey, &p);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -605,6 +597,18 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *
|
|||
# include "modules/recovery/main_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_GENERATOR
|
||||
# include "modules/generator/main_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_RANGEPROOF
|
||||
# include "modules/rangeproof/main_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_WHITELIST
|
||||
# include "modules/whitelist/main_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_SURJECTIONPROOF
|
||||
# include "modules/surjection/main_impl.h"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ void run_util_tests(void) {
|
|||
|
||||
void run_context_tests(void) {
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_pubkey zero_pubkey;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
unsigned char ctmp[32];
|
||||
int32_t ecount;
|
||||
|
|
@ -196,6 +197,8 @@ void run_context_tests(void) {
|
|||
secp256k1_scalar msg, key, nonce;
|
||||
secp256k1_scalar sigr, sigs;
|
||||
|
||||
memset(&zero_pubkey, 0, sizeof(zero_pubkey));
|
||||
|
||||
ecount = 0;
|
||||
ecount2 = 10;
|
||||
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
|
||||
|
|
@ -248,12 +251,20 @@ void run_context_tests(void) {
|
|||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 0);
|
||||
CHECK(ecount2 == 13);
|
||||
CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_negate(vrfy, &pubkey) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0);
|
||||
CHECK(secp256k1_ec_pubkey_negate(sign, &pubkey) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ec_pubkey_negate(sign, NULL) == 0);
|
||||
CHECK(ecount2 == 14);
|
||||
CHECK(secp256k1_ec_pubkey_negate(vrfy, &zero_pubkey) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_context_randomize(sign, NULL) == 1);
|
||||
CHECK(ecount2 == 13);
|
||||
CHECK(ecount2 == 14);
|
||||
secp256k1_context_set_illegal_callback(vrfy, NULL, NULL);
|
||||
secp256k1_context_set_illegal_callback(sign, NULL, NULL);
|
||||
|
||||
|
|
@ -1926,9 +1937,9 @@ void test_ge(void) {
|
|||
*
|
||||
* When the endomorphism code is compiled in, p5 = lambda*p1 and p6 = lambda^2*p1 are added as well.
|
||||
*/
|
||||
secp256k1_ge *ge = (secp256k1_ge *)malloc(sizeof(secp256k1_ge) * (1 + 4 * runs));
|
||||
secp256k1_gej *gej = (secp256k1_gej *)malloc(sizeof(secp256k1_gej) * (1 + 4 * runs));
|
||||
secp256k1_fe *zinv = (secp256k1_fe *)malloc(sizeof(secp256k1_fe) * (1 + 4 * runs));
|
||||
secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs));
|
||||
secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs));
|
||||
secp256k1_fe *zinv = (secp256k1_fe *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_fe) * (1 + 4 * runs));
|
||||
secp256k1_fe zf;
|
||||
secp256k1_fe zfi2, zfi3;
|
||||
|
||||
|
|
@ -1966,7 +1977,7 @@ void test_ge(void) {
|
|||
|
||||
/* Compute z inverses. */
|
||||
{
|
||||
secp256k1_fe *zs = malloc(sizeof(secp256k1_fe) * (1 + 4 * runs));
|
||||
secp256k1_fe *zs = checked_malloc(&ctx->error_callback, sizeof(secp256k1_fe) * (1 + 4 * runs));
|
||||
for (i = 0; i < 4 * runs + 1; i++) {
|
||||
if (i == 0) {
|
||||
/* The point at infinity does not have a meaningful z inverse. Any should do. */
|
||||
|
|
@ -2067,7 +2078,7 @@ void test_ge(void) {
|
|||
/* Test adding all points together in random order equals infinity. */
|
||||
{
|
||||
secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY;
|
||||
secp256k1_gej *gej_shuffled = (secp256k1_gej *)malloc((4 * runs + 1) * sizeof(secp256k1_gej));
|
||||
secp256k1_gej *gej_shuffled = (secp256k1_gej *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_gej));
|
||||
for (i = 0; i < 4 * runs + 1; i++) {
|
||||
gej_shuffled[i] = gej[i];
|
||||
}
|
||||
|
|
@ -2088,9 +2099,9 @@ void test_ge(void) {
|
|||
|
||||
/* Test batch gej -> ge conversion with and without known z ratios. */
|
||||
{
|
||||
secp256k1_fe *zr = (secp256k1_fe *)malloc((4 * runs + 1) * sizeof(secp256k1_fe));
|
||||
secp256k1_ge *ge_set_table = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge));
|
||||
secp256k1_ge *ge_set_all = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge));
|
||||
secp256k1_fe *zr = (secp256k1_fe *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_fe));
|
||||
secp256k1_ge *ge_set_table = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge));
|
||||
secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge));
|
||||
for (i = 0; i < 4 * runs + 1; i++) {
|
||||
/* Compute gej[i + 1].z / gez[i].z (with gej[n].z taken to be 1). */
|
||||
if (i < 4 * runs) {
|
||||
|
|
@ -2440,7 +2451,7 @@ void ecmult_const_random_mult(void) {
|
|||
0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956
|
||||
);
|
||||
secp256k1_gej b;
|
||||
secp256k1_ecmult_const(&b, &a, &xn);
|
||||
secp256k1_ecmult_const(&b, &a, &xn, 256);
|
||||
|
||||
CHECK(secp256k1_ge_is_valid_var(&a));
|
||||
ge_equals_gej(&expected_b, &b);
|
||||
|
|
@ -2456,12 +2467,12 @@ void ecmult_const_commutativity(void) {
|
|||
random_scalar_order_test(&a);
|
||||
random_scalar_order_test(&b);
|
||||
|
||||
secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a);
|
||||
secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b);
|
||||
secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a, 256);
|
||||
secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b, 256);
|
||||
secp256k1_ge_set_gej(&mid1, &res1);
|
||||
secp256k1_ge_set_gej(&mid2, &res2);
|
||||
secp256k1_ecmult_const(&res1, &mid1, &b);
|
||||
secp256k1_ecmult_const(&res2, &mid2, &a);
|
||||
secp256k1_ecmult_const(&res1, &mid1, &b, 256);
|
||||
secp256k1_ecmult_const(&res2, &mid2, &a, 256);
|
||||
secp256k1_ge_set_gej(&mid1, &res1);
|
||||
secp256k1_ge_set_gej(&mid2, &res2);
|
||||
ge_equals_ge(&mid1, &mid2);
|
||||
|
|
@ -2477,13 +2488,13 @@ void ecmult_const_mult_zero_one(void) {
|
|||
secp256k1_scalar_negate(&negone, &one);
|
||||
|
||||
random_group_element_test(&point);
|
||||
secp256k1_ecmult_const(&res1, &point, &zero);
|
||||
secp256k1_ecmult_const(&res1, &point, &zero, 3);
|
||||
secp256k1_ge_set_gej(&res2, &res1);
|
||||
CHECK(secp256k1_ge_is_infinity(&res2));
|
||||
secp256k1_ecmult_const(&res1, &point, &one);
|
||||
secp256k1_ecmult_const(&res1, &point, &one, 2);
|
||||
secp256k1_ge_set_gej(&res2, &res1);
|
||||
ge_equals_ge(&res2, &point);
|
||||
secp256k1_ecmult_const(&res1, &point, &negone);
|
||||
secp256k1_ecmult_const(&res1, &point, &negone, 256);
|
||||
secp256k1_gej_neg(&res1, &res1);
|
||||
secp256k1_ge_set_gej(&res2, &res1);
|
||||
ge_equals_ge(&res2, &point);
|
||||
|
|
@ -2509,7 +2520,7 @@ void ecmult_const_chain_multiply(void) {
|
|||
for (i = 0; i < 100; ++i) {
|
||||
secp256k1_ge tmp;
|
||||
secp256k1_ge_set_gej(&tmp, &point);
|
||||
secp256k1_ecmult_const(&point, &tmp, &scalar);
|
||||
secp256k1_ecmult_const(&point, &tmp, &scalar, 256);
|
||||
}
|
||||
secp256k1_ge_set_gej(&res, &point);
|
||||
ge_equals_gej(&res, &expected_point);
|
||||
|
|
@ -2576,6 +2587,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
|
|||
int wnaf[256] = {0};
|
||||
int i;
|
||||
int skew;
|
||||
int bits = 256;
|
||||
secp256k1_scalar num = *number;
|
||||
|
||||
secp256k1_scalar_set_int(&x, 0);
|
||||
|
|
@ -2585,10 +2597,11 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
|
|||
for (i = 0; i < 16; ++i) {
|
||||
secp256k1_scalar_shr_int(&num, 8);
|
||||
}
|
||||
bits = 128;
|
||||
#endif
|
||||
skew = secp256k1_wnaf_const(wnaf, num, w);
|
||||
skew = secp256k1_wnaf_const(wnaf, num, w, bits, 1);
|
||||
|
||||
for (i = WNAF_SIZE(w); i >= 0; --i) {
|
||||
for (i = WNAF_SIZE(bits, w); i >= 0; --i) {
|
||||
secp256k1_scalar t;
|
||||
int v = wnaf[i];
|
||||
CHECK(v != 0); /* check nonzero */
|
||||
|
|
@ -4446,10 +4459,22 @@ void run_ecdsa_openssl(void) {
|
|||
# include "modules/recovery/tests_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_GENERATOR
|
||||
# include "modules/generator/tests_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_RANGEPROOF
|
||||
# include "modules/rangeproof/tests_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_WHITELIST
|
||||
# include "modules/whitelist/tests_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_SURJECTIONPROOF
|
||||
# include "modules/surjection/tests_impl.h"
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
unsigned char seed16[16] = {0};
|
||||
unsigned char run32[32] = {0};
|
||||
|
|
@ -4574,10 +4599,23 @@ int main(int argc, char **argv) {
|
|||
run_recovery_tests();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_GENERATOR
|
||||
run_generator_tests();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_RANGEPROOF
|
||||
run_rangeproof_tests();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_WHITELIST
|
||||
/* Key whitelisting tests */
|
||||
run_whitelist_tests();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_SURJECTIONPROOF
|
||||
run_surjection_tests();
|
||||
#endif
|
||||
|
||||
secp256k1_rand256(run32);
|
||||
printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,11 @@
|
|||
#include "secp256k1.c"
|
||||
#include "testrand_impl.h"
|
||||
|
||||
#ifdef ENABLE_MODULE_RECOVERY
|
||||
#include "src/modules/recovery/main_impl.h"
|
||||
#include "include/secp256k1_recovery.h"
|
||||
#endif
|
||||
|
||||
/** stolen from tests.c */
|
||||
void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
|
||||
CHECK(a->infinity == b->infinity);
|
||||
|
|
@ -77,7 +82,7 @@ int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned cha
|
|||
* function with an increased `attempt`. So if attempt > 0 this means we
|
||||
* need to change the nonce to avoid an infinite loop. */
|
||||
if (attempt > 0) {
|
||||
(*idata)++;
|
||||
*idata = (*idata + 1) % EXHAUSTIVE_TEST_ORDER;
|
||||
}
|
||||
secp256k1_scalar_set_int(&s, *idata);
|
||||
secp256k1_scalar_get_b32(nonce32, &s);
|
||||
|
|
@ -169,7 +174,7 @@ void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *gr
|
|||
ge_equals_gej(&group[(i * r_log + j) % order], &tmp);
|
||||
|
||||
if (i > 0) {
|
||||
secp256k1_ecmult_const(&tmp, &group[i], &ng);
|
||||
secp256k1_ecmult_const(&tmp, &group[i], &ng, 256);
|
||||
ge_equals_gej(&group[(i * j) % order], &tmp);
|
||||
}
|
||||
}
|
||||
|
|
@ -244,6 +249,7 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou
|
|||
for (i = 1; i < order; i++) { /* message */
|
||||
for (j = 1; j < order; j++) { /* key */
|
||||
for (k = 1; k < order; k++) { /* nonce */
|
||||
const int starting_k = k;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
secp256k1_scalar sk, msg, r, s, expected_r;
|
||||
unsigned char sk32[32], msg32[32];
|
||||
|
|
@ -262,6 +268,11 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou
|
|||
CHECK(r == expected_r);
|
||||
CHECK((k * s) % order == (i + r * j) % order ||
|
||||
(k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order);
|
||||
|
||||
/* Overflow means we've tried every possible nonce */
|
||||
if (k < starting_k) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -276,6 +287,130 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou
|
|||
*/
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MODULE_RECOVERY
|
||||
void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {
|
||||
int i, j, k;
|
||||
|
||||
/* Loop */
|
||||
for (i = 1; i < order; i++) { /* message */
|
||||
for (j = 1; j < order; j++) { /* key */
|
||||
for (k = 1; k < order; k++) { /* nonce */
|
||||
const int starting_k = k;
|
||||
secp256k1_fe r_dot_y_normalized;
|
||||
secp256k1_ecdsa_recoverable_signature rsig;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
secp256k1_scalar sk, msg, r, s, expected_r;
|
||||
unsigned char sk32[32], msg32[32];
|
||||
int expected_recid;
|
||||
int recid;
|
||||
secp256k1_scalar_set_int(&msg, i);
|
||||
secp256k1_scalar_set_int(&sk, j);
|
||||
secp256k1_scalar_get_b32(sk32, &sk);
|
||||
secp256k1_scalar_get_b32(msg32, &msg);
|
||||
|
||||
secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k);
|
||||
|
||||
/* Check directly */
|
||||
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig);
|
||||
r_from_k(&expected_r, group, k);
|
||||
CHECK(r == expected_r);
|
||||
CHECK((k * s) % order == (i + r * j) % order ||
|
||||
(k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order);
|
||||
/* In computing the recid, there is an overflow condition that is disabled in
|
||||
* scalar_low_impl.h `secp256k1_scalar_set_b32` because almost every r.y value
|
||||
* will exceed the group order, and our signing code always holds out for r
|
||||
* values that don't overflow, so with a proper overflow check the tests would
|
||||
* loop indefinitely. */
|
||||
r_dot_y_normalized = group[k].y;
|
||||
secp256k1_fe_normalize(&r_dot_y_normalized);
|
||||
/* Also the recovery id is flipped depending if we hit the low-s branch */
|
||||
if ((k * s) % order == (i + r * j) % order) {
|
||||
expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 1 : 0;
|
||||
} else {
|
||||
expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 0 : 1;
|
||||
}
|
||||
CHECK(recid == expected_recid);
|
||||
|
||||
/* Convert to a standard sig then check */
|
||||
secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);
|
||||
secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig);
|
||||
/* Note that we compute expected_r *after* signing -- this is important
|
||||
* because our nonce-computing function function might change k during
|
||||
* signing. */
|
||||
r_from_k(&expected_r, group, k);
|
||||
CHECK(r == expected_r);
|
||||
CHECK((k * s) % order == (i + r * j) % order ||
|
||||
(k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order);
|
||||
|
||||
/* Overflow means we've tried every possible nonce */
|
||||
if (k < starting_k) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {
|
||||
/* This is essentially a copy of test_exhaustive_verify, with recovery added */
|
||||
int s, r, msg, key;
|
||||
for (s = 1; s < order; s++) {
|
||||
for (r = 1; r < order; r++) {
|
||||
for (msg = 1; msg < order; msg++) {
|
||||
for (key = 1; key < order; key++) {
|
||||
secp256k1_ge nonconst_ge;
|
||||
secp256k1_ecdsa_recoverable_signature rsig;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
secp256k1_pubkey pk;
|
||||
secp256k1_scalar sk_s, msg_s, r_s, s_s;
|
||||
secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s;
|
||||
int recid = 0;
|
||||
int k, should_verify;
|
||||
unsigned char msg32[32];
|
||||
|
||||
secp256k1_scalar_set_int(&s_s, s);
|
||||
secp256k1_scalar_set_int(&r_s, r);
|
||||
secp256k1_scalar_set_int(&msg_s, msg);
|
||||
secp256k1_scalar_set_int(&sk_s, key);
|
||||
secp256k1_scalar_get_b32(msg32, &msg_s);
|
||||
|
||||
/* Verify by hand */
|
||||
/* Run through every k value that gives us this r and check that *one* works.
|
||||
* Note there could be none, there could be multiple, ECDSA is weird. */
|
||||
should_verify = 0;
|
||||
for (k = 0; k < order; k++) {
|
||||
secp256k1_scalar check_x_s;
|
||||
r_from_k(&check_x_s, group, k);
|
||||
if (r_s == check_x_s) {
|
||||
secp256k1_scalar_set_int(&s_times_k_s, k);
|
||||
secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s);
|
||||
secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s);
|
||||
secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s);
|
||||
should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s);
|
||||
}
|
||||
}
|
||||
/* nb we have a "high s" rule */
|
||||
should_verify &= !secp256k1_scalar_is_high(&s_s);
|
||||
|
||||
/* We would like to try recovering the pubkey and checking that it matches,
|
||||
* but pubkey recovery is impossible in the exhaustive tests (the reason
|
||||
* being that there are 12 nonzero r values, 12 nonzero points, and no
|
||||
* overlap between the sets, so there are no valid signatures). */
|
||||
|
||||
/* Verify by converting to a standard signature and calling verify */
|
||||
secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid);
|
||||
secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);
|
||||
memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge));
|
||||
secp256k1_pubkey_save(&pk, &nonconst_ge);
|
||||
CHECK(should_verify ==
|
||||
secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(void) {
|
||||
int i;
|
||||
secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER];
|
||||
|
|
@ -324,6 +459,12 @@ int main(void) {
|
|||
test_exhaustive_sign(ctx, group, EXHAUSTIVE_TEST_ORDER);
|
||||
test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER);
|
||||
|
||||
#ifdef ENABLE_MODULE_RECOVERY
|
||||
test_exhaustive_recovery_sign(ctx, group, EXHAUSTIVE_TEST_ORDER);
|
||||
test_exhaustive_recovery_verify(ctx, group, EXHAUSTIVE_TEST_ORDER);
|
||||
#endif
|
||||
|
||||
secp256k1_context_destroy(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,10 @@ static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback *
|
|||
#endif
|
||||
|
||||
/* Like assert(), but when VERIFY is defined, and side-effect safe. */
|
||||
#ifdef VERIFY
|
||||
#if defined(COVERAGE)
|
||||
#define VERIFY_CHECK(check)
|
||||
#define VERIFY_SETUP(stmt)
|
||||
#elif defined(VERIFY)
|
||||
#define VERIFY_CHECK CHECK
|
||||
#define VERIFY_SETUP(stmt) do { stmt; } while(0)
|
||||
#else
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue