rangeproof: expose sidechannel message field in the signing API

Including a fix by Jonas Nick.
This commit is contained in:
Andrew Poelstra 2016-07-05 15:46:07 +00:00
parent cf40b1bed2
commit d46fc3c191
5 changed files with 52 additions and 11 deletions

View File

@ -199,7 +199,9 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign(
const unsigned char *nonce, const unsigned char *nonce,
int exp, int exp,
int min_bits, 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); ) 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. /** Extract some basic information from a range-proof.

View File

@ -30,7 +30,7 @@ static void bench_rangeproof_setup(void* arg) {
for (i = 0; i < 32; i++) data->blind[i] = i + 1; for (i = 0; i < 32; i++) data->blind[i] = i + 1;
CHECK(secp256k1_pedersen_commit(data->ctx, &data->commit, data->blind, data->v)); CHECK(secp256k1_pedersen_commit(data->ctx, &data->commit, data->blind, data->v));
data->len = 5134; 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)); CHECK(secp256k1_rangeproof_verify(data->ctx, &minv, &maxv, &data->commit, data->proof, data->len));
} }

View File

@ -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, 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; secp256k1_ge commitp;
ARG_CHECK(ctx != NULL); ARG_CHECK(ctx != NULL);
ARG_CHECK(proof != 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)); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
secp256k1_pedersen_commitment_load(&commitp, commit); secp256k1_pedersen_commitment_load(&commitp, commit);
return secp256k1_rangeproof_sign_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, 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 #endif

View File

@ -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, SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmult_context* ecmult_ctx,
const secp256k1_ecmult_gen_context* ecmult_gen_ctx, const secp256k1_ecmult_gen_context* ecmult_gen_ctx,
unsigned char *proof, size_t *plen, uint64_t min_value, 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_gej pubs[128]; /* Candidate digits for our proof, most inferred. */
secp256k1_scalar s[128]; /* Signatures in our proof, most forged. */ secp256k1_scalar s[128]; /* Signatures in our proof, most forged. */
secp256k1_scalar sec[32]; /* Blinding factors for the correct digits. */ 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; 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? */ /* Do we have enough room for the proof? */
if (*plen - len < 32 * (npub + rings - 1) + 32 + ((rings+6) >> 3)) { if (*plen - len < 32 * (npub + rings - 1) + 32 + ((rings+6) >> 3)) {
return 0; return 0;
@ -241,6 +249,9 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul
secp256k1_sha256_write(&sha256_m, proof, len); secp256k1_sha256_write(&sha256_m, proof, len);
memset(prep, 0, 4096); memset(prep, 0, 4096);
if (message != NULL) {
memcpy(prep, message, msg_len);
}
/* Note, the data corresponding to the blinding factors must be zero. */ /* Note, the data corresponding to the blinding factors must be zero. */
if (rsizes[rings - 1] > 1) { if (rsizes[rings - 1] > 1) {
size_t idx; size_t idx;

View File

@ -7,6 +7,8 @@
#ifndef SECP256K1_MODULE_RANGEPROOF_TESTS #ifndef SECP256K1_MODULE_RANGEPROOF_TESTS
#define SECP256K1_MODULE_RANGEPROOF_TESTS #define SECP256K1_MODULE_RANGEPROOF_TESTS
#include <string.h>
#include "group.h" #include "group.h"
#include "scalar.h" #include "scalar.h"
#include "testrand.h" #include "testrand.h"
@ -166,17 +168,42 @@ void test_rangeproof(void) {
size_t i; size_t i;
size_t j; size_t j;
size_t k; 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); secp256k1_rand256(blind);
for (i = 0; i < 11; i++) { for (i = 0; i < 11; i++) {
v = testvs[i]; v = testvs[i];
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v)); CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v));
for (vmin = 0; vmin < (i<9 && i > 0 ? 2 : 1); vmin++) { 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; 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); CHECK(len <= 5134);
mlen = 4096; mlen = 4096;
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len)); 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(message[j] == 0);
} }
CHECK(mlen <= 4096); CHECK(mlen <= 4096);
@ -185,7 +212,7 @@ void test_rangeproof(void) {
CHECK(minv <= v); CHECK(minv <= v);
CHECK(maxv >= v); CHECK(maxv >= v);
len = 5134; 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(len <= 73);
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len)); CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len));
CHECK(memcmp(blindout, blind, 32) == 0); CHECK(memcmp(blindout, blind, 32) == 0);
@ -199,7 +226,7 @@ void test_rangeproof(void) {
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v)); CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v));
for (i = 0; i < 19; i++) { for (i = 0; i < 19; i++) {
len = 5134; 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(secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len));
CHECK(len <= 5134); CHECK(len <= 5134);
CHECK(minv <= v); CHECK(minv <= v);
@ -211,7 +238,7 @@ void test_rangeproof(void) {
v = secp256k1_rands64(0, 255); v = secp256k1_rands64(0, 255);
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v)); CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v));
len = 5134; 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); CHECK(len <= 5134);
for (i = 0; i < len*8; i++) { for (i = 0; i < len*8; i++) {
proof[i >> 3] ^= 1 << (i & 7); proof[i >> 3] ^= 1 << (i & 7);
@ -242,7 +269,7 @@ void test_rangeproof(void) {
if (min_bits < 0) { if (min_bits < 0) {
min_bits = -min_bits; 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); CHECK(len <= 5134);
mlen = 4096; mlen = 4096;
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len)); CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len));