mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-16 13:01:19 +02:00
Update libsecp (TODO: Do this via subtree)
This commit is contained in:
parent
b5f1b6dd38
commit
ab892c2143
18 changed files with 2041 additions and 3 deletions
|
|
@ -169,3 +169,7 @@ endif
|
|||
if ENABLE_MODULE_RECOVERY
|
||||
include src/modules/recovery/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_RANGEPROOF
|
||||
include src/modules/rangeproof/Makefile.am.include
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -129,6 +129,11 @@ AC_ARG_ENABLE(module_recovery,
|
|||
[enable_module_recovery=$enableval],
|
||||
[enable_module_recovery=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(jni,
|
||||
AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]),
|
||||
[use_jni=$enableval],
|
||||
|
|
@ -422,6 +427,10 @@ 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_rangeproof" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_RANGEPROOF, 1, [Define this symbol to enable the Pedersen / zero knowledge range proof module])
|
||||
fi
|
||||
|
||||
AC_C_BIGENDIAN()
|
||||
|
||||
if test x"$use_external_asm" = x"yes"; then
|
||||
|
|
@ -443,14 +452,22 @@ 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 range proof module: $enable_module_rangeproof])
|
||||
AC_MSG_NOTICE([******])
|
||||
else
|
||||
if test x"$enable_module_schnorr" = x"yes"; then
|
||||
AC_MSG_ERROR([Schnorr signature module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_ecdh" = x"yes"; then
|
||||
AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
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_rangeproof" = x"yes"; then
|
||||
AC_MSG_ERROR([Range proof module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
|
||||
|
|
@ -465,8 +482,10 @@ 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_RANGEPROOF], [test x"$enable_module_rangeproof" = 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"])
|
||||
|
||||
|
|
|
|||
186
src/secp256k1/include/secp256k1_rangeproof.h
Normal file
186
src/secp256k1/include/secp256k1_rangeproof.h
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
#ifndef _SECP256K1_RANGEPROOF_
|
||||
# define _SECP256K1_RANGEPROOF_
|
||||
|
||||
# include "secp256k1.h"
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Initialize a context for usage with Pedersen commitments. */
|
||||
void secp256k1_pedersen_context_initialize(secp256k1_context* ctx);
|
||||
|
||||
/** Generate a pedersen commitment.
|
||||
* Returns 1: commitment successfully created.
|
||||
* 0: error
|
||||
* In: ctx: pointer to a context object, initialized for signing and Pedersen commitment (cannot be NULL)
|
||||
* blind: pointer to a 32-byte blinding factor (cannot be NULL)
|
||||
* value: unsigned 64-bit integer value to commit to.
|
||||
* Out: commit: pointer to a 33-byte array for the commitment (cannot be NULL)
|
||||
*
|
||||
* Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA.
|
||||
*/
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *commit,
|
||||
unsigned char *blind,
|
||||
uint64_t value
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Computes the sum of multiple positive and negative blinding factors.
|
||||
* Returns 1: sum successfully computed.
|
||||
* 0: error
|
||||
* In: ctx: pointer to a context object (cannot be NULL)
|
||||
* blinds: pointer to pointers to 32-byte character arrays for blinding factors. (cannot be NULL)
|
||||
* n: number of factors pointed to by blinds.
|
||||
* nneg: how many of the initial factors should be treated with a positive sign.
|
||||
* Out: blind_out: pointer to a 32-byte array for the sum (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *blind_out,
|
||||
const unsigned char * const *blinds,
|
||||
int n,
|
||||
int npositive
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Verify a tally of pedersen commitments
|
||||
* Returns 1: commitments successfully sum to zero.
|
||||
* 0: Commitments do not sum to zero or other error.
|
||||
* In: ctx: pointer to a context object, initialized for Pedersen commitment (cannot be NULL)
|
||||
* commits: pointer to pointers to 33-byte character arrays for the commitments. (cannot be NULL if pcnt is non-zero)
|
||||
* pcnt: number of commitments pointed to by commits.
|
||||
* ncommits: pointer to pointers to 33-byte character arrays for negative commitments. (cannot be NULL if ncnt is non-zero)
|
||||
* ncnt: number of commitments pointed to by ncommits.
|
||||
* excess: signed 64bit amount to add to the total to bring it to zero, can be negative.
|
||||
*
|
||||
* This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) - excess*H == 0.
|
||||
*
|
||||
* A pedersen commitment is xG + vH where G and H are generators for the secp256k1 group and x is a blinding factor,
|
||||
* while v is the committed value. For a collection of commitments to sum to zero both their blinding factors and
|
||||
* values must sum to zero.
|
||||
*
|
||||
*/
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
|
||||
const secp256k1_context* ctx,
|
||||
const unsigned char * const *commits,
|
||||
int pcnt,
|
||||
const unsigned char * const *ncommits,
|
||||
int ncnt,
|
||||
int64_t excess
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Initialize a context for usage with Pedersen commitments. */
|
||||
void secp256k1_rangeproof_context_initialize(secp256k1_context* ctx);
|
||||
|
||||
/** Verify a proof that a committed value is within a range.
|
||||
* Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs.
|
||||
* 0: Proof failed or other error.
|
||||
* In: ctx: pointer to a context object, initialized for range-proof and commitment (cannot be NULL)
|
||||
* commit: the 33-byte commitment being proved. (cannot be NULL)
|
||||
* proof: pointer to character array with the proof. (cannot be NULL)
|
||||
* plen: length of proof in bytes.
|
||||
* Out: min_value: pointer to a unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL)
|
||||
* max_value: pointer to a unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify(
|
||||
const secp256k1_context* ctx,
|
||||
uint64_t *min_value,
|
||||
uint64_t *max_value,
|
||||
const unsigned char *commit,
|
||||
const unsigned char *proof,
|
||||
int plen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Verify a range proof proof and rewind the proof to recover information sent by its author.
|
||||
* Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs, and the value and blinding were recovered.
|
||||
* 0: Proof failed, rewind failed, or other error.
|
||||
* In: ctx: pointer to a context object, initialized for range-proof and Pedersen commitment (cannot be NULL)
|
||||
* commit: the 33-byte commitment being proved. (cannot be NULL)
|
||||
* proof: pointer to character array with the proof. (cannot be NULL)
|
||||
* plen: length of proof in bytes.
|
||||
* nonce: 32-byte secret nonce used by the prover (cannot be NULL)
|
||||
* In/Out: blind_out: storage for the 32-byte blinding factor used for the commitment
|
||||
* value_out: pointer to an unsigned int64 which has the exact value of the commitment.
|
||||
* message_out: pointer to a 4096 byte character array to receive message data from the proof author.
|
||||
* outlen: length of message data written to message_out.
|
||||
* min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL)
|
||||
* max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *blind_out,
|
||||
uint64_t *value_out,
|
||||
unsigned char *message_out,
|
||||
int *outlen,
|
||||
const unsigned char *nonce,
|
||||
uint64_t *min_value,
|
||||
uint64_t *max_value,
|
||||
const unsigned char *commit,
|
||||
const unsigned char *proof,
|
||||
int plen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(9) SECP256K1_ARG_NONNULL(10);
|
||||
|
||||
/** Author a proof that a committed value is within a range.
|
||||
* Returns 1: Proof successfully created.
|
||||
* 0: Error
|
||||
* In: ctx: pointer to a context object, initialized for range-proof, signing, and Pedersen commitment (cannot be NULL)
|
||||
* proof: pointer to array to receive the proof, can be up to 5134 bytes. (cannot be NULL)
|
||||
* min_value: constructs a proof where the verifer can tell the minimum value is at least the specified amount.
|
||||
* commit: 33-byte array with the commitment being proved.
|
||||
* blind: 32-byte blinding factor used by commit.
|
||||
* nonce: 32-byte secret nonce used to initialize the proof (value can be reverse-engineered out of the proof if this secret is known.)
|
||||
* exp: Base-10 exponent. Digits below above will be made public, but the proof will be made smaller. Allowed range is -1 to 18.
|
||||
* (-1 is a special case that makes the value public. 0 is the most private.)
|
||||
* min_bits: Number of bits of the value to keep private. (0 = auto/minimal, - 64).
|
||||
* value: Actual value of the commitment.
|
||||
* In/out: plen: point to an integer with the size of the proof buffer and the size of the constructed proof.
|
||||
*
|
||||
* If min_value or exp is non-zero then the value must be on the range [0, 2^63) to prevent the proof range from spanning past 2^64.
|
||||
*
|
||||
* If exp is -1 the value is revealed by the proof (e.g. it proves that the proof is a blinding of a specific value, without revealing the blinding key.)
|
||||
*
|
||||
* This can randomly fail with probability around one in 2^100. If this happens, buy a lottery ticket and retry with a different nonce or blinding.
|
||||
*
|
||||
*/
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *proof,
|
||||
int *plen,
|
||||
uint64_t min_value,
|
||||
const unsigned char *commit,
|
||||
const unsigned char *blind,
|
||||
const unsigned char *nonce,
|
||||
int exp,
|
||||
int min_bits,
|
||||
uint64_t value
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7);
|
||||
|
||||
/** Extract some basic information from a range-proof.
|
||||
* Returns 1: Information successfully extracted.
|
||||
* 0: Decode failed.
|
||||
* In: ctx: pointer to a context object
|
||||
* proof: pointer to character array with the proof.
|
||||
* plen: length of proof in bytes.
|
||||
* Out: exp: Exponent used in the proof (-1 means the value isn't private).
|
||||
* mantissa: Number of bits covered by the proof.
|
||||
* min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL)
|
||||
* max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_info(
|
||||
const secp256k1_context* ctx,
|
||||
int *exp,
|
||||
int *mantissa,
|
||||
uint64_t *min_value,
|
||||
uint64_t *max_value,
|
||||
const unsigned char *proof,
|
||||
int plen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
65
src/secp256k1/src/bench_rangeproof.c
Normal file
65
src/secp256k1/src/bench_rangeproof.c
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2014, 2015 Pieter Wuille, Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "include/secp256k1_rangeproof.h"
|
||||
#include "util.h"
|
||||
#include "bench.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context* ctx;
|
||||
unsigned char commit[33];
|
||||
unsigned char proof[5134];
|
||||
unsigned char blind[32];
|
||||
int len;
|
||||
int min_bits;
|
||||
uint64_t v;
|
||||
} bench_rangeproof_t;
|
||||
|
||||
static void bench_rangeproof_setup(void* arg) {
|
||||
int i;
|
||||
uint64_t minv;
|
||||
uint64_t maxv;
|
||||
bench_rangeproof_t *data = (bench_rangeproof_t*)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));
|
||||
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));
|
||||
}
|
||||
|
||||
static void bench_rangeproof(void* arg) {
|
||||
int i;
|
||||
bench_rangeproof_t *data = (bench_rangeproof_t*)arg;
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
int j;
|
||||
uint64_t minv;
|
||||
uint64_t maxv;
|
||||
j = secp256k1_rangeproof_verify(data->ctx, &minv, &maxv, data->commit, data->proof, data->len);
|
||||
for (j = 0; j < 4; j++) {
|
||||
data->proof[j + 2 + 32 *((data->min_bits + 1) >> 1) - 4] = (i >> 8)&255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
run_benchmark("rangeproof_verify_bit", bench_rangeproof, bench_rangeproof_setup, NULL, &data, 10, 1000 * data.min_bits);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return 0;
|
||||
}
|
||||
15
src/secp256k1/src/modules/rangeproof/Makefile.am.include
Normal file
15
src/secp256k1/src/modules/rangeproof/Makefile.am.include
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
include_HEADERS += include/secp256k1_rangeproof.h
|
||||
noinst_HEADERS += src/modules/rangeproof/main_impl.h
|
||||
noinst_HEADERS += src/modules/rangeproof/pedersen.h
|
||||
noinst_HEADERS += src/modules/rangeproof/pedersen_impl.h
|
||||
noinst_HEADERS += src/modules/rangeproof/borromean.h
|
||||
noinst_HEADERS += src/modules/rangeproof/borromean_impl.h
|
||||
noinst_HEADERS += src/modules/rangeproof/rangeproof.h
|
||||
noinst_HEADERS += src/modules/rangeproof/rangeproof_impl.h
|
||||
noinst_HEADERS += src/modules/rangeproof/tests_impl.h
|
||||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_rangeproof
|
||||
bench_rangeproof_SOURCES = src/bench_rangeproof.c
|
||||
bench_rangeproof_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
bench_rangeproof_LDFLAGS = -static
|
||||
endif
|
||||
24
src/secp256k1/src/modules/rangeproof/borromean.h
Normal file
24
src/secp256k1/src/modules/rangeproof/borromean.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2014, 2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef _SECP256K1_BORROMEAN_H_
|
||||
#define _SECP256K1_BORROMEAN_H_
|
||||
|
||||
#include "scalar.h"
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
#include "ecmult.h"
|
||||
#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);
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
||||
201
src/secp256k1/src/modules/rangeproof/borromean_impl.h
Normal file
201
src/secp256k1/src/modules/rangeproof/borromean_impl.h
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2014, 2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef _SECP256K1_BORROMEAN_IMPL_H_
|
||||
#define _SECP256K1_BORROMEAN_IMPL_H_
|
||||
|
||||
#include "scalar.h"
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
#include "ecmult.h"
|
||||
#include "ecmult_gen.h"
|
||||
#include "borromean.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define BE32(x) (x)
|
||||
#else
|
||||
#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) {
|
||||
uint32_t ring;
|
||||
uint32_t epos;
|
||||
secp256k1_sha256_t sha256_en;
|
||||
secp256k1_sha256_initialize(&sha256_en);
|
||||
ring = BE32((uint32_t)ridx);
|
||||
epos = BE32((uint32_t)eidx);
|
||||
secp256k1_sha256_write(&sha256_en, e, elen);
|
||||
secp256k1_sha256_write(&sha256_en, m, mlen);
|
||||
secp256k1_sha256_write(&sha256_en, (unsigned char*)&ring, 4);
|
||||
secp256k1_sha256_write(&sha256_en, (unsigned char*)&epos, 4);
|
||||
secp256k1_sha256_finalize(&sha256_en, hash);
|
||||
}
|
||||
|
||||
/** "Borromean" ring signature.
|
||||
* Verifies nrings concurrent ring signatures all sharing a challenge value.
|
||||
* Signature is one s value per pubkey and a hash.
|
||||
* Verification equation:
|
||||
* | m = H(P_{0..}||message) (Message must contain pubkeys or a pubkey commitment)
|
||||
* | For each ring i:
|
||||
* | | en = to_scalar(H(e0||m||i||0))
|
||||
* | | For each pubkey j:
|
||||
* | | | r = s_i_j G + en * P_i_j
|
||||
* | | | e = H(r||m||i||j)
|
||||
* | | | en = to_scalar(e)
|
||||
* | | r_i = r
|
||||
* | 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) {
|
||||
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 size;
|
||||
int overflow;
|
||||
VERIFY_CHECK(ecmult_ctx != NULL);
|
||||
VERIFY_CHECK(e0 != NULL);
|
||||
VERIFY_CHECK(s != NULL);
|
||||
VERIFY_CHECK(pubs != NULL);
|
||||
VERIFY_CHECK(rsizes != NULL);
|
||||
VERIFY_CHECK(nrings > 0);
|
||||
VERIFY_CHECK(m != NULL);
|
||||
count = 0;
|
||||
secp256k1_sha256_initialize(&sha256_e0);
|
||||
for (i = 0; i < nrings; i++) {
|
||||
VERIFY_CHECK(INT_MAX - count > rsizes[i]);
|
||||
secp256k1_borromean_hash(tmp, m, mlen, e0, 32, i, 0);
|
||||
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
|
||||
for (j = 0; j < rsizes[i]; j++) {
|
||||
if (overflow || secp256k1_scalar_is_zero(&s[count]) || secp256k1_scalar_is_zero(&ens) || secp256k1_gej_is_infinity(&pubs[count])) {
|
||||
return 0;
|
||||
}
|
||||
if (evalues) {
|
||||
/*If requested, save the challenges for proof rewind.*/
|
||||
evalues[count] = ens;
|
||||
}
|
||||
secp256k1_ecmult(ecmult_ctx, &rgej, &pubs[count], &ens, &s[count]);
|
||||
if (secp256k1_gej_is_infinity(&rgej)) {
|
||||
return 0;
|
||||
}
|
||||
/* OPT: loop can be hoisted and split to use batch inversion across all the rings; this would make it much faster. */
|
||||
secp256k1_ge_set_gej_var(&rge, &rgej);
|
||||
secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1);
|
||||
if (j != rsizes[i] - 1) {
|
||||
secp256k1_borromean_hash(tmp, m, mlen, tmp, 33, i, j + 1);
|
||||
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
|
||||
} else {
|
||||
secp256k1_sha256_write(&sha256_e0, tmp, size);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
secp256k1_sha256_write(&sha256_e0, m, mlen);
|
||||
secp256k1_sha256_finalize(&sha256_e0, tmp);
|
||||
return memcmp(e0, tmp, 32) == 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
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 size;
|
||||
int overflow;
|
||||
VERIFY_CHECK(ecmult_ctx != NULL);
|
||||
VERIFY_CHECK(ecmult_gen_ctx != NULL);
|
||||
VERIFY_CHECK(e0 != NULL);
|
||||
VERIFY_CHECK(s != NULL);
|
||||
VERIFY_CHECK(pubs != NULL);
|
||||
VERIFY_CHECK(k != NULL);
|
||||
VERIFY_CHECK(sec != NULL);
|
||||
VERIFY_CHECK(rsizes != NULL);
|
||||
VERIFY_CHECK(secidx != NULL);
|
||||
VERIFY_CHECK(nrings > 0);
|
||||
VERIFY_CHECK(m != NULL);
|
||||
secp256k1_sha256_initialize(&sha256_e0);
|
||||
count = 0;
|
||||
for (i = 0; i < nrings; i++) {
|
||||
VERIFY_CHECK(INT_MAX - count > rsizes[i]);
|
||||
secp256k1_ecmult_gen(ecmult_gen_ctx, &rgej, &k[i]);
|
||||
secp256k1_ge_set_gej(&rge, &rgej);
|
||||
if (secp256k1_gej_is_infinity(&rgej)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1);
|
||||
for (j = secidx[i] + 1; j < rsizes[i]; j++) {
|
||||
secp256k1_borromean_hash(tmp, m, mlen, tmp, 33, i, j);
|
||||
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&ens)) {
|
||||
return 0;
|
||||
}
|
||||
/** The signing algorithm as a whole is not memory uniform so there is likely a cache sidechannel that
|
||||
* leaks which members are non-forgeries. That the forgeries themselves are variable time may leave
|
||||
* an additional privacy impacting timing side-channel, but not a key loss one.
|
||||
*/
|
||||
secp256k1_ecmult(ecmult_ctx, &rgej, &pubs[count + j], &ens, &s[count + j]);
|
||||
if (secp256k1_gej_is_infinity(&rgej)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej_var(&rge, &rgej);
|
||||
secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1);
|
||||
}
|
||||
secp256k1_sha256_write(&sha256_e0, tmp, size);
|
||||
count += rsizes[i];
|
||||
}
|
||||
secp256k1_sha256_write(&sha256_e0, m, mlen);
|
||||
secp256k1_sha256_finalize(&sha256_e0, e0);
|
||||
count = 0;
|
||||
for (i = 0; i < nrings; i++) {
|
||||
VERIFY_CHECK(INT_MAX - count > rsizes[i]);
|
||||
secp256k1_borromean_hash(tmp, m, mlen, e0, 32, i, 0);
|
||||
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&ens)) {
|
||||
return 0;
|
||||
}
|
||||
for (j = 0; j < secidx[i]; j++) {
|
||||
secp256k1_ecmult(ecmult_ctx, &rgej, &pubs[count + j], &ens, &s[count + j]);
|
||||
if (secp256k1_gej_is_infinity(&rgej)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej_var(&rge, &rgej);
|
||||
secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1);
|
||||
secp256k1_borromean_hash(tmp, m, mlen, tmp, 33, i, j + 1);
|
||||
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&ens)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
secp256k1_scalar_mul(&s[count + j], &ens, &sec[i]);
|
||||
secp256k1_scalar_negate(&s[count + j], &s[count + j]);
|
||||
secp256k1_scalar_add(&s[count + j], &s[count + j], &k[i]);
|
||||
if (secp256k1_scalar_is_zero(&s[count + j])) {
|
||||
return 0;
|
||||
}
|
||||
count += rsizes[i];
|
||||
}
|
||||
secp256k1_scalar_clear(&ens);
|
||||
secp256k1_ge_clear(&rge);
|
||||
secp256k1_gej_clear(&rgej);
|
||||
memset(tmp, 0, 33);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
176
src/secp256k1/src/modules/rangeproof/main_impl.h
Normal file
176
src/secp256k1/src/modules/rangeproof/main_impl.h
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2014-2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_RANGEPROOF_MAIN
|
||||
#define SECP256K1_MODULE_RANGEPROOF_MAIN
|
||||
|
||||
#include "modules/rangeproof/pedersen_impl.h"
|
||||
#include "modules/rangeproof/borromean_impl.h"
|
||||
#include "modules/rangeproof/rangeproof_impl.h"
|
||||
|
||||
void secp256k1_pedersen_context_initialize(secp256k1_context* ctx) {
|
||||
secp256k1_pedersen_context_build(&ctx->pedersen_ctx, &ctx->error_callback);
|
||||
}
|
||||
|
||||
/* Generates a pedersen commitment: *commit = blind * G + value * G2. The commitment is 33 bytes, the blinding factor is 32 bytes.*/
|
||||
int secp256k1_pedersen_commit(const secp256k1_context* ctx, unsigned char *commit, unsigned char *blind, uint64_t value) {
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge r;
|
||||
secp256k1_scalar sec;
|
||||
size_t sz;
|
||||
int overflow;
|
||||
int ret = 0;
|
||||
ARG_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(secp256k1_pedersen_context_is_built(&ctx->pedersen_ctx));
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(blind != NULL);
|
||||
secp256k1_scalar_set_b32(&sec, blind, &overflow);
|
||||
if (!overflow) {
|
||||
secp256k1_pedersen_ecmult(&ctx->ecmult_gen_ctx, &ctx->pedersen_ctx, &rj, &sec, value);
|
||||
if (!secp256k1_gej_is_infinity(&rj)) {
|
||||
secp256k1_ge_set_gej(&r, &rj);
|
||||
sz = 33;
|
||||
ret = secp256k1_eckey_pubkey_serialize(&r, commit, &sz, 1);
|
||||
}
|
||||
secp256k1_gej_clear(&rj);
|
||||
secp256k1_ge_clear(&r);
|
||||
}
|
||||
secp256k1_scalar_clear(&sec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Takes a list of n pointers to 32 byte blinding values, the first negs of which are treated with positive sign and the rest
|
||||
* negative, then calculates an additional blinding value that adds to zero.
|
||||
*/
|
||||
int secp256k1_pedersen_blind_sum(const secp256k1_context* ctx, unsigned char *blind_out, const unsigned char * const *blinds, int n, int npositive) {
|
||||
secp256k1_scalar acc;
|
||||
secp256k1_scalar x;
|
||||
int i;
|
||||
int overflow;
|
||||
ARG_CHECK(ctx != NULL);
|
||||
ARG_CHECK(blind_out != NULL);
|
||||
ARG_CHECK(blinds != NULL);
|
||||
secp256k1_scalar_set_int(&acc, 0);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_set_b32(&x, blinds[i], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
if (i >= npositive) {
|
||||
secp256k1_scalar_negate(&x, &x);
|
||||
}
|
||||
secp256k1_scalar_add(&acc, &acc, &x);
|
||||
}
|
||||
secp256k1_scalar_get_b32(blind_out, &acc);
|
||||
secp256k1_scalar_clear(&acc);
|
||||
secp256k1_scalar_clear(&x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Takes two list of 33-byte commitments and sums the first set and subtracts the second and verifies that they sum to excess. */
|
||||
int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const unsigned char * const *commits, int pcnt,
|
||||
const unsigned char * const *ncommits, int ncnt, int64_t excess) {
|
||||
secp256k1_gej accj;
|
||||
secp256k1_ge add;
|
||||
int i;
|
||||
ARG_CHECK(ctx != NULL);
|
||||
ARG_CHECK(!pcnt || (commits != NULL));
|
||||
ARG_CHECK(!ncnt || (ncommits != NULL));
|
||||
ARG_CHECK(secp256k1_pedersen_context_is_built(&ctx->pedersen_ctx));
|
||||
secp256k1_gej_set_infinity(&accj);
|
||||
if (excess) {
|
||||
uint64_t ex;
|
||||
int neg;
|
||||
/* Take the absolute value, and negate the result if the input was negative. */
|
||||
neg = secp256k1_sign_and_abs64(&ex, excess);
|
||||
secp256k1_pedersen_ecmult_small(&ctx->pedersen_ctx, &accj, ex);
|
||||
if (neg) {
|
||||
secp256k1_gej_neg(&accj, &accj);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ncnt; i++) {
|
||||
if (!secp256k1_eckey_pubkey_parse(&add, ncommits[i], 33)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL);
|
||||
}
|
||||
secp256k1_gej_neg(&accj, &accj);
|
||||
for (i = 0; i < pcnt; i++) {
|
||||
if (!secp256k1_eckey_pubkey_parse(&add, commits[i], 33)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL);
|
||||
}
|
||||
return secp256k1_gej_is_infinity(&accj);
|
||||
}
|
||||
|
||||
void secp256k1_rangeproof_context_initialize(secp256k1_context* ctx) {
|
||||
secp256k1_rangeproof_context_build(&ctx->rangeproof_ctx, &ctx->error_callback);
|
||||
}
|
||||
|
||||
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 scale;
|
||||
ARG_CHECK(exp != NULL);
|
||||
ARG_CHECK(mantissa != NULL);
|
||||
ARG_CHECK(min_value != NULL);
|
||||
ARG_CHECK(max_value != NULL);
|
||||
offset = 0;
|
||||
scale = 1;
|
||||
(void)ctx;
|
||||
return secp256k1_rangeproof_getheader_impl(&offset, exp, mantissa, &scale, min_value, max_value, proof, plen);
|
||||
}
|
||||
|
||||
int secp256k1_rangeproof_rewind(const secp256k1_context* ctx,
|
||||
unsigned char *blind_out, uint64_t *value_out, unsigned char *message_out, int *outlen, const unsigned char *nonce,
|
||||
uint64_t *min_value, uint64_t *max_value,
|
||||
const unsigned char *commit, const unsigned char *proof, int plen) {
|
||||
ARG_CHECK(ctx != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
ARG_CHECK(min_value != NULL);
|
||||
ARG_CHECK(max_value != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(secp256k1_pedersen_context_is_built(&ctx->pedersen_ctx));
|
||||
ARG_CHECK(secp256k1_rangeproof_context_is_built(&ctx->rangeproof_ctx));
|
||||
return secp256k1_rangeproof_verify_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, &ctx->pedersen_ctx, &ctx->rangeproof_ctx,
|
||||
blind_out, value_out, message_out, outlen, nonce, min_value, max_value, commit, proof, plen);
|
||||
}
|
||||
|
||||
int secp256k1_rangeproof_verify(const secp256k1_context* ctx, uint64_t *min_value, uint64_t *max_value,
|
||||
const unsigned char *commit, const unsigned char *proof, int plen) {
|
||||
ARG_CHECK(ctx != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
ARG_CHECK(min_value != NULL);
|
||||
ARG_CHECK(max_value != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(secp256k1_pedersen_context_is_built(&ctx->pedersen_ctx));
|
||||
ARG_CHECK(secp256k1_rangeproof_context_is_built(&ctx->rangeproof_ctx));
|
||||
return secp256k1_rangeproof_verify_impl(&ctx->ecmult_ctx, NULL, &ctx->pedersen_ctx, &ctx->rangeproof_ctx,
|
||||
NULL, NULL, NULL, NULL, NULL, min_value, max_value, commit, proof, plen);
|
||||
}
|
||||
|
||||
int secp256k1_rangeproof_sign(const secp256k1_context* ctx, unsigned char *proof, int *plen, uint64_t min_value,
|
||||
const unsigned char *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value){
|
||||
ARG_CHECK(ctx != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
ARG_CHECK(plen != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(blind != NULL);
|
||||
ARG_CHECK(nonce != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(secp256k1_pedersen_context_is_built(&ctx->pedersen_ctx));
|
||||
ARG_CHECK(secp256k1_rangeproof_context_is_built(&ctx->rangeproof_ctx));
|
||||
return secp256k1_rangeproof_sign_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, &ctx->pedersen_ctx, &ctx->rangeproof_ctx,
|
||||
proof, plen, min_value, commit, blind, nonce, exp, min_bits, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
34
src/secp256k1/src/modules/rangeproof/pedersen.h
Normal file
34
src/secp256k1/src/modules/rangeproof/pedersen.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2014, 2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_PEDERSEN_H_
|
||||
#define _SECP256K1_PEDERSEN_H_
|
||||
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
secp256k1_ge_storage (*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);
|
||||
|
||||
/* 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);
|
||||
|
||||
#endif
|
||||
139
src/secp256k1/src/modules/rangeproof/pedersen_impl.h
Normal file
139
src/secp256k1/src/modules/rangeproof/pedersen_impl.h
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/***********************************************************************
|
||||
* Copyright (c) 2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php. *
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_PEDERSEN_IMPL_H_
|
||||
#define _SECP256K1_PEDERSEN_IMPL_H_
|
||||
|
||||
/** Alternative generator for secp256k1.
|
||||
* This is the sha256 of 'g' after DER encoding (without compression),
|
||||
* which happens to be a point on the curve.
|
||||
* sage: G2 = EllipticCurve ([F (0), F (7)]).lift_x(int(hashlib.sha256('0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'.decode('hex')).hexdigest(),16))
|
||||
* sage: '%x %x'%G2.xy()
|
||||
*/
|
||||
static const secp256k1_ge secp256k1_ge_const_g2 = SECP256K1_GE_CONST(
|
||||
0x50929b74UL, 0xc1a04954UL, 0xb78b4b60UL, 0x35e97a5eUL,
|
||||
0x078a5a0fUL, 0x28ec96d5UL, 0x47bfee9aUL, 0xce803ac0UL,
|
||||
0x31d3c686UL, 0x3973926eUL, 0x049e637cUL, 0xb1b5f40aUL,
|
||||
0x36dac28aUL, 0xf1766968UL, 0xc30c2313UL, 0xf3a38904UL
|
||||
);
|
||||
|
||||
static void secp256k1_pedersen_context_init(secp256k1_pedersen_context *ctx) {
|
||||
ctx->prec = NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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_gej vj;
|
||||
secp256k1_ecmult_gen(ecmult_gen_ctx, rj, sec);
|
||||
secp256k1_pedersen_ecmult_small(pedersen_ctx, &vj, value);
|
||||
/* FIXME: constant time. */
|
||||
secp256k1_gej_add_var(rj, rj, &vj, NULL);
|
||||
secp256k1_gej_clear(&vj);
|
||||
}
|
||||
|
||||
#endif
|
||||
31
src/secp256k1/src/modules/rangeproof/rangeproof.h
Normal file
31
src/secp256k1/src/modules/rangeproof/rangeproof.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_RANGEPROOF_H_
|
||||
#define _SECP256K1_RANGEPROOF_H_
|
||||
|
||||
#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);
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
||||
736
src/secp256k1/src/modules/rangeproof/rangeproof_impl.h
Normal file
736
src/secp256k1/src/modules/rangeproof/rangeproof_impl.h
Normal file
|
|
@ -0,0 +1,736 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_RANGEPROOF_IMPL_H_
|
||||
#define _SECP256K1_RANGEPROOF_IMPL_H_
|
||||
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
#include "rangeproof.h"
|
||||
#include "hash_impl.h"
|
||||
|
||||
#include "modules/rangeproof/pedersen.h"
|
||||
#include "modules/rangeproof/borromean.h"
|
||||
|
||||
static const int secp256k1_rangeproof_offsets[20] = {
|
||||
0, 96, 189, 276, 360, 438, 510, 579, 642,
|
||||
699, 753, 801, 843, 882, 915, 942, 966, 984,
|
||||
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;
|
||||
VERIFY_CHECK(exp < 19);
|
||||
if (exp < 0) {
|
||||
exp = 0;
|
||||
}
|
||||
basis = &(*ctx->prec)[secp256k1_rangeproof_offsets[exp]];
|
||||
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);
|
||||
}
|
||||
npub += rsizes[i];
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
unsigned char tmp[32];
|
||||
unsigned char rngseed[32 + 33 + 10];
|
||||
secp256k1_rfc6979_hmac_sha256_t rng;
|
||||
secp256k1_scalar acc;
|
||||
int overflow;
|
||||
int ret;
|
||||
int i;
|
||||
int j;
|
||||
int b;
|
||||
int 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_scalar_clear(&acc);
|
||||
npub = 0;
|
||||
ret = 1;
|
||||
for (i = 0; i < rings; i++) {
|
||||
if (i < rings - 1) {
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, tmp, 32);
|
||||
do {
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, tmp, 32);
|
||||
secp256k1_scalar_set_b32(&sec[i], tmp, &overflow);
|
||||
} while (overflow || secp256k1_scalar_is_zero(&sec[i]));
|
||||
secp256k1_scalar_add(&acc, &acc, &sec[i]);
|
||||
} else {
|
||||
secp256k1_scalar_negate(&acc, &acc);
|
||||
sec[i] = acc;
|
||||
}
|
||||
for (j = 0; j < rsizes[i]; j++) {
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, tmp, 32);
|
||||
if (message) {
|
||||
for (b = 0; b < 32; b++) {
|
||||
tmp[b] ^= message[(i * 4 + j) * 32 + b];
|
||||
message[(i * 4 + j) * 32 + b] = tmp[b];
|
||||
}
|
||||
}
|
||||
secp256k1_scalar_set_b32(&s[npub], tmp, &overflow);
|
||||
ret &= !(overflow || secp256k1_scalar_is_zero(&s[npub]));
|
||||
npub++;
|
||||
}
|
||||
}
|
||||
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
|
||||
secp256k1_scalar_clear(&acc);
|
||||
memset(tmp, 0, 32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_range_proveparams(uint64_t *v, int *rings, int *rsizes, int *npub, int *secidx, uint64_t *min_value,
|
||||
int *mantissa, uint64_t *scale, int *exp, int *min_bits, uint64_t value) {
|
||||
int i;
|
||||
*rings = 1;
|
||||
rsizes[0] = 1;
|
||||
secidx[0] = 0;
|
||||
*scale = 1;
|
||||
*mantissa = 0;
|
||||
*npub = 0;
|
||||
if (*min_value == UINT64_MAX) {
|
||||
/* If the minimum value is the maximal representable value, then we cannot code a range. */
|
||||
*exp = -1;
|
||||
}
|
||||
if (*exp >= 0) {
|
||||
int max_bits;
|
||||
uint64_t v2;
|
||||
if ((*min_value && value > INT64_MAX) || (value && *min_value >= INT64_MAX)) {
|
||||
/* If either value or min_value is >= 2^63-1 then the other must by zero to avoid overflowing the proven range. */
|
||||
return 0;
|
||||
}
|
||||
max_bits = *min_value ? secp256k1_clz64_var(*min_value) : 64;
|
||||
if (*min_bits > max_bits) {
|
||||
*min_bits = max_bits;
|
||||
}
|
||||
if (*min_bits > 61 || value > INT64_MAX) {
|
||||
/** Ten is not a power of two, so dividing by ten and then representing in base-2 times ten
|
||||
* expands the representable range. The verifier requires the proven range is within 0..2**64.
|
||||
* For very large numbers (all over 2**63) we must change our exponent to compensate.
|
||||
* Rather than handling it precisely, this just disables use of the exponent for big values.
|
||||
*/
|
||||
*exp = 0;
|
||||
}
|
||||
/* Mask off the least significant digits, as requested. */
|
||||
*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++) {
|
||||
*v /= 10;
|
||||
v2 *= 10;
|
||||
}
|
||||
*exp = i;
|
||||
v2 = *v;
|
||||
for (i = 0; i < *exp; i++) {
|
||||
v2 *= 10;
|
||||
*scale *= 10;
|
||||
}
|
||||
/* If the masked number isn't precise, compute the public offset. */
|
||||
*min_value = value - v2;
|
||||
/* How many bits do we need to represent our value? */
|
||||
*mantissa = *v ? 64 - secp256k1_clz64_var(*v) : 1;
|
||||
if (*min_bits > *mantissa) {
|
||||
/* If the user asked for more precision, give it to them. */
|
||||
*mantissa = *min_bits;
|
||||
}
|
||||
/* Digits in radix-4, except for the last digit if our mantissa length is odd. */
|
||||
*rings = (*mantissa + 1) >> 1;
|
||||
for (i = 0; i < *rings; i++) {
|
||||
rsizes[i] = ((i < *rings - 1) | (!(*mantissa&1))) ? 4 : 2;
|
||||
*npub += rsizes[i];
|
||||
secidx[i] = (*v >> (i*2)) & 3;
|
||||
}
|
||||
VERIFY_CHECK(*mantissa>0);
|
||||
VERIFY_CHECK((*v & ~(UINT64_MAX>>(64-*mantissa))) == 0); /* Did this get all the bits? */
|
||||
} else {
|
||||
/* A proof for an exact value. */
|
||||
*exp = 0;
|
||||
*min_value = value;
|
||||
*v = 0;
|
||||
*npub = 2;
|
||||
}
|
||||
VERIFY_CHECK(*v * *scale + *min_value == value);
|
||||
VERIFY_CHECK(*rings > 0);
|
||||
VERIFY_CHECK(*rings <= 32);
|
||||
VERIFY_CHECK(*npub <= 128);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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){
|
||||
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. */
|
||||
secp256k1_scalar k[32]; /* Nonces for our non-forged signatures. */
|
||||
secp256k1_scalar stmp;
|
||||
secp256k1_sha256_t sha256_m;
|
||||
unsigned char prep[4096];
|
||||
unsigned char tmp[33];
|
||||
unsigned char *signs; /* Location of sign flags in the proof. */
|
||||
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;
|
||||
int overflow;
|
||||
int npub;
|
||||
len = 0;
|
||||
if (*plen < 65 || min_value > value || min_bits > 64 || min_bits < 0 || exp < -1 || exp > 18) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_range_proveparams(&v, &rings, rsizes, &npub, secidx, &min_value, &mantissa, &scale, &exp, &min_bits, value)) {
|
||||
return 0;
|
||||
}
|
||||
proof[len] = (rsizes[0] > 1 ? (64 | exp) : 0) | (min_value ? 32 : 0);
|
||||
len++;
|
||||
if (rsizes[0] > 1) {
|
||||
VERIFY_CHECK(mantissa > 0 && mantissa <= 64);
|
||||
proof[len] = mantissa - 1;
|
||||
len++;
|
||||
}
|
||||
if (min_value) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
proof[len + i] = (min_value >> ((7-i) * 8)) & 255;
|
||||
}
|
||||
len += 8;
|
||||
}
|
||||
/* 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_sha256_write(&sha256_m, proof, len);
|
||||
|
||||
memset(prep, 0, 4096);
|
||||
/* Note, the data corresponding to the blinding factors must be zero. */
|
||||
if (rsizes[rings - 1] > 1) {
|
||||
int idx;
|
||||
/* Value encoding sidechannel. */
|
||||
idx = rsizes[rings - 1] - 1;
|
||||
idx -= secidx[rings - 1] == idx;
|
||||
idx = ((rings - 1) * 4 + idx) * 32;
|
||||
for (i = 0; i < 8; i++) {
|
||||
prep[8 + i + idx] = prep[16 + i + idx] = prep[24 + i + idx] = (v >> (56 - i * 8)) & 255;
|
||||
prep[i + idx] = 0;
|
||||
}
|
||||
prep[idx] = 128;
|
||||
}
|
||||
if (!secp256k1_rangeproof_genrand(sec, s, prep, rsizes, rings, nonce, commit, proof, len)) {
|
||||
return 0;
|
||||
}
|
||||
memset(prep, 0, 4096);
|
||||
for (i = 0; i < rings; i++) {
|
||||
/* Sign will overwrite the non-forged signature, move that random value into the nonce. */
|
||||
k[i] = s[i * 4 + secidx[i]];
|
||||
secp256k1_scalar_clear(&s[i * 4 + secidx[i]]);
|
||||
}
|
||||
/** Genrand returns the last blinding factor as -sum(rest),
|
||||
* adding in the blinding factor for our commitment, results in the blinding factor for
|
||||
* the commitment to the last digit that the verifier can compute for itself by subtracting
|
||||
* all the digits in the proof from the commitment. This lets the prover skip sending the
|
||||
* blinded value for one digit.
|
||||
*/
|
||||
secp256k1_scalar_set_b32(&stmp, blind, &overflow);
|
||||
secp256k1_scalar_add(&sec[rings - 1], &sec[rings - 1], &stmp);
|
||||
if (overflow || secp256k1_scalar_is_zero(&sec[rings - 1])) {
|
||||
return 0;
|
||||
}
|
||||
signs = &proof[len];
|
||||
/* We need one sign bit for each blinded value we send. */
|
||||
for (i = 0; i < (rings + 6) >> 3; i++) {
|
||||
signs[i] = 0;
|
||||
len++;
|
||||
}
|
||||
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));
|
||||
if (secp256k1_gej_is_infinity(&pubs[npub])) {
|
||||
return 0;
|
||||
}
|
||||
if (i < rings - 1) {
|
||||
size_t size = 33;
|
||||
secp256k1_ge c;
|
||||
/*OPT: split loop and batch invert.*/
|
||||
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);
|
||||
len += 32;
|
||||
}
|
||||
npub += rsizes[i];
|
||||
}
|
||||
secp256k1_rangeproof_pub_expand(rangeproof_ctx, pubs, exp, rsizes, rings);
|
||||
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;
|
||||
}
|
||||
len += 32;
|
||||
for (i = 0; i < npub; i++) {
|
||||
secp256k1_scalar_get_b32(&proof[len],&s[i]);
|
||||
len += 32;
|
||||
}
|
||||
VERIFY_CHECK(len <= *plen);
|
||||
*plen = len;
|
||||
memset(prep, 0, 4096);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Computes blinding factor x given k, s, and the challenge e. */
|
||||
SECP256K1_INLINE static void secp256k1_rangeproof_recover_x(secp256k1_scalar *x, const secp256k1_scalar *k, const secp256k1_scalar *e,
|
||||
const secp256k1_scalar *s) {
|
||||
secp256k1_scalar stmp;
|
||||
secp256k1_scalar_negate(x, s);
|
||||
secp256k1_scalar_add(x, x, k);
|
||||
secp256k1_scalar_inverse(&stmp, e);
|
||||
secp256k1_scalar_mul(x, x, &stmp);
|
||||
}
|
||||
|
||||
/* Computes ring's nonce given the blinding factor x, the challenge e, and the signature s. */
|
||||
SECP256K1_INLINE static void secp256k1_rangeproof_recover_k(secp256k1_scalar *k, const secp256k1_scalar *x, const secp256k1_scalar *e,
|
||||
const secp256k1_scalar *s) {
|
||||
secp256k1_scalar stmp;
|
||||
secp256k1_scalar_mul(&stmp, x, e);
|
||||
secp256k1_scalar_add(k, s, &stmp);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_rangeproof_ch32xor(unsigned char *x, const unsigned char *y) {
|
||||
int i;
|
||||
for (i = 0; i < 32; i++) {
|
||||
x[i] ^= y[i];
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
int b;
|
||||
int skip1;
|
||||
int skip2;
|
||||
int 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);
|
||||
*v = UINT64_MAX;
|
||||
secp256k1_scalar_clear(blind);
|
||||
if (rings == 1 && rsizes[0] == 1) {
|
||||
/* With only a single proof, we can only recover the blinding factor. */
|
||||
secp256k1_rangeproof_recover_x(blind, &s_orig[0], &ev[0], &s[0]);
|
||||
if (v) {
|
||||
*v = 0;
|
||||
}
|
||||
if (mlen) {
|
||||
*mlen = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
npub = (rings - 1) << 2;
|
||||
for (j = 0; j < 2; j++) {
|
||||
int idx;
|
||||
/* Look for a value encoding in the last ring. */
|
||||
idx = npub + rsizes[rings - 1] - 1 - j;
|
||||
secp256k1_scalar_get_b32(tmp, &s[idx]);
|
||||
secp256k1_rangeproof_ch32xor(tmp, &prep[idx * 32]);
|
||||
if ((tmp[0] & 128) && (memcmp(&tmp[16], &tmp[24], 8) == 0) && (memcmp(&tmp[8], &tmp[16], 8) == 0)) {
|
||||
value = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
value = (value << 8) + tmp[24 + i];
|
||||
}
|
||||
if (v) {
|
||||
*v = value;
|
||||
}
|
||||
memcpy(&prep[idx * 32], tmp, 32);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j > 1) {
|
||||
/* Couldn't extract a value. */
|
||||
if (mlen) {
|
||||
*mlen = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
skip1 = rsizes[rings - 1] - 1 - j;
|
||||
skip2 = ((value >> ((rings - 1) << 1)) & 3);
|
||||
if (skip1 == skip2) {
|
||||
/*Value is in wrong position.*/
|
||||
if (mlen) {
|
||||
*mlen = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
skip1 += (rings - 1) << 2;
|
||||
skip2 += (rings - 1) << 2;
|
||||
/* Like in the rsize[] == 1 case, Having figured out which s is the one which was not forged, we can recover the blinding factor. */
|
||||
secp256k1_rangeproof_recover_x(&stmp, &s_orig[skip2], &ev[skip2], &s[skip2]);
|
||||
secp256k1_scalar_negate(&sec[rings - 1], &sec[rings - 1]);
|
||||
secp256k1_scalar_add(blind, &stmp, &sec[rings - 1]);
|
||||
if (!m || !mlen || *mlen == 0) {
|
||||
if (mlen) {
|
||||
*mlen = 0;
|
||||
}
|
||||
/* FIXME: cleanup in early out/failure cases. */
|
||||
return 1;
|
||||
}
|
||||
offset = 0;
|
||||
npub = 0;
|
||||
for (i = 0; i < rings; i++) {
|
||||
int idx;
|
||||
idx = (value >> (i << 1)) & 3;
|
||||
for (j = 0; j < rsizes[i]; j++) {
|
||||
if (npub == skip1 || npub == skip2) {
|
||||
npub++;
|
||||
continue;
|
||||
}
|
||||
if (idx == j) {
|
||||
/** For the non-forged signatures the signature is calculated instead of random, instead we recover the prover's nonces.
|
||||
* this could just as well recover the blinding factors and messages could be put there as is done for recovering the
|
||||
* blinding factor in the last ring, but it takes an inversion to recover x so it's faster to put the message data in k.
|
||||
*/
|
||||
secp256k1_rangeproof_recover_k(&stmp, &sec[i], &ev[npub], &s[npub]);
|
||||
} else {
|
||||
stmp = s[npub];
|
||||
}
|
||||
secp256k1_scalar_get_b32(tmp, &stmp);
|
||||
secp256k1_rangeproof_ch32xor(tmp, &prep[npub * 32]);
|
||||
for (b = 0; b < 32 && offset < *mlen; b++) {
|
||||
m[offset] = tmp[b];
|
||||
offset++;
|
||||
}
|
||||
npub++;
|
||||
}
|
||||
}
|
||||
*mlen = offset;
|
||||
memset(prep, 0, 4096);
|
||||
for (i = 0; i < 128; i++) {
|
||||
secp256k1_scalar_clear(&s_orig[i]);
|
||||
}
|
||||
for (i = 0; i < 32; i++) {
|
||||
secp256k1_scalar_clear(&sec[i]);
|
||||
}
|
||||
secp256k1_scalar_clear(&stmp);
|
||||
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) {
|
||||
int i;
|
||||
int has_nz_range;
|
||||
int has_min;
|
||||
if (plen < 65 || ((proof[*offset] & 128) != 0)) {
|
||||
return 0;
|
||||
}
|
||||
has_nz_range = proof[*offset] & 64;
|
||||
has_min = proof[*offset] & 32;
|
||||
*exp = -1;
|
||||
*mantissa = 0;
|
||||
if (has_nz_range) {
|
||||
*exp = proof[*offset] & 31;
|
||||
*offset += 1;
|
||||
if (*exp > 18) {
|
||||
return 0;
|
||||
}
|
||||
*mantissa = proof[*offset] + 1;
|
||||
if (*mantissa > 64) {
|
||||
return 0;
|
||||
}
|
||||
*max_value = UINT64_MAX>>(64-*mantissa);
|
||||
} else {
|
||||
*max_value = 0;
|
||||
}
|
||||
*offset += 1;
|
||||
*scale = 1;
|
||||
for (i = 0; i < *exp; i++) {
|
||||
if (*max_value > UINT64_MAX / 10) {
|
||||
return 0;
|
||||
}
|
||||
*max_value *= 10;
|
||||
*scale *= 10;
|
||||
}
|
||||
*min_value = 0;
|
||||
if (has_min) {
|
||||
if(plen - *offset < 8) {
|
||||
return 0;
|
||||
}
|
||||
/*FIXME: Compact minvalue encoding?*/
|
||||
for (i = 0; i < 8; i++) {
|
||||
*min_value = (*min_value << 8) | proof[*offset + i];
|
||||
}
|
||||
*offset += 8;
|
||||
}
|
||||
if (*max_value > UINT64_MAX - *min_value) {
|
||||
return 0;
|
||||
}
|
||||
*max_value += *min_value;
|
||||
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.*/
|
||||
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) {
|
||||
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];
|
||||
int ret;
|
||||
int i;
|
||||
size_t size;
|
||||
int exp;
|
||||
int mantissa;
|
||||
int offset;
|
||||
int rings;
|
||||
int overflow;
|
||||
int npub;
|
||||
int offset_post_header;
|
||||
uint64_t scale;
|
||||
unsigned char signs[31];
|
||||
unsigned char m[33];
|
||||
const unsigned char *e0;
|
||||
offset = 0;
|
||||
if (!secp256k1_rangeproof_getheader_impl(&offset, &exp, &mantissa, &scale, min_value, max_value, proof, plen)) {
|
||||
return 0;
|
||||
}
|
||||
offset_post_header = offset;
|
||||
rings = 1;
|
||||
rsizes[0] = 1;
|
||||
npub = 1;
|
||||
if (mantissa != 0) {
|
||||
rings = (mantissa >> 1);
|
||||
for (i = 0; i < rings; i++) {
|
||||
rsizes[i] = 4;
|
||||
}
|
||||
npub = (mantissa >> 1) << 2;
|
||||
if (mantissa & 1) {
|
||||
rsizes[rings] = 2;
|
||||
npub += rsizes[rings];
|
||||
rings++;
|
||||
}
|
||||
}
|
||||
VERIFY_CHECK(rings <= 32);
|
||||
if (plen - offset < 32 * (npub + rings - 1) + 32 + ((rings+6) >> 3)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_initialize(&sha256_m);
|
||||
secp256k1_sha256_write(&sha256_m, commit, 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;
|
||||
}
|
||||
offset += (rings + 6) >> 3;
|
||||
if ((rings - 1) & 7) {
|
||||
/* Number of coded blinded points is not a multiple of 8, force extra sign bits to 0 to reject mutation. */
|
||||
if ((proof[offset - 1] >> ((rings - 1) & 7)) != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
npub = 0;
|
||||
secp256k1_gej_set_infinity(&accj);
|
||||
if (*min_value) {
|
||||
secp256k1_pedersen_ecmult_small(pedersen_ctx, &accj, *min_value);
|
||||
}
|
||||
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_sha256_write(&sha256_m, m, 33);
|
||||
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);
|
||||
if (secp256k1_gej_is_infinity(&pubs[npub])) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_rangeproof_pub_expand(rangeproof_ctx, pubs, exp, rsizes, rings);
|
||||
npub += rsizes[rings - 1];
|
||||
e0 = &proof[offset];
|
||||
offset += 32;
|
||||
for (i = 0; i < npub; i++) {
|
||||
secp256k1_scalar_set_b32(&s[i], &proof[offset], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
offset += 32;
|
||||
}
|
||||
if (offset != plen) {
|
||||
/*Extra data found, reject.*/
|
||||
return 0;
|
||||
}
|
||||
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)) {
|
||||
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);
|
||||
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) {
|
||||
return 0;
|
||||
}
|
||||
if (blindout) {
|
||||
secp256k1_scalar_get_b32(blindout, &blind);
|
||||
}
|
||||
if (value_out) {
|
||||
*value_out = vv;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
281
src/secp256k1/src/modules/rangeproof/tests_impl.h
Normal file
281
src/secp256k1/src/modules/rangeproof/tests_impl.h
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_RANGEPROOF_TESTS
|
||||
#define SECP256K1_MODULE_RANGEPROOF_TESTS
|
||||
|
||||
#include "include/secp256k1_rangeproof.h"
|
||||
|
||||
void test_pedersen(void) {
|
||||
unsigned char commits[33*19];
|
||||
const unsigned char *cptr[19];
|
||||
unsigned char blinds[32*19];
|
||||
const unsigned char *bptr[19];
|
||||
secp256k1_scalar s;
|
||||
uint64_t values[19];
|
||||
int64_t totalv;
|
||||
int i;
|
||||
int inputs;
|
||||
int outputs;
|
||||
int total;
|
||||
inputs = (secp256k1_rand32() & 7) + 1;
|
||||
outputs = (secp256k1_rand32() & 7) + 2;
|
||||
total = inputs + outputs;
|
||||
for (i = 0; i < 19; i++) {
|
||||
cptr[i] = &commits[i * 33];
|
||||
bptr[i] = &blinds[i * 32];
|
||||
}
|
||||
totalv = 0;
|
||||
for (i = 0; i < inputs; i++) {
|
||||
values[i] = secp256k1_rands64(0, INT64_MAX - totalv);
|
||||
totalv += values[i];
|
||||
}
|
||||
if (secp256k1_rand32() & 1) {
|
||||
for (i = 0; i < outputs; i++) {
|
||||
int64_t max = INT64_MAX;
|
||||
if (totalv < 0) {
|
||||
max += totalv;
|
||||
}
|
||||
values[i + inputs] = secp256k1_rands64(0, max);
|
||||
totalv -= values[i + inputs];
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < outputs - 1; i++) {
|
||||
values[i + inputs] = secp256k1_rands64(0, totalv);
|
||||
totalv -= values[i + inputs];
|
||||
}
|
||||
values[total - 1] = totalv >> (secp256k1_rand32() & 1);
|
||||
totalv -= values[total - 1];
|
||||
}
|
||||
for (i = 0; i < total - 1; i++) {
|
||||
random_scalar_order(&s);
|
||||
secp256k1_scalar_get_b32(&blinds[i * 32], &s);
|
||||
}
|
||||
CHECK(secp256k1_pedersen_blind_sum(ctx, &blinds[(total - 1) * 32], bptr, total - 1, inputs));
|
||||
for (i = 0; i < total; i++) {
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commits[i * 33], &blinds[i * 32], values[i]));
|
||||
}
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs, totalv));
|
||||
CHECK(!secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs, totalv + 1));
|
||||
random_scalar_order(&s);
|
||||
for (i = 0; i < 4; i++) {
|
||||
secp256k1_scalar_get_b32(&blinds[i * 32], &s);
|
||||
}
|
||||
values[0] = INT64_MAX;
|
||||
values[1] = 0;
|
||||
values[2] = 1;
|
||||
for (i = 0; i < 3; i++) {
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commits[i * 33], &blinds[i * 32], values[i]));
|
||||
}
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[2], 1, -1));
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[2], 1, &cptr[1], 1, 1));
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1, 0));
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[1], 1, INT64_MAX));
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1, 0));
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[0], 1, -INT64_MAX));
|
||||
}
|
||||
|
||||
void test_borromean(void) {
|
||||
unsigned char e0[32];
|
||||
secp256k1_scalar s[64];
|
||||
secp256k1_gej pubs[64];
|
||||
secp256k1_scalar k[8];
|
||||
secp256k1_scalar sec[8];
|
||||
secp256k1_ge ge;
|
||||
secp256k1_scalar one;
|
||||
unsigned char m[32];
|
||||
int rsizes[8];
|
||||
int secidx[8];
|
||||
int nrings;
|
||||
int i;
|
||||
int j;
|
||||
int c;
|
||||
secp256k1_rand256_test(m);
|
||||
nrings = 1 + (secp256k1_rand32()&7);
|
||||
c = 0;
|
||||
secp256k1_scalar_set_int(&one, 1);
|
||||
if (secp256k1_rand32()&1) {
|
||||
secp256k1_scalar_negate(&one, &one);
|
||||
}
|
||||
for (i = 0; i < nrings; i++) {
|
||||
rsizes[i] = 1 + (secp256k1_rand32()&7);
|
||||
secidx[i] = secp256k1_rand32() % rsizes[i];
|
||||
random_scalar_order(&sec[i]);
|
||||
random_scalar_order(&k[i]);
|
||||
if(secp256k1_rand32()&7) {
|
||||
sec[i] = one;
|
||||
}
|
||||
if(secp256k1_rand32()&7) {
|
||||
k[i] = one;
|
||||
}
|
||||
for (j = 0; j < rsizes[i]; j++) {
|
||||
random_scalar_order(&s[c + j]);
|
||||
if(secp256k1_rand32()&7) {
|
||||
s[i] = one;
|
||||
}
|
||||
if (j == secidx[i]) {
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubs[c + j], &sec[i]);
|
||||
} else {
|
||||
random_group_element_test(&ge);
|
||||
random_group_element_jacobian_test(&pubs[c + j],&ge);
|
||||
}
|
||||
}
|
||||
c += rsizes[i];
|
||||
}
|
||||
CHECK(secp256k1_borromean_sign(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, e0, s, pubs, k, sec, rsizes, secidx, nrings, m, 32));
|
||||
CHECK(secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32));
|
||||
i = secp256k1_rand32() % c;
|
||||
secp256k1_scalar_negate(&s[i],&s[i]);
|
||||
CHECK(!secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32));
|
||||
secp256k1_scalar_negate(&s[i],&s[i]);
|
||||
secp256k1_scalar_set_int(&one, 1);
|
||||
for(j = 0; j < 4; j++) {
|
||||
i = secp256k1_rand32() % c;
|
||||
if (secp256k1_rand32() & 1) {
|
||||
secp256k1_gej_double_var(&pubs[i],&pubs[i], NULL);
|
||||
} else {
|
||||
secp256k1_scalar_add(&s[i],&s[i],&one);
|
||||
}
|
||||
CHECK(!secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32));
|
||||
}
|
||||
}
|
||||
|
||||
void test_rangeproof(void) {
|
||||
const uint64_t testvs[11] = {0, 1, 5, 11, 65535, 65537, INT32_MAX, UINT32_MAX, INT64_MAX - 1, INT64_MAX, UINT64_MAX};
|
||||
unsigned char commit[33];
|
||||
unsigned char commit2[33];
|
||||
unsigned char proof[5134];
|
||||
unsigned char blind[32];
|
||||
unsigned char blindout[32];
|
||||
unsigned char message[4096];
|
||||
int mlen;
|
||||
uint64_t v;
|
||||
uint64_t vout;
|
||||
uint64_t vmin;
|
||||
uint64_t minv;
|
||||
uint64_t maxv;
|
||||
int len;
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
secp256k1_rand256(blind);
|
||||
for (i = 0; i < 11; i++) {
|
||||
v = testvs[i];
|
||||
CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v));
|
||||
for (vmin = 0; vmin < (i<9 && i > 0 ? 2 : 1); vmin++) {
|
||||
len = 5134;
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, commit, blind, commit, 0, 0, v));
|
||||
CHECK(len <= 5134);
|
||||
mlen = 4096;
|
||||
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit, &minv, &maxv, commit, proof, len));
|
||||
for (j = 0; j < mlen; j++) {
|
||||
CHECK(message[j] == 0);
|
||||
}
|
||||
CHECK(mlen <= 4096);
|
||||
CHECK(memcmp(blindout, blind, 32) == 0);
|
||||
CHECK(vout == v);
|
||||
CHECK(minv <= v);
|
||||
CHECK(maxv >= v);
|
||||
len = 5134;
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v, commit, blind, commit, -1, 64, v));
|
||||
CHECK(len <= 73);
|
||||
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit, &minv, &maxv, commit, proof, len));
|
||||
CHECK(memcmp(blindout, blind, 32) == 0);
|
||||
CHECK(vout == v);
|
||||
CHECK(minv == v);
|
||||
CHECK(maxv == v);
|
||||
}
|
||||
}
|
||||
secp256k1_rand256(blind);
|
||||
v = INT64_MAX - 1;
|
||||
CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v));
|
||||
for (i = 0; i < 19; i++) {
|
||||
len = 5134;
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, commit, blind, commit, i, 0, v));
|
||||
CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit, proof, len));
|
||||
CHECK(len <= 5134);
|
||||
CHECK(minv <= v);
|
||||
CHECK(maxv >= v);
|
||||
}
|
||||
secp256k1_rand256(blind);
|
||||
{
|
||||
/*Malleability test.*/
|
||||
v = secp256k1_rands64(0, 255);
|
||||
CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v));
|
||||
len = 5134;
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, commit, blind, commit, 0, 3, v));
|
||||
CHECK(len <= 5134);
|
||||
for (i = 0; i < len*8; i++) {
|
||||
proof[i >> 3] ^= 1 << (i & 7);
|
||||
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit, proof, len));
|
||||
proof[i >> 3] ^= 1 << (i & 7);
|
||||
}
|
||||
CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit, proof, len));
|
||||
CHECK(minv <= v);
|
||||
CHECK(maxv >= v);
|
||||
}
|
||||
memcpy(commit2, commit, 33);
|
||||
for (i = 0; i < 10 * count; i++) {
|
||||
int exp;
|
||||
int min_bits;
|
||||
v = secp256k1_rands64(0, UINT64_MAX >> (secp256k1_rand32()&63));
|
||||
vmin = 0;
|
||||
if ((v < INT64_MAX) && (secp256k1_rand32()&1)) {
|
||||
vmin = secp256k1_rands64(0, v);
|
||||
}
|
||||
secp256k1_rand256(blind);
|
||||
CHECK(secp256k1_pedersen_commit(ctx, commit, blind, v));
|
||||
len = 5134;
|
||||
exp = (int)secp256k1_rands64(0,18)-(int)secp256k1_rands64(0,18);
|
||||
if (exp < 0) {
|
||||
exp = -exp;
|
||||
}
|
||||
min_bits = (int)secp256k1_rands64(0,64)-(int)secp256k1_rands64(0,64);
|
||||
if (min_bits < 0) {
|
||||
min_bits = -min_bits;
|
||||
}
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, commit, blind, commit, exp, min_bits, v));
|
||||
CHECK(len <= 5134);
|
||||
mlen = 4096;
|
||||
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit, &minv, &maxv, commit, proof, len));
|
||||
for (j = 0; j < mlen; j++) {
|
||||
CHECK(message[j] == 0);
|
||||
}
|
||||
CHECK(mlen <= 4096);
|
||||
CHECK(memcmp(blindout, blind, 32) == 0);
|
||||
CHECK(vout == v);
|
||||
CHECK(minv <= v);
|
||||
CHECK(maxv >= v);
|
||||
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit, &minv, &maxv, commit, proof, len));
|
||||
memcpy(commit2, commit, 33);
|
||||
}
|
||||
for (j = 0; j < 10; j++) {
|
||||
for (i = 0; i < 96; i++) {
|
||||
secp256k1_rand256(&proof[i * 32]);
|
||||
}
|
||||
for (k = 0; k < 128; k++) {
|
||||
len = k;
|
||||
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit2, proof, len));
|
||||
}
|
||||
len = secp256k1_rands64(0, 3072);
|
||||
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, commit2, proof, len));
|
||||
}
|
||||
}
|
||||
|
||||
void run_rangeproof_tests(void) {
|
||||
int i;
|
||||
secp256k1_pedersen_context_initialize(ctx);
|
||||
secp256k1_rangeproof_context_initialize(ctx);
|
||||
for (i = 0; i < 10*count; i++) {
|
||||
test_pedersen();
|
||||
}
|
||||
for (i = 0; i < 10*count; i++) {
|
||||
test_borromean();
|
||||
}
|
||||
test_rangeproof();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -18,6 +18,11 @@
|
|||
#include "eckey_impl.h"
|
||||
#include "hash_impl.h"
|
||||
|
||||
#ifdef ENABLE_MODULE_RANGEPROOF
|
||||
# include "modules/rangeproof/pedersen.h"
|
||||
# include "modules/rangeproof/rangeproof.h"
|
||||
#endif
|
||||
|
||||
#define ARG_CHECK(cond) do { \
|
||||
if (EXPECT(!(cond), 0)) { \
|
||||
secp256k1_callback_call(&ctx->illegal_callback, #cond); \
|
||||
|
|
@ -51,6 +56,10 @@ 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;
|
||||
};
|
||||
|
|
@ -69,6 +78,10 @@ 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);
|
||||
|
|
@ -86,6 +99,10 @@ 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;
|
||||
}
|
||||
|
||||
|
|
@ -93,6 +110,10 @@ 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);
|
||||
}
|
||||
|
|
@ -559,3 +580,7 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *
|
|||
#ifdef ENABLE_MODULE_RECOVERY
|
||||
# include "modules/recovery/main_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_RANGEPROOF
|
||||
# include "modules/rangeproof/main_impl.h"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -35,4 +35,7 @@ static void secp256k1_rand256_test(unsigned char *b32);
|
|||
/** Generate pseudorandom bytes with long sequences of zero and one bits. */
|
||||
static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len);
|
||||
|
||||
/** Generate a pseudorandom 64-bit integer in the range min..max, inclusive. */
|
||||
static int64_t secp256k1_rands64(uint64_t min, uint64_t max);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2013-2015 Pieter Wuille *
|
||||
* Copyright (c) 2013-2015 Pieter Wuille, Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
|
@ -107,4 +107,21 @@ static void secp256k1_rand256_test(unsigned char *b32) {
|
|||
secp256k1_rand_bytes_test(b32, 32);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int64_t secp256k1_rands64(uint64_t min, uint64_t max) {
|
||||
uint64_t range;
|
||||
uint64_t r;
|
||||
uint64_t clz;
|
||||
VERIFY_CHECK(max >= min);
|
||||
if (max == min) {
|
||||
return min;
|
||||
}
|
||||
range = max - min;
|
||||
clz = secp256k1_clz64_var(range);
|
||||
do {
|
||||
r = ((uint64_t)secp256k1_rand32() << 32) | secp256k1_rand32();
|
||||
r >>= clz;
|
||||
} while (r > range);
|
||||
return min + (int64_t)r;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell *
|
||||
* Copyright (c) 2013-2015 Pieter Wuille, Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
|
@ -133,6 +133,52 @@ void random_scalar_order(secp256k1_scalar *num) {
|
|||
} while(1);
|
||||
}
|
||||
|
||||
void run_util_tests(void) {
|
||||
int i;
|
||||
uint64_t r;
|
||||
uint64_t r2;
|
||||
uint64_t r3;
|
||||
int64_t s;
|
||||
CHECK(secp256k1_clz64_var(0) == 64);
|
||||
CHECK(secp256k1_clz64_var(1) == 63);
|
||||
CHECK(secp256k1_clz64_var(2) == 62);
|
||||
CHECK(secp256k1_clz64_var(3) == 62);
|
||||
CHECK(secp256k1_clz64_var(~0ULL) == 0);
|
||||
CHECK(secp256k1_clz64_var((~0ULL) - 1) == 0);
|
||||
CHECK(secp256k1_clz64_var((~0ULL) >> 1) == 1);
|
||||
CHECK(secp256k1_clz64_var((~0ULL) >> 2) == 2);
|
||||
CHECK(secp256k1_sign_and_abs64(&r, INT64_MAX) == 0);
|
||||
CHECK(r == INT64_MAX);
|
||||
CHECK(secp256k1_sign_and_abs64(&r, INT64_MAX - 1) == 0);
|
||||
CHECK(r == INT64_MAX - 1);
|
||||
CHECK(secp256k1_sign_and_abs64(&r, INT64_MIN) == 1);
|
||||
CHECK(r == (uint64_t)INT64_MAX + 1);
|
||||
CHECK(secp256k1_sign_and_abs64(&r, INT64_MIN + 1) == 1);
|
||||
CHECK(r == (uint64_t)INT64_MAX);
|
||||
CHECK(secp256k1_sign_and_abs64(&r, 0) == 0);
|
||||
CHECK(r == 0);
|
||||
CHECK(secp256k1_sign_and_abs64(&r, 1) == 0);
|
||||
CHECK(r == 1);
|
||||
CHECK(secp256k1_sign_and_abs64(&r, -1) == 1);
|
||||
CHECK(r == 1);
|
||||
CHECK(secp256k1_sign_and_abs64(&r, 2) == 0);
|
||||
CHECK(r == 2);
|
||||
CHECK(secp256k1_sign_and_abs64(&r, -2) == 1);
|
||||
CHECK(r == 2);
|
||||
for (i = 0; i < 10; i++) {
|
||||
CHECK(secp256k1_clz64_var((~0ULL) - secp256k1_rand32()) == 0);
|
||||
r = ((uint64_t)secp256k1_rand32() << 32) | secp256k1_rand32();
|
||||
r2 = secp256k1_rands64(0, r);
|
||||
CHECK(r2 <= r);
|
||||
r3 = secp256k1_rands64(r2, r);
|
||||
CHECK((r3 >= r2) && (r3 <= r));
|
||||
r = secp256k1_rands64(0, INT64_MAX);
|
||||
s = (int64_t)r * (secp256k1_rand32()&1?-1:1);
|
||||
CHECK(secp256k1_sign_and_abs64(&r2, s) == (s < 0));
|
||||
CHECK(r2 == r);
|
||||
}
|
||||
}
|
||||
|
||||
void run_context_tests(void) {
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
|
|
@ -4391,6 +4437,10 @@ void run_ecdsa_openssl(void) {
|
|||
# include "modules/recovery/tests_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_RANGEPROOF
|
||||
# include "modules/rangeproof/tests_impl.h"
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
unsigned char seed16[16] = {0};
|
||||
unsigned char run32[32] = {0};
|
||||
|
|
@ -4443,6 +4493,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
run_rand_bits();
|
||||
run_rand_int();
|
||||
run_util_tests();
|
||||
|
||||
run_sha256_tests();
|
||||
run_hmac_sha256_tests();
|
||||
|
|
@ -4514,6 +4565,10 @@ int main(int argc, char **argv) {
|
|||
run_recovery_tests();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_RANGEPROOF
|
||||
run_rangeproof_tests();
|
||||
#endif
|
||||
|
||||
secp256k1_rand256(run32);
|
||||
printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* Copyright (c) 2013-2015 Pieter Wuille, Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
|
@ -73,6 +73,33 @@ static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Extract the sign of an int64, take the abs and return a uint64, constant time. */
|
||||
SECP256K1_INLINE static int secp256k1_sign_and_abs64(uint64_t *out, int64_t in) {
|
||||
uint64_t mask0, mask1;
|
||||
int ret;
|
||||
ret = in < 0;
|
||||
mask0 = ret + ~((uint64_t)0);
|
||||
mask1 = ~mask0;
|
||||
*out = (uint64_t)in;
|
||||
*out = (*out & mask0) | ((~*out + 1) & mask1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_clz64_var(uint64_t x) {
|
||||
int ret;
|
||||
if (!x) {
|
||||
return 64;
|
||||
}
|
||||
# if defined(HAVE_BUILTIN_CLZLL)
|
||||
ret = __builtin_clzll(x);
|
||||
# else
|
||||
/*FIXME: debruijn fallback. */
|
||||
for (ret = 0; ((x & (1ULL << 63)) == 0); x <<= 1, ret++);
|
||||
# endif
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* Macro for restrict, when available and not in a VERIFY build. */
|
||||
#if defined(SECP256K1_BUILD) && defined(VERIFY)
|
||||
# define SECP256K1_RESTRICT
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue