Merge pull request #57 from apoelstra/2019-04-surjectionproof-stack
surjectionproof: reduce stack usage and limit proofs to anonymity set of 16
This commit is contained in:
commit
44db4d801f
10
configure.ac
10
configure.ac
@ -174,6 +174,11 @@ AC_ARG_ENABLE(module_surjectionproof,
|
|||||||
[enable_module_surjectionproof=$enableval],
|
[enable_module_surjectionproof=$enableval],
|
||||||
[enable_module_surjectionproof=no])
|
[enable_module_surjectionproof=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(reduced_surjection_proof_size,
|
||||||
|
AS_HELP_STRING([--enable-reduced-surjection-proof-size],[use reduced surjection proof size (disabling parsing and verification) [default=no]]),
|
||||||
|
[use_reduced_surjection_proof_size=$enableval],
|
||||||
|
[use_reduced_surjection_proof_size=no])
|
||||||
|
|
||||||
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
|
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
|
||||||
[finite field implementation to use [default=auto]])],[req_field=$withval], [req_field=auto])
|
[finite field implementation to use [default=auto]])],[req_field=$withval], [req_field=auto])
|
||||||
|
|
||||||
@ -568,6 +573,10 @@ if test x"$use_external_default_callbacks" = x"yes"; then
|
|||||||
AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used])
|
AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test x"$use_reduced_surjection_proof_size" = x"yes"; then
|
||||||
|
AC_DEFINE(USE_REDUCED_SURJECTION_PROOF_SIZE, 1, [Define this symbol to reduce SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS to 16, disabling parsing and verification])
|
||||||
|
fi
|
||||||
|
|
||||||
if test x"$enable_experimental" = x"yes"; then
|
if test x"$enable_experimental" = x"yes"; then
|
||||||
AC_MSG_NOTICE([******])
|
AC_MSG_NOTICE([******])
|
||||||
AC_MSG_NOTICE([WARNING: experimental build])
|
AC_MSG_NOTICE([WARNING: experimental build])
|
||||||
@ -652,6 +661,7 @@ 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_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
|
||||||
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
|
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
|
||||||
AM_CONDITIONAL([ENABLE_MODULE_SURJECTIONPROOF], [test x"$enable_module_surjectionproof" = x"yes"])
|
AM_CONDITIONAL([ENABLE_MODULE_SURJECTIONPROOF], [test x"$enable_module_surjectionproof" = x"yes"])
|
||||||
|
AM_CONDITIONAL([USE_REDUCED_SURJECTION_PROOF_SIZE], [test x"$use_reduced_surjection_proof_size" = x"yes"])
|
||||||
|
|
||||||
dnl make sure nothing new is exported so that we don't break the cache
|
dnl make sure nothing new is exported so that we don't break the cache
|
||||||
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
|
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
|
||||||
|
@ -11,6 +11,9 @@ extern "C" {
|
|||||||
/** Maximum number of inputs that may be given in a surjection proof */
|
/** Maximum number of inputs that may be given in a surjection proof */
|
||||||
#define SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS 256
|
#define SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS 256
|
||||||
|
|
||||||
|
/** Maximum number of inputs that may be used in a surjection proof */
|
||||||
|
#define SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS 256
|
||||||
|
|
||||||
/** Number of bytes a serialized surjection proof requires given the
|
/** Number of bytes a serialized surjection proof requires given the
|
||||||
* number of inputs and the number of used inputs.
|
* number of inputs and the number of used inputs.
|
||||||
*/
|
*/
|
||||||
@ -19,7 +22,7 @@ extern "C" {
|
|||||||
|
|
||||||
/** Maximum number of bytes a serialized surjection proof requires. */
|
/** Maximum number of bytes a serialized surjection proof requires. */
|
||||||
#define SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX \
|
#define SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX \
|
||||||
SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS)
|
SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS)
|
||||||
|
|
||||||
/** Opaque data structure that holds a parsed surjection proof
|
/** Opaque data structure that holds a parsed surjection proof
|
||||||
*
|
*
|
||||||
@ -46,9 +49,10 @@ typedef struct {
|
|||||||
/** Bitmap of which input tags are used in the surjection proof */
|
/** Bitmap of which input tags are used in the surjection proof */
|
||||||
unsigned char used_inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS / 8];
|
unsigned char used_inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS / 8];
|
||||||
/** Borromean signature: e0, scalars */
|
/** Borromean signature: e0, scalars */
|
||||||
unsigned char data[32 * (1 + SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS)];
|
unsigned char data[32 * (1 + SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS)];
|
||||||
} secp256k1_surjectionproof;
|
} secp256k1_surjectionproof;
|
||||||
|
|
||||||
|
#ifndef USE_REDUCED_SURJECTION_PROOF_SIZE
|
||||||
/** Parse a surjection proof
|
/** Parse a surjection proof
|
||||||
*
|
*
|
||||||
* Returns: 1 when the proof could be parsed, 0 otherwise.
|
* Returns: 1 when the proof could be parsed, 0 otherwise.
|
||||||
@ -70,6 +74,7 @@ SECP256K1_API int secp256k1_surjectionproof_parse(
|
|||||||
const unsigned char *input,
|
const unsigned char *input,
|
||||||
size_t inputlen
|
size_t inputlen
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Serialize a surjection proof
|
/** Serialize a surjection proof
|
||||||
*
|
*
|
||||||
@ -143,7 +148,8 @@ SECP256K1_API size_t secp256k1_surjectionproof_serialized_size(
|
|||||||
* e.g. in a coinjoin with others' inputs, an ephemeral tag can be given;
|
* 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.)
|
* 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: 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
|
* n_input_tags_to_use: the number of inputs to select randomly to put in the anonymity set
|
||||||
|
* Must be <= SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS
|
||||||
* fixed_output_tag: fixed output tag
|
* fixed_output_tag: fixed output tag
|
||||||
* max_n_iterations: the maximum number of iterations to do before giving up. Because the
|
* max_n_iterations: the maximum number of iterations to do before giving up. Because the
|
||||||
* maximum number of inputs (SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) is
|
* maximum number of inputs (SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) is
|
||||||
@ -237,6 +243,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_generat
|
|||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8);
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef USE_REDUCED_SURJECTION_PROOF_SIZE
|
||||||
/** Surjection proof verification function
|
/** Surjection proof verification function
|
||||||
* Returns 0: proof was invalid
|
* Returns 0: proof was invalid
|
||||||
* 1: proof was valid
|
* 1: proof was valid
|
||||||
@ -254,6 +261,7 @@ SECP256K1_API int secp256k1_surjectionproof_verify(
|
|||||||
size_t n_ephemeral_input_tags,
|
size_t n_ephemeral_input_tags,
|
||||||
const secp256k1_generator* ephemeral_output_tag
|
const secp256k1_generator* ephemeral_output_tag
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,20 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#if defined HAVE_CONFIG_H
|
||||||
|
#include "libsecp256k1-config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "include/secp256k1_rangeproof.h"
|
||||||
|
#include "include/secp256k1_surjectionproof.h"
|
||||||
#include "modules/rangeproof/borromean.h"
|
#include "modules/rangeproof/borromean.h"
|
||||||
#include "modules/surjection/surjection_impl.h"
|
#include "modules/surjection/surjection_impl.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "include/secp256k1_rangeproof.h"
|
|
||||||
#include "include/secp256k1_surjectionproof.h"
|
#ifdef USE_REDUCED_SURJECTION_PROOF_SIZE
|
||||||
|
#undef SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS
|
||||||
|
#define SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS 16
|
||||||
|
#endif
|
||||||
|
|
||||||
static size_t secp256k1_count_bits_set(const unsigned char* data, size_t count) {
|
static size_t secp256k1_count_bits_set(const unsigned char* data, size_t count) {
|
||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
@ -35,6 +44,9 @@ static size_t secp256k1_count_bits_set(const unsigned char* data, size_t count)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_REDUCED_SURJECTION_PROOF_SIZE
|
||||||
|
static
|
||||||
|
#endif
|
||||||
int secp256k1_surjectionproof_parse(const secp256k1_context* ctx, secp256k1_surjectionproof *proof, const unsigned char *input, size_t inputlen) {
|
int secp256k1_surjectionproof_parse(const secp256k1_context* ctx, secp256k1_surjectionproof *proof, const unsigned char *input, size_t inputlen) {
|
||||||
size_t n_inputs;
|
size_t n_inputs;
|
||||||
size_t signature_len;
|
size_t signature_len;
|
||||||
@ -213,6 +225,7 @@ int secp256k1_surjectionproof_initialize(const secp256k1_context* ctx, secp256k1
|
|||||||
ARG_CHECK(fixed_output_tag != NULL);
|
ARG_CHECK(fixed_output_tag != NULL);
|
||||||
ARG_CHECK(random_seed32 != NULL);
|
ARG_CHECK(random_seed32 != NULL);
|
||||||
ARG_CHECK(n_input_tags <= SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS);
|
ARG_CHECK(n_input_tags <= SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS);
|
||||||
|
ARG_CHECK(n_input_tags_to_use <= SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS);
|
||||||
ARG_CHECK(n_input_tags_to_use <= n_input_tags);
|
ARG_CHECK(n_input_tags_to_use <= n_input_tags);
|
||||||
(void) ctx;
|
(void) ctx;
|
||||||
|
|
||||||
@ -270,10 +283,8 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s
|
|||||||
size_t n_total_pubkeys;
|
size_t n_total_pubkeys;
|
||||||
size_t n_used_pubkeys;
|
size_t n_used_pubkeys;
|
||||||
size_t ring_input_index = 0;
|
size_t ring_input_index = 0;
|
||||||
secp256k1_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
secp256k1_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS];
|
||||||
secp256k1_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
secp256k1_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS];
|
||||||
secp256k1_ge inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
|
||||||
secp256k1_ge output;
|
|
||||||
unsigned char msg32[32];
|
unsigned char msg32[32];
|
||||||
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
VERIFY_CHECK(ctx != NULL);
|
||||||
@ -312,17 +323,14 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
secp256k1_generator_load(&output, ephemeral_output_tag);
|
if (secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, ephemeral_input_tags, n_total_pubkeys, proof->used_inputs, ephemeral_output_tag, input_index, &ring_input_index) == 0) {
|
||||||
for (i = 0; i < n_total_pubkeys; i++) {
|
return 0;
|
||||||
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 */
|
/* Produce signature */
|
||||||
rsizes[0] = (int) n_used_pubkeys;
|
rsizes[0] = (int) n_used_pubkeys;
|
||||||
indices[0] = (int) ring_input_index;
|
indices[0] = (int) ring_input_index;
|
||||||
secp256k1_surjection_genmessage(msg32, inputs, n_total_pubkeys, &output);
|
secp256k1_surjection_genmessage(msg32, ephemeral_input_tags, n_total_pubkeys, ephemeral_output_tag);
|
||||||
if (secp256k1_surjection_genrand(borromean_s, n_used_pubkeys, &blinding_key) == 0) {
|
if (secp256k1_surjection_genrand(borromean_s, n_used_pubkeys, &blinding_key) == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -340,15 +348,16 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_REDUCED_SURJECTION_PROOF_SIZE
|
||||||
|
static
|
||||||
|
#endif
|
||||||
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) {
|
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 rsizes[1]; /* array needed for borromean sig API */
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t n_total_pubkeys;
|
size_t n_total_pubkeys;
|
||||||
size_t n_used_pubkeys;
|
size_t n_used_pubkeys;
|
||||||
secp256k1_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
secp256k1_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS];
|
||||||
secp256k1_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
secp256k1_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS];
|
||||||
secp256k1_ge inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
|
||||||
secp256k1_ge output;
|
|
||||||
unsigned char msg32[32];
|
unsigned char msg32[32];
|
||||||
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
VERIFY_CHECK(ctx != NULL);
|
||||||
@ -364,12 +373,12 @@ int secp256k1_surjectionproof_verify(const secp256k1_context* ctx, const secp256
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
secp256k1_generator_load(&output, ephemeral_output_tag);
|
/* Reject proofs with too many used inputs in USE_REDUCED_SURJECTION_PROOF_SIZE mode */
|
||||||
for (i = 0; i < n_total_pubkeys; i++) {
|
if (n_used_pubkeys > SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS) {
|
||||||
secp256k1_generator_load(&inputs[i], &ephemeral_input_tags[i]);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, inputs, n_total_pubkeys, proof->used_inputs, &output, 0, NULL) == 0) {
|
if (secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, ephemeral_input_tags, n_total_pubkeys, proof->used_inputs, ephemeral_output_tag, 0, NULL) == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,7 +391,7 @@ int secp256k1_surjectionproof_verify(const secp256k1_context* ctx, const secp256
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
secp256k1_surjection_genmessage(msg32, inputs, n_total_pubkeys, &output);
|
secp256k1_surjection_genmessage(msg32, ephemeral_input_tags, n_total_pubkeys, ephemeral_output_tag);
|
||||||
return secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, &proof->data[0], borromean_s, ring_pubkeys, rsizes, 1, msg32, 32);
|
return secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, &proof->data[0], borromean_s, ring_pubkeys, rsizes, 1, msg32, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
#include "scalar.h"
|
#include "scalar.h"
|
||||||
#include "hash.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) {
|
SECP256K1_INLINE static void secp256k1_surjection_genmessage(unsigned char *msg32, const secp256k1_generator *ephemeral_input_tags, size_t n_input_tags, const secp256k1_generator *ephemeral_output_tag) {
|
||||||
/* compute message */
|
/* compute message */
|
||||||
size_t i;
|
size_t i;
|
||||||
unsigned char pk_ser[33];
|
unsigned char pk_ser[33];
|
||||||
@ -24,12 +24,12 @@ SECP256K1_INLINE static void secp256k1_surjection_genmessage(unsigned char *msg3
|
|||||||
|
|
||||||
secp256k1_sha256_initialize(&sha256_en);
|
secp256k1_sha256_initialize(&sha256_en);
|
||||||
for (i = 0; i < n_input_tags; i++) {
|
for (i = 0; i < n_input_tags; i++) {
|
||||||
secp256k1_eckey_pubkey_serialize(&ephemeral_input_tags[i], pk_ser, &pk_len, 1);
|
pk_ser[0] = 2 + (ephemeral_input_tags[i].data[63] & 1);
|
||||||
assert(pk_len == sizeof(pk_ser));
|
memcpy(&pk_ser[1], &ephemeral_input_tags[i].data[0], 32);
|
||||||
secp256k1_sha256_write(&sha256_en, pk_ser, pk_len);
|
secp256k1_sha256_write(&sha256_en, pk_ser, pk_len);
|
||||||
}
|
}
|
||||||
secp256k1_eckey_pubkey_serialize(ephemeral_output_tag, pk_ser, &pk_len, 1);
|
pk_ser[0] = 2 + (ephemeral_output_tag->data[63] & 1);
|
||||||
assert(pk_len == sizeof(pk_ser));
|
memcpy(&pk_ser[1], &ephemeral_output_tag->data[0], 32);
|
||||||
secp256k1_sha256_write(&sha256_en, pk_ser, pk_len);
|
secp256k1_sha256_write(&sha256_en, pk_ser, pk_len);
|
||||||
secp256k1_sha256_finalize(&sha256_en, msg32);
|
secp256k1_sha256_finalize(&sha256_en, msg32);
|
||||||
}
|
}
|
||||||
@ -61,24 +61,29 @@ SECP256K1_INLINE static int secp256k1_surjection_genrand(secp256k1_scalar *s, si
|
|||||||
return 1;
|
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) {
|
SECP256K1_INLINE static int secp256k1_surjection_compute_public_keys(secp256k1_gej *pubkeys, size_t n_pubkeys, const secp256k1_generator *input_tags, size_t n_input_tags, const unsigned char *used_tags, const secp256k1_generator *output_tag, size_t input_index, size_t *ring_input_index) {
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t j = 0;
|
size_t j = 0;
|
||||||
for (i = 0; i < n_input_tags; i++) {
|
for (i = 0; i < n_input_tags; i++) {
|
||||||
if (used_tags[i / 8] & (1 << (i % 8))) {
|
if (used_tags[i / 8] & (1 << (i % 8))) {
|
||||||
secp256k1_ge tmpge;
|
secp256k1_ge tmpge;
|
||||||
secp256k1_ge_neg(&tmpge, &input_tags[i]);
|
secp256k1_generator_load(&tmpge, &input_tags[i]);
|
||||||
|
secp256k1_ge_neg(&tmpge, &tmpge);
|
||||||
|
|
||||||
|
VERIFY_CHECK(j < SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS);
|
||||||
|
VERIFY_CHECK(j < n_pubkeys);
|
||||||
secp256k1_gej_set_ge(&pubkeys[j], &tmpge);
|
secp256k1_gej_set_ge(&pubkeys[j], &tmpge);
|
||||||
secp256k1_gej_add_ge_var(&pubkeys[j], &pubkeys[j], output_tag, NULL);
|
|
||||||
|
secp256k1_generator_load(&tmpge, output_tag);
|
||||||
|
secp256k1_gej_add_ge_var(&pubkeys[j], &pubkeys[j], &tmpge, NULL);
|
||||||
if (ring_input_index != NULL && input_index == i) {
|
if (ring_input_index != NULL && input_index == i) {
|
||||||
*ring_input_index = j;
|
*ring_input_index = j;
|
||||||
}
|
}
|
||||||
j++;
|
j++;
|
||||||
if (j > n_pubkeys) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Caller needs to ensure that the number of set bits in used_tags (which we counted in j) equals n_pubkeys. */
|
||||||
|
VERIFY_CHECK(j == n_pubkeys);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,6 +427,7 @@ static void test_gen_verify(size_t n_inputs, size_t n_used) {
|
|||||||
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof, serialized_len));
|
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]);
|
result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs]);
|
||||||
CHECK(result == 1);
|
CHECK(result == 1);
|
||||||
|
|
||||||
/* various fail cases */
|
/* various fail cases */
|
||||||
if (n_inputs > 1) {
|
if (n_inputs > 1) {
|
||||||
result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs - 1]);
|
result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs - 1]);
|
||||||
@ -441,6 +442,15 @@ static void test_gen_verify(size_t n_inputs, size_t n_used) {
|
|||||||
n_inputs += 1;
|
n_inputs += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < n_inputs; i++) {
|
||||||
|
/* flip bit */
|
||||||
|
proof.used_inputs[i / 8] ^= (1 << (i % 8));
|
||||||
|
result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs]);
|
||||||
|
CHECK(result == 0);
|
||||||
|
/* reset the bit */
|
||||||
|
proof.used_inputs[i / 8] ^= (1 << (i % 8));
|
||||||
|
}
|
||||||
|
|
||||||
/* cleanup */
|
/* cleanup */
|
||||||
for (i = 0; i < n_inputs + 1; i++) {
|
for (i = 0; i < n_inputs + 1; i++) {
|
||||||
free(input_blinding_key[i]);
|
free(input_blinding_key[i]);
|
||||||
@ -456,7 +466,6 @@ static void test_no_used_inputs_verify(void) {
|
|||||||
size_t n_ephemeral_input_tags = 1;
|
size_t n_ephemeral_input_tags = 1;
|
||||||
secp256k1_generator ephemeral_output_tag;
|
secp256k1_generator ephemeral_output_tag;
|
||||||
unsigned char blinding_key[32];
|
unsigned char blinding_key[32];
|
||||||
secp256k1_ge inputs[1];
|
|
||||||
secp256k1_ge output;
|
secp256k1_ge output;
|
||||||
secp256k1_sha256 sha256_e0;
|
secp256k1_sha256 sha256_e0;
|
||||||
int result;
|
int result;
|
||||||
@ -477,8 +486,7 @@ static void test_no_used_inputs_verify(void) {
|
|||||||
|
|
||||||
/* create "borromean signature" which is just a hash of metadata (pubkeys, etc) in this case */
|
/* 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(&output, &ephemeral_output_tag);
|
||||||
secp256k1_generator_load(&inputs[0], &ephemeral_input_tags[0]);
|
secp256k1_surjection_genmessage(proof.data, ephemeral_input_tags, 1, &ephemeral_output_tag);
|
||||||
secp256k1_surjection_genmessage(proof.data, inputs, 1, &output);
|
|
||||||
secp256k1_sha256_initialize(&sha256_e0);
|
secp256k1_sha256_initialize(&sha256_e0);
|
||||||
secp256k1_sha256_write(&sha256_e0, proof.data, 32);
|
secp256k1_sha256_write(&sha256_e0, proof.data, 32);
|
||||||
secp256k1_sha256_finalize(&sha256_e0, proof.data);
|
secp256k1_sha256_finalize(&sha256_e0, proof.data);
|
||||||
@ -668,12 +676,11 @@ void run_surjection_tests(void) {
|
|||||||
test_input_selection(0);
|
test_input_selection(0);
|
||||||
test_input_selection(1);
|
test_input_selection(1);
|
||||||
test_input_selection(5);
|
test_input_selection(5);
|
||||||
test_input_selection(100);
|
test_input_selection(SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS);
|
||||||
test_input_selection(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS);
|
|
||||||
|
|
||||||
test_input_selection_distribution();
|
test_input_selection_distribution();
|
||||||
test_gen_verify(10, 3);
|
test_gen_verify(10, 3);
|
||||||
test_gen_verify(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS);
|
test_gen_verify(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS);
|
||||||
test_no_used_inputs_verify();
|
test_no_used_inputs_verify();
|
||||||
test_bad_serialize();
|
test_bad_serialize();
|
||||||
test_bad_parse();
|
test_bad_parse();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user