rangeproof: add summing function for blinded generators; drop excess and gen from verify_tally

This commit is contained in:
Andrew Poelstra 2016-07-06 15:44:09 +00:00 committed by Pieter Wuille
parent 4577c24234
commit 6eebf82d8a
10 changed files with 263 additions and 84 deletions

View File

@ -16,8 +16,7 @@ extern "C" {
* guaranteed to be portable between different platforms or versions. It is
* however guaranteed to be 33 bytes in size, and can be safely copied/moved.
* If you need to convert to a format suitable for storage or transmission, use
* the secp256k1_pedersen_commitment_serialize_* and
* secp256k1_pedersen_commitment_serialize_* functions.
* secp256k1_pedersen_commitment_serialize and secp256k1_pedersen_commitment_parse.
*
* Furthermore, it is guaranteed to identical signatures will have identical
* representation, so they can be memcmp'ed.
@ -71,7 +70,7 @@ void secp256k1_pedersen_context_initialize(secp256k1_context* ctx);
*
* Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA.
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
const secp256k1_context* ctx,
secp256k1_pedersen_commitment *commit,
const unsigned char *blind,
@ -88,7 +87,7 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
* 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(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum(
const secp256k1_context* ctx,
unsigned char *blind_out,
const unsigned char * const *blinds,
@ -104,24 +103,57 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum(
* pcnt: number of commitments pointed to by commits.
* ncommits: pointer to array of pointers to the negative commitments. (cannot be NULL if ncnt is non-zero)
* ncnt: number of commitments pointed to by ncommits.
* excess: signed 64bit amount to add to the total to bring it to zero, can be negative.
*
* This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) - excess*H == 0.
* This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) == 0.
*
* A pedersen commitment is xG + vH where G and H are generators for the secp256k1 group and x is a blinding factor,
* while v is the committed value. For a collection of commitments to sum to zero both their blinding factors and
* values must sum to zero.
* A pedersen commitment is xG + vA where G and A are generators for the secp256k1 group and x is a blinding factor,
* while v is the committed value. For a collection of commitments to sum to zero, for each distinct generator
* A all blinding factors and all values must sum to zero.
*
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
const secp256k1_context* ctx,
const secp256k1_pedersen_commitment * const* commits,
size_t pcnt,
const secp256k1_pedersen_commitment * const* ncommits,
size_t ncnt,
int64_t excess,
const secp256k1_generator *gen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(7);
size_t ncnt
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
/** Sets the final Pedersen blinding factor correctly when the generators themselves
* have blinding factors.
*
* Consider a generator of the form A' = A + rG, where A is the "real" generator
* but A' is the generator provided to verifiers. Then a Pedersen commitment
* P = vA' + r'G really has the form vA + (vr + r')G. To get all these (vr + r')
* to sum to zero for multiple commitments, we take three arrays consisting of
* the `v`s, `r`s, and `r'`s, respectively called `value`s, `generator_blind`s
* and `blinding_factor`s, and sum them.
*
* The function then subtracts the sum of all (vr + r') from the last element
* of the `blinding_factor` array, setting the total sum to zero.
*
* Returns 1 always.
*
* In: ctx: pointer to a context object
* value: array of asset values, `v` in the above paragraph.
* May not be NULL unless `n_total` is 0.
* generator_blind: array of asset blinding factors, `r` in the above paragraph
* May not be NULL unless `n_total` is 0.
* n_total: Total size of the above arrays
* n_inputs: How many of the initial array elements represent commitments that
* will be negated in the final sum
* In/Out: blinding_factor: array of commitment blinding factors, `r'` in the above paragraph
* May not be NULL unless `n_total` is 0.
* the last value will be modified to get the total sum to zero.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_generator_blind_sum(
const secp256k1_context* ctx,
const uint64_t *value,
const unsigned char* const* generator_blind,
unsigned char* const* blinding_factor,
size_t n_total,
size_t n_inputs
);
/** Initialize a context for usage with Pedersen commitments. */
void secp256k1_rangeproof_context_initialize(secp256k1_context* ctx);
@ -133,18 +165,22 @@ void secp256k1_rangeproof_context_initialize(secp256k1_context* ctx);
* commit: the commitment being proved. (cannot be NULL)
* proof: pointer to character array with the proof. (cannot be NULL)
* plen: length of proof in bytes.
* extra_commit: additional data covered in rangeproof signature
* extra_commit_len: length of extra_commit byte array (0 if NULL)
* Out: min_value: pointer to a unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL)
* max_value: pointer to a unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify(
const secp256k1_context* ctx,
uint64_t *min_value,
uint64_t *max_value,
const secp256k1_pedersen_commitment *commit,
const unsigned char *proof,
size_t plen,
const unsigned char *extra_commit,
size_t extra_commit_len,
const secp256k1_generator* gen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7);
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(9);
/** Verify a range proof proof and rewind the proof to recover information sent by its author.
* Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs, and the value and blinding were recovered.
@ -154,6 +190,8 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify(
* proof: pointer to character array with the proof. (cannot be NULL)
* plen: length of proof in bytes.
* nonce: 32-byte secret nonce used by the prover (cannot be NULL)
* extra_commit: additional data covered in rangeproof signature
* extra_commit_len: length of extra_commit byte array (0 if NULL)
* 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.
@ -161,7 +199,7 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify(
* min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL)
* max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind(
const secp256k1_context* ctx,
unsigned char *blind_out,
uint64_t *value_out,
@ -173,8 +211,10 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind(
const secp256k1_pedersen_commitment *commit,
const unsigned char *proof,
size_t plen,
const unsigned char *extra_commit,
size_t extra_commit_len,
const secp256k1_generator *gen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(9) SECP256K1_ARG_NONNULL(10) SECP256K1_ARG_NONNULL(12);
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(9) SECP256K1_ARG_NONNULL(10) SECP256K1_ARG_NONNULL(14);
/** Author a proof that a committed value is within a range.
* Returns 1: Proof successfully created.
@ -189,6 +229,10 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind(
* (-1 is a special case that makes the value public. 0 is the most private.)
* min_bits: Number of bits of the value to keep private. (0 = auto/minimal, - 64).
* value: Actual value of the commitment.
* message: pointer to a byte array of data to be embedded in the rangeproof that can be recovered by rewinding the proof
* msg_len: size of the message to be embedded in the rangeproof
* extra_commit: additional data to be covered in rangeproof signature
* extra_commit_len: length of extra_commit byte array (0 if NULL)
* 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.
@ -198,7 +242,7 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind(
* This can randomly fail with probability around one in 2^100. If this happens, buy a lottery ticket and retry with a different nonce or blinding.
*
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign(
const secp256k1_context* ctx,
unsigned char *proof,
size_t *plen,
@ -211,8 +255,10 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign(
uint64_t value,
const unsigned char *message,
size_t msg_len,
const unsigned char *extra_commit,
size_t extra_commit_len,
const secp256k1_generator *gen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(13);
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(15);
/** Extract some basic information from a range-proof.
* Returns 1: Information successfully extracted.
@ -225,7 +271,7 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign(
* min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL)
* max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_info(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_info(
const secp256k1_context* ctx,
int *exp,
int *mantissa,

View File

@ -12,6 +12,7 @@
#include "field.h"
#include "group.h"
#include "hash.h"
#include "scalar.h"
static void secp256k1_generator_load(secp256k1_ge* ge, const secp256k1_generator* gen) {
secp256k1_fe fe;

View File

@ -118,8 +118,7 @@ int secp256k1_pedersen_blind_sum(const secp256k1_context* ctx, unsigned char *bl
}
/* Takes two lists of commitments and sums the first set and subtracts the second and verifies that they sum to excess. */
int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const secp256k1_pedersen_commitment * const* commits, size_t pcnt, const secp256k1_pedersen_commitment * const* ncommits, size_t ncnt, int64_t excess, const secp256k1_generator* gen) {
secp256k1_ge genp;
int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const secp256k1_pedersen_commitment * const* commits, size_t pcnt, const secp256k1_pedersen_commitment * const* ncommits, size_t ncnt) {
secp256k1_gej accj;
secp256k1_ge add;
size_t i;
@ -127,17 +126,6 @@ int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const secp256k
ARG_CHECK(!pcnt || (commits != NULL));
ARG_CHECK(!ncnt || (ncommits != NULL));
secp256k1_gej_set_infinity(&accj);
secp256k1_generator_load(&genp, gen);
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(&accj, ex, &genp);
if (neg) {
secp256k1_gej_neg(&accj, &accj);
}
}
for (i = 0; i < ncnt; i++) {
secp256k1_pedersen_commitment_load(&add, ncommits[i]);
secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL);
@ -150,6 +138,60 @@ int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const secp256k
return secp256k1_gej_is_infinity(&accj);
}
int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, const uint64_t *value, const unsigned char* const* generator_blind, unsigned char* const* blinding_factor, size_t n_total, size_t n_inputs) {
secp256k1_scalar sum;
secp256k1_scalar tmp;
size_t i;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(n_total == 0 || value != NULL);
ARG_CHECK(n_total == 0 || generator_blind != NULL);
ARG_CHECK(n_total == 0 || blinding_factor != NULL);
ARG_CHECK(n_total > n_inputs);
(void) ctx;
if (n_total == 0) {
return 1;
}
secp256k1_scalar_set_int(&sum, 0);
for (i = 0; i < n_total; i++) {
int overflow = 0;
secp256k1_scalar addend;
secp256k1_scalar_set_u64(&addend, value[i]); /* s = v */
secp256k1_scalar_set_b32(&tmp, generator_blind[i], &overflow);
if (overflow == 1) {
secp256k1_scalar_clear(&tmp);
secp256k1_scalar_clear(&addend);
secp256k1_scalar_clear(&sum);
return 0;
}
secp256k1_scalar_mul(&addend, &addend, &tmp); /* s = vr */
secp256k1_scalar_set_b32(&tmp, blinding_factor[i], &overflow);
if (overflow == 1) {
secp256k1_scalar_clear(&tmp);
secp256k1_scalar_clear(&addend);
secp256k1_scalar_clear(&sum);
return 0;
}
secp256k1_scalar_add(&addend, &addend, &tmp); /* s = vr + r' */
secp256k1_scalar_cond_negate(&addend, i < n_inputs); /* s is negated if it's an input */
secp256k1_scalar_add(&sum, &sum, &addend); /* sum += s */
secp256k1_scalar_clear(&addend);
}
/* Right now tmp has the last pedersen blinding factor. Subtract the sum from it. */
secp256k1_scalar_negate(&sum, &sum);
secp256k1_scalar_add(&tmp, &tmp, &sum);
secp256k1_scalar_get_b32(blinding_factor[n_total - 1], &tmp);
secp256k1_scalar_clear(&tmp);
secp256k1_scalar_clear(&sum);
return 1;
}
int secp256k1_rangeproof_info(const secp256k1_context* ctx, int *exp, int *mantissa,
uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, size_t plen) {
size_t offset;
@ -167,7 +209,7 @@ int secp256k1_rangeproof_info(const secp256k1_context* ctx, int *exp, int *manti
int secp256k1_rangeproof_rewind(const secp256k1_context* ctx,
unsigned char *blind_out, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce,
uint64_t *min_value, uint64_t *max_value,
const secp256k1_pedersen_commitment *commit, const unsigned char *proof, size_t plen, const secp256k1_generator* gen) {
const secp256k1_pedersen_commitment *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_generator* gen) {
secp256k1_ge commitp;
secp256k1_ge genp;
ARG_CHECK(ctx != NULL);
@ -180,11 +222,11 @@ int secp256k1_rangeproof_rewind(const secp256k1_context* ctx,
secp256k1_pedersen_commitment_load(&commitp, commit);
secp256k1_generator_load(&genp, gen);
return secp256k1_rangeproof_verify_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx,
blind_out, value_out, message_out, outlen, nonce, min_value, max_value, &commitp, proof, plen, &genp);
blind_out, value_out, message_out, outlen, nonce, min_value, max_value, &commitp, proof, plen, extra_commit, extra_commit_len, &genp);
}
int secp256k1_rangeproof_verify(const secp256k1_context* ctx, uint64_t *min_value, uint64_t *max_value,
const secp256k1_pedersen_commitment *commit, const unsigned char *proof, size_t plen, const secp256k1_generator* gen) {
const secp256k1_pedersen_commitment *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_generator* gen) {
secp256k1_ge commitp;
secp256k1_ge genp;
ARG_CHECK(ctx != NULL);
@ -196,12 +238,12 @@ int secp256k1_rangeproof_verify(const secp256k1_context* ctx, uint64_t *min_valu
secp256k1_pedersen_commitment_load(&commitp, commit);
secp256k1_generator_load(&genp, gen);
return secp256k1_rangeproof_verify_impl(&ctx->ecmult_ctx, NULL,
NULL, NULL, NULL, NULL, NULL, min_value, max_value, &commitp, proof, plen, &genp);
NULL, NULL, NULL, NULL, NULL, min_value, max_value, &commitp, proof, plen, extra_commit, extra_commit_len, &genp);
}
int secp256k1_rangeproof_sign(const secp256k1_context* ctx, unsigned char *proof, size_t *plen, uint64_t min_value,
const secp256k1_pedersen_commitment *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value,
const unsigned char *message, size_t msg_len, const secp256k1_generator* gen){
const unsigned char *message, size_t msg_len, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_generator* gen){
secp256k1_ge commitp;
secp256k1_ge genp;
ARG_CHECK(ctx != NULL);
@ -215,7 +257,7 @@ int secp256k1_rangeproof_sign(const secp256k1_context* ctx, unsigned char *proof
secp256k1_pedersen_commitment_load(&commitp, commit);
secp256k1_generator_load(&genp, gen);
return secp256k1_rangeproof_sign_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx,
proof, plen, min_value, &commitp, blind, nonce, exp, min_bits, value, message, msg_len, &genp);
proof, plen, min_value, &commitp, blind, nonce, exp, min_bits, value, message, msg_len, extra_commit, extra_commit_len, &genp);
}
#endif

View File

@ -15,6 +15,7 @@
static int secp256k1_rangeproof_verify_impl(const secp256k1_ecmult_context* ecmult_ctx,
const secp256k1_ecmult_gen_context* ecmult_gen_ctx,
unsigned char *blindout, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce,
uint64_t *min_value, uint64_t *max_value, const secp256k1_ge *commit, const unsigned char *proof, size_t plen, const secp256k1_ge* genp);
uint64_t *min_value, uint64_t *max_value, const secp256k1_ge *commit, const unsigned char *proof, size_t plen,
const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_ge* genp);
#endif

View File

@ -193,7 +193,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul
const secp256k1_ecmult_gen_context* ecmult_gen_ctx,
unsigned char *proof, size_t *plen, uint64_t min_value,
const secp256k1_ge *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value,
const unsigned char *message, size_t msg_len, const secp256k1_ge* genp){
const unsigned char *message, size_t msg_len, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_ge* genp){
secp256k1_gej pubs[128]; /* Candidate digits for our proof, most inferred. */
secp256k1_scalar s[128]; /* Signatures in our proof, most forged. */
secp256k1_scalar sec[32]; /* Blinding factors for the correct digits. */
@ -318,6 +318,9 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul
npub += rsizes[i];
}
secp256k1_rangeproof_pub_expand(pubs, exp, rsizes, rings, genp);
if (extra_commit != NULL) {
secp256k1_sha256_write(&sha256_m, extra_commit, extra_commit_len);
}
secp256k1_sha256_finalize(&sha256_m, tmp);
if (!secp256k1_borromean_sign(ecmult_ctx, ecmult_gen_ctx, &proof[len], s, pubs, k, sec, rsizes, secidx, rings, tmp, 32)) {
return 0;
@ -538,7 +541,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_getheader_impl(size_t *offset,
SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecmult_context* ecmult_ctx,
const secp256k1_ecmult_gen_context* ecmult_gen_ctx,
unsigned char *blindout, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce,
uint64_t *min_value, uint64_t *max_value, const secp256k1_ge *commit, const unsigned char *proof, size_t plen, const secp256k1_ge* genp) {
uint64_t *min_value, uint64_t *max_value, const secp256k1_ge *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_ge* genp) {
secp256k1_gej accj;
secp256k1_gej pubs[128];
secp256k1_ge c;
@ -640,6 +643,9 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm
/*Extra data found, reject.*/
return 0;
}
if (extra_commit != NULL) {
secp256k1_sha256_write(&sha256_m, extra_commit, extra_commit_len);
}
secp256k1_sha256_finalize(&sha256_m, m);
ret = secp256k1_borromean_verify(ecmult_ctx, nonce ? evalues : NULL, e0, s, pubs, rsizes, rings, m, 32);
if (ret && nonce) {

View File

@ -16,7 +16,7 @@
#include "include/secp256k1_rangeproof.h"
void test_pedersen(void) {
static void test_pedersen(void) {
secp256k1_pedersen_commitment commits[19];
const secp256k1_pedersen_commitment *cptr[19];
unsigned char blinds[32*19];
@ -40,23 +40,12 @@ void test_pedersen(void) {
values[i] = secp256k1_rands64(0, INT64_MAX - totalv);
totalv += values[i];
}
if (secp256k1_rand32() & 1) {
for (i = 0; i < outputs; i++) {
int64_t max = INT64_MAX;
if (totalv < 0) {
max += totalv;
}
values[i + inputs] = secp256k1_rands64(0, max);
totalv -= values[i + inputs];
}
} else {
for (i = 0; i < outputs - 1; i++) {
values[i + inputs] = secp256k1_rands64(0, totalv);
totalv -= values[i + inputs];
}
values[total - 1] = totalv >> (secp256k1_rand32() & 1);
totalv -= values[total - 1];
for (i = 0; i < outputs - 1; i++) {
values[i + inputs] = secp256k1_rands64(0, totalv);
totalv -= values[i + inputs];
}
values[total - 1] = totalv;
for (i = 0; i < total - 1; i++) {
random_scalar_order(&s);
secp256k1_scalar_get_b32(&blinds[i * 32], &s);
@ -65,8 +54,11 @@ void test_pedersen(void) {
for (i = 0; i < total; i++) {
CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
}
CHECK(secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs, totalv, secp256k1_generator_h));
CHECK(!secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs, totalv + 1, secp256k1_generator_h));
CHECK(secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs));
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[inputs], outputs, cptr, inputs));
if (inputs > 0 && values[0] > 0) {
CHECK(!secp256k1_pedersen_verify_tally(ctx, cptr, inputs - 1, &cptr[inputs], outputs));
}
random_scalar_order(&s);
for (i = 0; i < 4; i++) {
secp256k1_scalar_get_b32(&blinds[i * 32], &s);
@ -77,15 +69,11 @@ void test_pedersen(void) {
for (i = 0; i < 3; i++) {
CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
}
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[2], 1, -1, secp256k1_generator_h));
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[2], 1, &cptr[1], 1, 1, secp256k1_generator_h));
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1, 0, secp256k1_generator_h));
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[1], 1, INT64_MAX, secp256k1_generator_h));
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1, 0, secp256k1_generator_h));
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[0], 1, -INT64_MAX, secp256k1_generator_h));
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1));
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1));
}
void test_borromean(void) {
static void test_borromean(void) {
unsigned char e0[32];
secp256k1_scalar s[64];
secp256k1_gej pubs[64];
@ -150,7 +138,7 @@ void test_borromean(void) {
}
}
void test_rangeproof(void) {
static void test_rangeproof(void) {
const uint64_t testvs[11] = {0, 1, 5, 11, 65535, 65537, INT32_MAX, UINT32_MAX, INT64_MAX - 1, INT64_MAX, UINT64_MAX};
secp256k1_pedersen_commitment commit;
secp256k1_pedersen_commitment commit2;
@ -196,10 +184,10 @@ void test_rangeproof(void) {
input_message_len = sizeof(message_long);
}
len = 5134;
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, 0, 0, v, input_message, input_message_len, secp256k1_generator_h));
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, 0, 0, v, input_message, input_message_len, NULL, 0, secp256k1_generator_h));
CHECK(len <= 5134);
mlen = 4096;
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len, secp256k1_generator_h));
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
if (input_message != NULL) {
CHECK(memcmp(message, input_message, input_message_len) == 0);
}
@ -212,9 +200,21 @@ 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, NULL, 0, secp256k1_generator_h));
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, -1, 64, v, NULL, 0, NULL, 0, secp256k1_generator_h));
CHECK(len <= 73);
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, secp256k1_generator_h));
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
CHECK(memcmp(blindout, blind, 32) == 0);
CHECK(vout == v);
CHECK(minv == v);
CHECK(maxv == v);
/* Check with a committed message */
len = 5134;
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, -1, 64, v, NULL, 0, message_short, sizeof(message_short), secp256k1_generator_h));
CHECK(len <= 73);
CHECK(!secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
CHECK(!secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, message_long, sizeof(message_long), secp256k1_generator_h));
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, message_short, sizeof(message_short), secp256k1_generator_h));
CHECK(memcmp(blindout, blind, 32) == 0);
CHECK(vout == v);
CHECK(minv == v);
@ -226,11 +226,13 @@ void test_rangeproof(void) {
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
for (i = 0; i < 19; i++) {
len = 5134;
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, i, 0, v, NULL, 0, secp256k1_generator_h));
CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, secp256k1_generator_h));
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, i, 0, v, NULL, 0, NULL, 0, secp256k1_generator_h));
CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
CHECK(len <= 5134);
CHECK(minv <= v);
CHECK(maxv >= v);
/* Make sure it fails when validating with a committed message */
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, message_short, sizeof(message_short), secp256k1_generator_h));
}
secp256k1_rand256(blind);
{
@ -238,14 +240,14 @@ void test_rangeproof(void) {
v = secp256k1_rands64(0, 255);
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
len = 5134;
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, 0, 3, v, NULL, 0, secp256k1_generator_h));
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, 0, 3, v, NULL, 0, NULL, 0, secp256k1_generator_h));
CHECK(len <= 5134);
for (i = 0; i < len*8; i++) {
proof[i >> 3] ^= 1 << (i & 7);
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, secp256k1_generator_h));
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
proof[i >> 3] ^= 1 << (i & 7);
}
CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, secp256k1_generator_h));
CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
CHECK(minv <= v);
CHECK(maxv >= v);
}
@ -269,10 +271,10 @@ 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, NULL, 0, secp256k1_generator_h));
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, exp, min_bits, v, NULL, 0, NULL, 0, secp256k1_generator_h));
CHECK(len <= 5134);
mlen = 4096;
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len, secp256k1_generator_h));
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
for (j = 0; j < mlen; j++) {
CHECK(message[j] == 0);
}
@ -281,7 +283,7 @@ void test_rangeproof(void) {
CHECK(vout == v);
CHECK(minv <= v);
CHECK(maxv >= v);
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, secp256k1_generator_h));
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
memcpy(&commit2, &commit, sizeof(commit));
}
for (j = 0; j < 10; j++) {
@ -290,13 +292,69 @@ void test_rangeproof(void) {
}
for (k = 0; k < 128; k++) {
len = k;
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit2, proof, len, secp256k1_generator_h));
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit2, proof, len, NULL, 0, secp256k1_generator_h));
}
len = secp256k1_rands64(0, 3072);
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit2, proof, len, secp256k1_generator_h));
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit2, proof, len, NULL, 0, secp256k1_generator_h));
}
}
#define MAX_N_GENS 30
void test_multiple_generators(void) {
const size_t n_inputs = (secp256k1_rand32() % (MAX_N_GENS / 2)) + 1;
const size_t n_outputs = (secp256k1_rand32() % (MAX_N_GENS / 2)) + 1;
const size_t n_generators = n_inputs + n_outputs;
unsigned char *generator_blind[MAX_N_GENS];
unsigned char *pedersen_blind[MAX_N_GENS];
secp256k1_generator generator[MAX_N_GENS];
secp256k1_pedersen_commitment commit[MAX_N_GENS];
const secp256k1_pedersen_commitment *commit_ptr[MAX_N_GENS];
size_t i;
int64_t total_value;
uint64_t value[MAX_N_GENS];
secp256k1_scalar s;
unsigned char generator_seed[32];
random_scalar_order(&s);
secp256k1_scalar_get_b32(generator_seed, &s);
/* Create all the needed generators */
for (i = 0; i < n_generators; i++) {
generator_blind[i] = (unsigned char*) malloc(32);
pedersen_blind[i] = (unsigned char*) malloc(32);
random_scalar_order(&s);
secp256k1_scalar_get_b32(generator_blind[i], &s);
random_scalar_order(&s);
secp256k1_scalar_get_b32(pedersen_blind[i], &s);
CHECK(secp256k1_generator_generate_blinded(ctx, &generator[i], generator_seed, generator_blind[i]));
commit_ptr[i] = &commit[i];
}
/* Compute all the values -- can be positive or negative */
total_value = 0;
for (i = 0; i < n_outputs; i++) {
value[n_inputs + i] = secp256k1_rands64(0, INT64_MAX - total_value);
total_value += value[n_inputs + i];
}
for (i = 0; i < n_inputs - 1; i++) {
value[i] = secp256k1_rands64(0, total_value);
total_value -= value[i];
}
value[i] = total_value;
/* Correct for blinding factors and do the commitments */
CHECK(secp256k1_pedersen_blind_generator_blind_sum(ctx, value, (const unsigned char * const *) generator_blind, pedersen_blind, n_generators, n_inputs));
for (i = 0; i < n_generators; i++) {
CHECK(secp256k1_pedersen_commit(ctx, &commit[i], pedersen_blind[i], value[i], &generator[i]));
}
/* Verify */
CHECK(secp256k1_pedersen_verify_tally(ctx, &commit_ptr[0], n_inputs, &commit_ptr[n_inputs], n_outputs));
}
void run_rangeproof_tests(void) {
int i;
for (i = 0; i < 10*count; i++) {
@ -306,6 +364,7 @@ void run_rangeproof_tests(void) {
test_borromean();
}
test_rangeproof();
test_multiple_generators();
}
#endif

View File

@ -38,6 +38,9 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b
/** Set a scalar to an unsigned integer. */
static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v);
/** Set a scalar to an unsigned 64-bit integer */
static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint64_t v);
/** Convert a scalar to a byte array. */
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a);

View File

@ -7,6 +7,8 @@
#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_
#define _SECP256K1_SCALAR_REPR_IMPL_H_
#include "scalar.h"
/* Limbs of the secp256k1 order. */
#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL)
#define SECP256K1_N_1 ((uint64_t)0xBAAEDCE6AF48A03BULL)
@ -38,6 +40,13 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig
r->d[3] = 0;
}
SECP256K1_INLINE static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint64_t v) {
r->d[0] = v;
r->d[1] = 0;
r->d[2] = 0;
r->d[3] = 0;
}
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6);
return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1);

View File

@ -56,6 +56,17 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig
r->d[7] = 0;
}
SECP256K1_INLINE static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint64_t v) {
r->d[0] = v;
r->d[1] = v >> 32;
r->d[2] = 0;
r->d[3] = 0;
r->d[4] = 0;
r->d[5] = 0;
r->d[6] = 0;
r->d[7] = 0;
}
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5);
return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1);

View File

@ -17,6 +17,7 @@ SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a)
SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; }
SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; }
SECP256K1_INLINE static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint64_t v) { *r = v % EXHAUSTIVE_TEST_ORDER; }
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
if (offset < 32)