From d46fc3c191c764a040f8a58fcad298cf482743e2 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Tue, 5 Jul 2016 15:46:07 +0000 Subject: [PATCH] rangeproof: expose sidechannel message field in the signing API Including a fix by Jonas Nick. --- include/secp256k1_rangeproof.h | 4 ++- src/bench_rangeproof.c | 2 +- src/modules/rangeproof/main_impl.h | 5 +-- src/modules/rangeproof/rangeproof_impl.h | 13 +++++++- src/modules/rangeproof/tests_impl.h | 39 ++++++++++++++++++++---- 5 files changed, 52 insertions(+), 11 deletions(-) diff --git a/include/secp256k1_rangeproof.h b/include/secp256k1_rangeproof.h index 94cfaee8..7803e7a5 100644 --- a/include/secp256k1_rangeproof.h +++ b/include/secp256k1_rangeproof.h @@ -199,7 +199,9 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign( const unsigned char *nonce, int exp, int min_bits, - uint64_t value + uint64_t value, + const unsigned char *message, + size_t msg_len ) 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. diff --git a/src/bench_rangeproof.c b/src/bench_rangeproof.c index 76466574..66fb2869 100644 --- a/src/bench_rangeproof.c +++ b/src/bench_rangeproof.c @@ -30,7 +30,7 @@ static void bench_rangeproof_setup(void* arg) { 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, (const unsigned char*)&data->commit, 0, data->min_bits, data->v)); + CHECK(secp256k1_rangeproof_sign(data->ctx, data->proof, &data->len, 0, &data->commit, data->blind, (const unsigned char*)&data->commit, 0, data->min_bits, data->v, NULL, 0)); CHECK(secp256k1_rangeproof_verify(data->ctx, &minv, &maxv, &data->commit, data->proof, data->len)); } diff --git a/src/modules/rangeproof/main_impl.h b/src/modules/rangeproof/main_impl.h index a1ad6715..c743b6d7 100644 --- a/src/modules/rangeproof/main_impl.h +++ b/src/modules/rangeproof/main_impl.h @@ -175,7 +175,8 @@ int secp256k1_rangeproof_verify(const secp256k1_context* ctx, uint64_t *min_valu } int secp256k1_rangeproof_sign(const secp256k1_context* ctx, unsigned char *proof, size_t *plen, uint64_t min_value, - const secp256k1_pedersen_commitment *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value){ + const secp256k1_pedersen_commitment *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value, + const unsigned char *message, size_t msg_len){ secp256k1_ge commitp; ARG_CHECK(ctx != NULL); ARG_CHECK(proof != NULL); @@ -187,7 +188,7 @@ int secp256k1_rangeproof_sign(const secp256k1_context* ctx, unsigned char *proof ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); secp256k1_pedersen_commitment_load(&commitp, commit); return secp256k1_rangeproof_sign_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, - proof, plen, min_value, &commitp, blind, nonce, exp, min_bits, value); + proof, plen, min_value, &commitp, blind, nonce, exp, min_bits, value, message, msg_len); } #endif diff --git a/src/modules/rangeproof/rangeproof_impl.h b/src/modules/rangeproof/rangeproof_impl.h index 3f2c3a46..efd43e12 100644 --- a/src/modules/rangeproof/rangeproof_impl.h +++ b/src/modules/rangeproof/rangeproof_impl.h @@ -191,7 +191,8 @@ SECP256K1_INLINE static int secp256k1_range_proveparams(uint64_t *v, size_t *rin SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmult_context* ecmult_ctx, const secp256k1_ecmult_gen_context* ecmult_gen_ctx, unsigned char *proof, size_t *plen, uint64_t min_value, - const secp256k1_ge *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value){ + const secp256k1_ge *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value, + const unsigned char *message, size_t msg_len){ 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. */ @@ -231,6 +232,13 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul } len += 8; } + /* Do we have enough room in the proof for the message? Each ring gives us 128 bytes, but the + * final ring is used to encode the blinding factor and the value, so we can't use that. (Well, + * technically there are 64 bytes available if we avoided the other data, but this is difficult + * because it's not always in the same place. */ + if (msg_len > 0 && msg_len > 128 * (rings - 1)) { + return 0; + } /* Do we have enough room for the proof? */ if (*plen - len < 32 * (npub + rings - 1) + 32 + ((rings+6) >> 3)) { return 0; @@ -241,6 +249,9 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul secp256k1_sha256_write(&sha256_m, proof, len); memset(prep, 0, 4096); + if (message != NULL) { + memcpy(prep, message, msg_len); + } /* Note, the data corresponding to the blinding factors must be zero. */ if (rsizes[rings - 1] > 1) { size_t idx; diff --git a/src/modules/rangeproof/tests_impl.h b/src/modules/rangeproof/tests_impl.h index 7cd27969..c8815afb 100644 --- a/src/modules/rangeproof/tests_impl.h +++ b/src/modules/rangeproof/tests_impl.h @@ -7,6 +7,8 @@ #ifndef SECP256K1_MODULE_RANGEPROOF_TESTS #define SECP256K1_MODULE_RANGEPROOF_TESTS +#include + #include "group.h" #include "scalar.h" #include "testrand.h" @@ -166,17 +168,42 @@ void test_rangeproof(void) { size_t i; size_t j; size_t k; + /* Short message is a Simone de Beauvoir quote */ + const unsigned char message_short[120] = "When I see my own likeness in the depths of someone else's consciousness, I always experience a moment of panic."; + /* Long message is 0xA5 with a bunch of this quote in the middle */ + unsigned char message_long[3968]; + memset(message_long, 0xa5, sizeof(message_long)); + for (i = 1200; i < 3600; i += 120) { + memcpy(&message_long[i], message_short, sizeof(message_short)); + } + secp256k1_rand256(blind); for (i = 0; i < 11; i++) { v = testvs[i]; CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v)); for (vmin = 0; vmin < (i<9 && i > 0 ? 2 : 1); vmin++) { + const unsigned char *input_message = NULL; + size_t input_message_len = 0; + /* vmin is always either 0 or 1; if it is 1, then we have no room for a message. + * If it's 0, we use "minimum encoding" and only have room for a small message when + * `testvs[i]` is >= 4; for a large message when it's >= 2^32. */ + if (vmin == 0 && i > 2) { + input_message = message_short; + input_message_len = sizeof(message_short); + } + if (vmin == 0 && i > 7) { + input_message = message_long; + input_message_len = sizeof(message_long); + } len = 5134; - CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, 0, 0, v)); + CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, 0, 0, v, input_message, input_message_len)); CHECK(len <= 5134); mlen = 4096; CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len)); - for (j = 0; j < mlen; j++) { + if (input_message != NULL) { + CHECK(memcmp(message, input_message, input_message_len) == 0); + } + for (j = input_message_len; j < mlen; j++) { CHECK(message[j] == 0); } CHECK(mlen <= 4096); @@ -185,7 +212,7 @@ void test_rangeproof(void) { CHECK(minv <= v); CHECK(maxv >= v); len = 5134; - CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, -1, 64, v)); + CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, -1, 64, v, NULL, 0)); CHECK(len <= 73); CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len)); CHECK(memcmp(blindout, blind, 32) == 0); @@ -199,7 +226,7 @@ void test_rangeproof(void) { 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.data, i, 0, v)); + CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, i, 0, v, NULL, 0)); CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len)); CHECK(len <= 5134); CHECK(minv <= v); @@ -211,7 +238,7 @@ void test_rangeproof(void) { 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.data, 0, 3, v)); + CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, 0, 3, v, NULL, 0)); CHECK(len <= 5134); for (i = 0; i < len*8; i++) { proof[i >> 3] ^= 1 << (i & 7); @@ -242,7 +269,7 @@ void test_rangeproof(void) { if (min_bits < 0) { min_bits = -min_bits; } - CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, exp, min_bits, v)); + CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, exp, min_bits, v, NULL, 0)); CHECK(len <= 5134); mlen = 4096; CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len));