diff --git a/.gitignore b/.gitignore index c4e5d9ccd..673768efc 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ bench_schnorrsig bench_sign bench_verify bench_recover +bench_whitelist bench_internal tests exhaustive_tests diff --git a/src/modules/rangeproof/borromean.h b/src/modules/rangeproof/borromean.h index efd4da162..917225ed4 100644 --- a/src/modules/rangeproof/borromean.h +++ b/src/modules/rangeproof/borromean.h @@ -14,11 +14,13 @@ #include "ecmult.h" #include "ecmult_gen.h" +#include "modules/rangeproof/borromean_util.h" + int secp256k1_borromean_verify(secp256k1_scalar *evalues, const unsigned char *e0, const secp256k1_scalar *s, const secp256k1_gej *pubs, const size_t *rsizes, size_t nrings, const unsigned char *m, size_t mlen); int secp256k1_borromean_sign(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 size_t *rsizes, const size_t *secidx, size_t nrings, const unsigned char *m, size_t mlen); + unsigned char *e0, secp256k1_scalar *s, const secp256k1_gej *pubs, const secp256k1_scalar *sec, + const size_t *rsizes, const secp256k1_borromean_sz_closure* secidx_closure, size_t nrings, const unsigned char *m, size_t mlen); #endif diff --git a/src/modules/rangeproof/borromean_impl.h b/src/modules/rangeproof/borromean_impl.h index 0b8dcd478..97117962e 100644 --- a/src/modules/rangeproof/borromean_impl.h +++ b/src/modules/rangeproof/borromean_impl.h @@ -109,8 +109,8 @@ int secp256k1_borromean_verify(secp256k1_scalar *evalues, const unsigned char *e } int secp256k1_borromean_sign(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 size_t *rsizes, const size_t *secidx, size_t nrings, const unsigned char *m, size_t mlen) { + unsigned char *e0, secp256k1_scalar *s, const secp256k1_gej *pubs, const secp256k1_scalar *sec, + const size_t *rsizes, const secp256k1_borromean_sz_closure* secidx_closure, size_t nrings, const unsigned char *m, size_t mlen) { secp256k1_gej rgej; secp256k1_ge rge; secp256k1_scalar ens; @@ -125,23 +125,24 @@ int secp256k1_borromean_sign(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, 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(secidx_closure != NULL); VERIFY_CHECK(nrings > 0); VERIFY_CHECK(m != NULL); secp256k1_sha256_initialize(&sha256_e0); count = 0; for (i = 0; i < nrings; i++) { + size_t secidx_i = secidx_closure->call(secidx_closure, i); VERIFY_CHECK(INT_MAX - count > rsizes[i]); - secp256k1_ecmult_gen(ecmult_gen_ctx, &rgej, &k[i]); + /* We have been provided an s value that we will just overwrite, so use it as a nonce */ + secp256k1_ecmult_gen(ecmult_gen_ctx, &rgej, &s[count + secidx_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++) { + 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)) { @@ -165,13 +166,18 @@ int secp256k1_borromean_sign(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_sha256_finalize(&sha256_e0, e0); count = 0; for (i = 0; i < nrings; i++) { + size_t secidx_i = secidx_closure->call(secidx_closure, i); + /* We have been provided an s value that we will just overwrite, so use it as a nonce */ + secp256k1_scalar k = s[count + secidx_i]; + secp256k1_scalar_clear(&s[count + secidx_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++) { + for (j = 0; j < secidx_i; j++) { secp256k1_ecmult(&rgej, &pubs[count + j], &ens, &s[count + j]); if (secp256k1_gej_is_infinity(&rgej)) { return 0; @@ -186,7 +192,7 @@ int secp256k1_borromean_sign(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, } 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]); + secp256k1_scalar_add(&s[count + j], &s[count + j], &k); if (secp256k1_scalar_is_zero(&s[count + j])) { return 0; } diff --git a/src/modules/rangeproof/borromean_util.h b/src/modules/rangeproof/borromean_util.h new file mode 100644 index 000000000..f6e08b0f8 --- /dev/null +++ b/src/modules/rangeproof/borromean_util.h @@ -0,0 +1,32 @@ +/********************************************************************** + * Copyright (c) 2021 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_BORROMEAN_UTIL_H_ +#define _SECP256K1_BORROMEAN_UTIL_H_ + +#include /* for size_t */ +#include /* for uint64_t */ + +/** A pointer to a function that returns a size_t given a ring index + * + * Used by borromean_sign to look up the size of each ring and the secret + * index, to avoid caching these values which would take excessive stack. + * As it turns out, both these values can be determined from the mantissa (for + * rangeproofs) or are constant (for surjection proofs or ring signatures) + * + * In: input: a single closed-over value + * index: which ring in the borromean ring signature this lookup + * function should look up + */ +typedef struct secp256k1_borromean_sz_closure { + uint64_t input; + size_t (*call)(const struct secp256k1_borromean_sz_closure* self, size_t index); +} secp256k1_borromean_sz_closure; + +/** Create a sz_closure that just returns a constant */ +secp256k1_borromean_sz_closure secp256k1_borromean_sz_closure_const(uint64_t c); + +#endif diff --git a/src/modules/rangeproof/borromean_util_impl.h b/src/modules/rangeproof/borromean_util_impl.h new file mode 100644 index 000000000..c81d04188 --- /dev/null +++ b/src/modules/rangeproof/borromean_util_impl.h @@ -0,0 +1,26 @@ +/********************************************************************** + * Copyright (c) 2021 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_BORROMEAN_UTIL_IMPL_H_ +#define _SECP256K1_BORROMEAN_UTIL_IMPL_H_ + +#include "modules/rangeproof/borromean_util.h" +#include "util.h" + +static size_t secp256k1_borromean_sz_closure_const_call(const secp256k1_borromean_sz_closure* self, size_t index) { + (void) index; + return self->input; +} + +secp256k1_borromean_sz_closure secp256k1_borromean_sz_closure_const(uint64_t c) { + secp256k1_borromean_sz_closure ret; + VERIFY_CHECK(c < SIZE_MAX); + ret.input = c; + ret.call = secp256k1_borromean_sz_closure_const_call; + return ret; +} + +#endif diff --git a/src/modules/rangeproof/main_impl.h b/src/modules/rangeproof/main_impl.h index 9129e4c30..e3ee103e1 100644 --- a/src/modules/rangeproof/main_impl.h +++ b/src/modules/rangeproof/main_impl.h @@ -11,6 +11,7 @@ #include "modules/rangeproof/pedersen_impl.h" #include "modules/rangeproof/borromean_impl.h" +#include "modules/rangeproof/borromean_util_impl.h" #include "modules/rangeproof/rangeproof_impl.h" /** Alternative generator for secp256k1. @@ -231,17 +232,23 @@ int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, c 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) { + secp256k1_rangeproof_header header; size_t offset; - uint64_t scale; ARG_CHECK(exp != NULL); ARG_CHECK(mantissa != NULL); ARG_CHECK(min_value != NULL); ARG_CHECK(max_value != NULL); ARG_CHECK(proof != NULL); offset = 0; - scale = 1; (void)ctx; - return secp256k1_rangeproof_getheader_impl(&offset, exp, mantissa, &scale, min_value, max_value, proof, plen); + if (!secp256k1_rangeproof_header_parse(&header, &offset, proof, plen)) { + return 0; + } + *exp = header.exp; + *mantissa = header.mantissa; + *min_value = header.min_value; + *max_value = header.max_value; + return 1; } int secp256k1_rangeproof_rewind(const secp256k1_context* ctx, diff --git a/src/modules/rangeproof/rangeproof.h b/src/modules/rangeproof/rangeproof.h index fd8cf9505..dd0d71bf0 100644 --- a/src/modules/rangeproof/rangeproof.h +++ b/src/modules/rangeproof/rangeproof.h @@ -12,6 +12,79 @@ #include "ecmult.h" #include "ecmult_gen.h" +/** Structure representing data directly encoded into a rangeproof header + * + * A rangeproof is a proof, associated with a Pedersen commitment, that a + * "proven value" in is the range [0, 2^mantissa]. The committed value is + * related to the proven value by the contents of this header, as + * + * committed = min_value + 10^exp * proven + */ +typedef struct secp256k1_rangeproof_header { + /** Power of ten to multiply the proven value by, or -1 for an exact proof + * + * Encoded in the header. */ + int exp; + /** Number of bits used to represent the proven value + * + * Encoded in the header. */ + size_t mantissa; + /** 10 to the power of exp, or 1 for a proof of an exact value. + * + * Implied by `exp`, not encoded. */ + uint64_t scale; + /** Minimum value for the range (added to the proven value). + * + * Encoded in the header. */ + uint64_t min_value; + /** Maximum value for the range (min_value + 10^exp * 2^mantissa). + * + * Implied by `min_value`, `exp`, `mantissa`. Not encoded. */ + uint64_t max_value; + /** Number of rings to use in the underlying borromean ring signature + * + * Implied by `mantissa`. Not encoded. */ + size_t n_rings; + /** Number of public keys to use in the underlying borromean ring signature + * + * Implied by `mantissa`. Not encoded. */ + size_t n_pubs; + /** Number of keys in each ring + * + * Implied by `mantissa`. Not encoded. */ + size_t rsizes[32]; +} secp256k1_rangeproof_header; + +/** Parses out a rangeproof header from a rangeproof and fills in all fields + * + * Returns: 1 on success, 0 on failure + * Out: header: the parsed header + * offset: the number of bytes of `proof` that the header occupied + * In: proof: the proof to parse the header out of + * plen: the length of the proof + */ +static int secp256k1_rangeproof_header_parse( + secp256k1_rangeproof_header* header, + size_t* offset, + const unsigned char* proof, + size_t plen +); + +/** Serializes out a rangeproof header which has at least `exp`, `min_value` and `mantissa` set + * + * Returns: 1 on success, 0 on failure + * Out: proof: the buffer to serialize into + * offset: the number of bytes of `proof` that the header occupies + * In: plen: the length of the proof buffer + * header: the header to serialize + */ +static int secp256k1_rangeproof_header_serialize( + unsigned char* proof, + size_t plen, + size_t* offset, + const secp256k1_rangeproof_header* header +); + static int secp256k1_rangeproof_verify_impl(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, diff --git a/src/modules/rangeproof/rangeproof_impl.h b/src/modules/rangeproof/rangeproof_impl.h index 184b79882..78afcbb33 100644 --- a/src/modules/rangeproof/rangeproof_impl.h +++ b/src/modules/rangeproof/rangeproof_impl.h @@ -17,6 +17,208 @@ #include "modules/rangeproof/pedersen.h" #include "modules/rangeproof/borromean.h" +#include "modules/rangeproof/rangeproof.h" + +static size_t secp256k1_borromean_sz_closure_secidx_call(const secp256k1_borromean_sz_closure* self, size_t index) { + return (self->input >> (index * 2)) & 3; +} + +/** Create a sz_closure for the secret index within each ring */ +static secp256k1_borromean_sz_closure secp256k1_borromean_sz_closure_secidx(uint64_t value) { + secp256k1_borromean_sz_closure ret; + ret.input = value; + ret.call = secp256k1_borromean_sz_closure_secidx_call; + return ret; +} + +/** Takes a header with `exp`, `mantissa` and `min_value` set and fills in all other fields + * + * Returns 1 on success, 0 if the `max_value` field would exceed UINT64_MAX */ +static int secp256k1_rangeproof_header_expand(secp256k1_rangeproof_header* header) { + if (header->mantissa == 0) { + header->n_rings = 1; + header->n_pubs = 1; + header->max_value = 0; + header->rsizes[0] = 1; + } else { + size_t i; + + header->n_rings = header->mantissa / 2; + header->n_pubs = 4 * header->n_rings; + header->max_value = UINT64_MAX >> (64 - header->mantissa); + for (i = 0; i < header->n_rings; i++) { + header->rsizes[i] = 4; + } + + if (header->mantissa & 1) { + header->rsizes[header->n_rings] = 2; + header->n_pubs += 2; + header->n_rings++; + } + } + VERIFY_CHECK(header->n_rings <= 32); + + header->scale = 1; + if (header->exp > 0) { + int i; + for (i = 0; i < header->exp; i++) { + if (header->max_value > UINT64_MAX / 10) { + return 0; + } + header->max_value *= 10; + header->scale *= 10; + } + } + + if (header->max_value > UINT64_MAX - header->min_value) { + return 0; + } + header->max_value += header->min_value; + + return 1; +} + +static int secp256k1_rangeproof_header_parse( + secp256k1_rangeproof_header* header, + size_t* offset, + const unsigned char* proof, + size_t plen +) { + memset(header, 0, sizeof(*header)); + *offset = 0; + + if (plen < 65 || ((proof[0] & 128) != 0)) { + return 0; + } + /* Read `exp` and `mantissa` */ + if (proof[0] & 64) { + *offset += 1; + header->exp = proof[0] & 31; + if (header->exp > 18) { + return 0; + } + header->mantissa = proof[1] + 1; + if (header->mantissa > 64) { + return 0; + } + } else { + /* single-value proof */ + header->mantissa = 0; + header->exp = -1; + } + *offset += 1; + /* Read `min_value` */ + if (proof[0] & 32) { + size_t i; + for (i = 0; i < 8; i++) { + header->min_value = (header->min_value << 8) | proof[*offset + i]; + } + *offset += 8; + } else { + header->min_value = 0; + } + + return secp256k1_rangeproof_header_expand(header); +} + +static int secp256k1_rangeproof_header_set_for_value( + secp256k1_rangeproof_header* header, + uint64_t* proven_value, + const uint64_t min_value, + const uint64_t min_bits, + const int exp, + const uint64_t value +) { + memset(header, 0, sizeof(*header)); + *proven_value = 0; + + /* Sanity checks */ + if (min_value > value || min_bits > 64 || exp < -1 || exp > 18) { + return 0; + } + + /* Start by just using the user's requested values, then adjust them in + * various ways to make them compatible. This is probably not advisable + * from a privacy point-of-view but it's important to be compatible with + * the 2015-era API, and all of these issues will go away when we merge + * Bulletproofs. */ + header->exp = exp; + header->min_value = min_value; + header->mantissa = min_bits ? min_bits : 1; /* force mantissa to be nonzero */ + + /* Special-case single-value proofs */ + if (header->exp == -1) { + header->mantissa = 0; /* ignore user's min_bits */ + return secp256k1_rangeproof_header_expand(header); + } + + /* Deal with extreme values (copied directly from 2015 code) */ + 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. + */ + header->exp = 0; + } + { + /* If the user has asked for more bits of proof then there is room for in the exponent, reduce the exponent. */ + uint64_t max = min_bits ? (UINT64_MAX >> (64 - min_bits)) : 0; + int i; + for (i = 0; i < header->exp && max <= UINT64_MAX / 10; i++) { + max *= 10; + } + header->exp = i; + } + + + /* Increase the mantissa from min_bits until it actually covers the proven value */ + if (!secp256k1_rangeproof_header_expand(header)) { + return 0; + } + *proven_value = (value - header->min_value) / header->scale; + while (header->mantissa < 64 && (*proven_value >> header->mantissa) > 0) { + header->mantissa++; + } + /* Fudge min_value so we don't lose the low-order digits of `value` */ + header->min_value = value - (*proven_value * header->scale); + + /* Increasing the mantissa will have increased the number of rings etc + * so re-expand the header to recompute the other derived values. */ + return secp256k1_rangeproof_header_expand(header); +} + +static int secp256k1_rangeproof_header_serialize( + unsigned char* proof, + size_t plen, + size_t* offset, + const secp256k1_rangeproof_header* header +) { + *offset = 0; + if (plen < 65) { + return 0; + } + + /* Write control byte */ + proof[0] = (header->exp >= 0 ? (64 | header->exp) : 0) | (header->min_value ? 32 : 0); + *offset += 1; + /* Write mantissa, for non-exact-value proofs */ + if (header->exp >= 0) { + VERIFY_CHECK(header->mantissa > 0 && header->mantissa <= 64); + proof[1] = header->mantissa - 1; + *offset += 1; + } + /* Write min_value, if present */ + if (header->min_value > 0) { + size_t i; + for (i = 0; i < 8; i++) { + proof[*offset + i] = (header->min_value >> ((7-i) * 8)) & 255; + } + *offset += 8; + } + + return 1; +} SECP256K1_INLINE static void secp256k1_rangeproof_pub_expand(secp256k1_gej *pubs, int exp, size_t *rsizes, size_t rings, const secp256k1_ge* genp) { @@ -59,11 +261,32 @@ SECP256K1_INLINE static void secp256k1_rangeproof_serialize_point(unsigned char* secp256k1_fe_get_b32(data + 1, &pointx); } -SECP256K1_INLINE static int secp256k1_rangeproof_genrand(secp256k1_scalar *sec, secp256k1_scalar *s, unsigned char *message, - size_t *rsizes, size_t rings, const unsigned char *nonce, const secp256k1_ge *commit, const unsigned char *proof, size_t len, const secp256k1_ge* genp) { - unsigned char tmp[32]; +SECP256K1_INLINE static void secp256k1_rangeproof_init_rng( + secp256k1_rfc6979_hmac_sha256* rng, + const unsigned char* nonce, + const secp256k1_ge* commit, + const unsigned char *proof, + const size_t len, + const secp256k1_ge* genp +) { unsigned char rngseed[32 + 33 + 33 + 10]; - secp256k1_rfc6979_hmac_sha256 rng; + VERIFY_CHECK(len <= 10); + + memcpy(rngseed, nonce, 32); + secp256k1_rangeproof_serialize_point(rngseed + 32, commit); + secp256k1_rangeproof_serialize_point(rngseed + 32 + 33, genp); + memcpy(rngseed + 33 + 33 + 32, proof, len); + secp256k1_rfc6979_hmac_sha256_initialize(rng, rngseed, 32 + 33 + 33 + len); +} + +SECP256K1_INLINE static int secp256k1_rangeproof_genrand( + secp256k1_scalar *sec, + secp256k1_scalar *s, + unsigned char *message, + const secp256k1_rangeproof_header* header, + secp256k1_rfc6979_hmac_sha256* rng +) { + unsigned char tmp[32]; secp256k1_scalar acc; int overflow; int ret; @@ -71,20 +294,14 @@ SECP256K1_INLINE static int secp256k1_rangeproof_genrand(secp256k1_scalar *sec, size_t j; int b; size_t npub; - VERIFY_CHECK(len <= 10); - memcpy(rngseed, nonce, 32); - secp256k1_rangeproof_serialize_point(rngseed + 32, commit); - secp256k1_rangeproof_serialize_point(rngseed + 32 + 33, genp); - memcpy(rngseed + 33 + 33 + 32, proof, len); - secp256k1_rfc6979_hmac_sha256_initialize(&rng, rngseed, 32 + 33 + 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); + for (i = 0; i < header->n_rings; i++) { + if (i < header->n_rings - 1) { + secp256k1_rfc6979_hmac_sha256_generate(rng, tmp, 32); do { - secp256k1_rfc6979_hmac_sha256_generate(&rng, tmp, 32); + 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]); @@ -92,8 +309,8 @@ SECP256K1_INLINE static int secp256k1_rangeproof_genrand(secp256k1_scalar *sec, secp256k1_scalar_negate(&acc, &acc); sec[i] = acc; } - for (j = 0; j < rsizes[i]; j++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, tmp, 32); + for (j = 0; j < header->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]; @@ -105,142 +322,63 @@ SECP256K1_INLINE static int secp256k1_rangeproof_genrand(secp256k1_scalar *sec, npub++; } } - secp256k1_rfc6979_hmac_sha256_finalize(&rng); + 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, size_t *rings, size_t *rsizes, size_t *npub, size_t *secidx, uint64_t *min_value, - int *mantissa, uint64_t *scale, int *exp, int *min_bits, uint64_t value) { - size_t 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; (int) i < *exp && (v2 <= UINT64_MAX / 10); i++) { - *v /= 10; - v2 *= 10; - } - *exp = i; - v2 = *v; - for (i = 0; (int) 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_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 unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_ge* genp){ + secp256k1_rangeproof_header header; 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 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. */ - size_t rings; /* How many digits will our proof cover. */ - size_t rsizes[32]; /* How many possible values there are for each place. */ - size_t secidx[32]; /* Which digit is the correct one. */ + secp256k1_rfc6979_hmac_sha256 genrand_rng; + secp256k1_borromean_sz_closure secidx_closure; size_t len; /* Number of bytes used so far. */ size_t i; + size_t pub_idx; int overflow; - size_t npub; len = 0; - if (*plen < 65 || min_value > value || min_bits > 64 || min_bits < 0 || exp < -1 || exp > 18) { + if (*plen < 65) { return 0; } - if (!secp256k1_range_proveparams(&v, &rings, rsizes, &npub, secidx, &min_value, &mantissa, &scale, &exp, &min_bits, value)) { + + if (!secp256k1_rangeproof_header_set_for_value(&header, &v, min_value, min_bits, exp, 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; + if (header.exp >= 0) { + secidx_closure = secp256k1_borromean_sz_closure_secidx(v); + } else { + secidx_closure = secp256k1_borromean_sz_closure_const(0); } + + VERIFY_CHECK(v * header.scale + header.min_value == value); + VERIFY_CHECK(header.n_rings > 0); + VERIFY_CHECK(header.n_rings <= 32); + VERIFY_CHECK(header.n_pubs <= 128); + + secp256k1_rangeproof_header_serialize (proof, *plen, &len, &header); + /* 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)) { + if (msg_len > 0 && msg_len > 128 * (header.n_rings - 1)) { return 0; } /* Do we have enough room for the proof? */ - if (*plen - len < 32 * (npub + rings - 1) + 32 + ((rings+6) >> 3)) { + if (*plen - len < 32 * (header.n_pubs + header.n_rings - 1) + 32 + ((header.n_rings + 6) >> 3)) { return 0; } secp256k1_sha256_initialize(&sha256_m); @@ -255,27 +393,23 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul memcpy(prep, message, msg_len); } /* Note, the data corresponding to the blinding factors must be zero. */ - if (rsizes[rings - 1] > 1) { + if (header.rsizes[header.n_rings - 1] > 1) { size_t idx; /* Value encoding sidechannel. */ - idx = rsizes[rings - 1] - 1; - idx -= secidx[rings - 1] == idx; - idx = ((rings - 1) * 4 + idx) * 32; + idx = header.rsizes[header.n_rings - 1] - 1; + idx -= secidx_closure.call(&secidx_closure, header.n_rings - 1) == idx; + idx = ((header.n_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, genp)) { + secp256k1_rangeproof_init_rng(&genrand_rng, nonce, commit, proof, len, genp); + if (!secp256k1_rangeproof_genrand(sec, s, prep, &header, &genrand_rng)) { 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 @@ -283,30 +417,31 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul * 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])) { + secp256k1_scalar_add(&sec[header.n_rings - 1], &sec[header.n_rings - 1], &stmp); + if (overflow || secp256k1_scalar_is_zero(&sec[header.n_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++) { + for (i = 0; i < (header.n_rings + 6) >> 3; i++) { signs[i] = 0; len++; } - npub = 0; - for (i = 0; i < rings; i++) { + pub_idx = 0; + for (i = 0; i < header.n_rings; i++) { + uint64_t secidx_i = secidx_closure.call(&secidx_closure, i); /*OPT: Use the precomputed gen2 basis?*/ - secp256k1_pedersen_ecmult(ecmult_gen_ctx, &pubs[npub], &sec[i], ((uint64_t)secidx[i] * scale) << (i*2), genp); - if (secp256k1_gej_is_infinity(&pubs[npub])) { + secp256k1_pedersen_ecmult(ecmult_gen_ctx, &pubs[pub_idx], &sec[i], (secidx_i * header.scale) << (i*2), genp); + if (secp256k1_gej_is_infinity(&pubs[pub_idx])) { return 0; } - if (i < rings - 1) { + if (i < header.n_rings - 1) { unsigned char tmpc[33]; secp256k1_ge c; unsigned char quadness; /*OPT: split loop and batch invert.*/ - /*OPT: do not compute full pubs[npub] in ge form; we only need x */ - secp256k1_ge_set_gej_var(&c, &pubs[npub]); + /*OPT: do not compute full pubs[pub_idx] in ge form; we only need x */ + secp256k1_ge_set_gej_var(&c, &pubs[pub_idx]); secp256k1_rangeproof_serialize_point(tmpc, &c); quadness = tmpc[0]; secp256k1_sha256_write(&sha256_m, tmpc, 33); @@ -314,19 +449,19 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul memcpy(&proof[len], tmpc + 1, 32); len += 32; } - npub += rsizes[i]; + pub_idx += header.rsizes[i]; } - secp256k1_rangeproof_pub_expand(pubs, exp, rsizes, rings, genp); + secp256k1_rangeproof_pub_expand(pubs, header.exp, header.rsizes, header.n_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_gen_ctx, &proof[len], s, pubs, k, sec, rsizes, secidx, rings, tmp, 32)) { + if (!secp256k1_borromean_sign(ecmult_gen_ctx, &proof[len], s, pubs, sec, header.rsizes, &secidx_closure, header.n_rings, tmp, 32)) { return 0; } len += 32; - for (i = 0; i < npub; i++) { - secp256k1_scalar_get_b32(&proof[len],&s[i]); + for (i = 0; i < pub_idx; i++) { + secp256k1_scalar_get_b32(&proof[len], &s[i]); len += 32; } VERIFY_CHECK(len <= *plen); @@ -362,7 +497,8 @@ SECP256K1_INLINE static void secp256k1_rangeproof_ch32xor(unsigned char *x, cons SECP256K1_INLINE static int secp256k1_rangeproof_rewind_inner(secp256k1_scalar *blind, uint64_t *v, unsigned char *m, size_t *mlen, secp256k1_scalar *ev, secp256k1_scalar *s, - size_t *rsizes, size_t rings, const unsigned char *nonce, const secp256k1_ge *commit, const unsigned char *proof, size_t len, const secp256k1_ge *genp) { + secp256k1_rangeproof_header* header, const unsigned char *nonce, const secp256k1_ge *commit, const unsigned char *proof, size_t len, const secp256k1_ge *genp) { + secp256k1_rfc6979_hmac_sha256 genrand_rng; secp256k1_scalar s_orig[128]; secp256k1_scalar sec[32]; secp256k1_scalar stmp; @@ -376,15 +512,15 @@ SECP256K1_INLINE static int secp256k1_rangeproof_rewind_inner(secp256k1_scalar * size_t skip1; size_t skip2; size_t 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, genp); + secp256k1_rangeproof_init_rng(&genrand_rng, nonce, commit, proof, len, genp); + if (!secp256k1_rangeproof_genrand(sec, s_orig, prep, header, &genrand_rng)) { + return 0; + } *v = UINT64_MAX; secp256k1_scalar_clear(blind); - if (rings == 1 && rsizes[0] == 1) { + if (header->n_rings == 1 && header->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) { @@ -395,11 +531,10 @@ SECP256K1_INLINE static int secp256k1_rangeproof_rewind_inner(secp256k1_scalar * } return 1; } - npub = (rings - 1) << 2; for (j = 0; j < 2; j++) { size_t idx; /* Look for a value encoding in the last ring. */ - idx = npub + rsizes[rings - 1] - 1 - j; + idx = 4 * (header->n_rings - 1) + header->rsizes[header->n_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)) { @@ -421,8 +556,8 @@ SECP256K1_INLINE static int secp256k1_rangeproof_rewind_inner(secp256k1_scalar * } return 0; } - skip1 = rsizes[rings - 1] - 1 - j; - skip2 = ((value >> ((rings - 1) << 1)) & 3); + skip1 = header->rsizes[header->n_rings - 1] - 1 - j; + skip2 = ((value >> ((header->n_rings - 1) << 1)) & 3); if (skip1 == skip2) { /*Value is in wrong position.*/ if (mlen) { @@ -430,12 +565,12 @@ SECP256K1_INLINE static int secp256k1_rangeproof_rewind_inner(secp256k1_scalar * } return 0; } - skip1 += (rings - 1) << 2; - skip2 += (rings - 1) << 2; + skip1 += (header->n_rings - 1) << 2; + skip2 += (header->n_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]); + secp256k1_scalar_negate(&sec[header->n_rings - 1], &sec[header->n_rings - 1]); + secp256k1_scalar_add(blind, &stmp, &sec[header->n_rings - 1]); if (!m || !mlen || *mlen == 0) { if (mlen) { *mlen = 0; @@ -445,10 +580,10 @@ SECP256K1_INLINE static int secp256k1_rangeproof_rewind_inner(secp256k1_scalar * } offset = 0; npub = 0; - for (i = 0; i < rings; i++) { + for (i = 0; i < header->n_rings; i++) { size_t idx; idx = (value >> (i << 1)) & 3; - for (j = 0; j < rsizes[i]; j++) { + for (j = 0; j < header->rsizes[i]; j++) { if (npub == skip1 || npub == skip2) { npub++; continue; @@ -483,105 +618,31 @@ SECP256K1_INLINE static int secp256k1_rangeproof_rewind_inner(secp256k1_scalar * return 1; } -SECP256K1_INLINE static int secp256k1_rangeproof_getheader_impl(size_t *offset, int *exp, int *mantissa, uint64_t *scale, - uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, size_t 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 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_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 unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_ge* genp) { 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 sha256_m; - size_t rsizes[32]; + secp256k1_rangeproof_header header; int ret; size_t i; - int exp; - int mantissa; + size_t pub_idx; size_t offset; - size_t rings; - int overflow; - size_t npub; - int offset_post_header; - uint64_t scale; + size_t offset_post_header; 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)) { + if (!secp256k1_rangeproof_header_parse(&header, &offset, proof, plen)) { return 0; } + *min_value = header.min_value; + *max_value = header.max_value; 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)) { + if (plen - offset < 32 * (header.n_pubs + header.n_rings - 1) + 32 + ((header.n_rings + 6) >> 3)) { return 0; } secp256k1_sha256_initialize(&sha256_m); @@ -590,23 +651,24 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm secp256k1_rangeproof_serialize_point(m, genp); secp256k1_sha256_write(&sha256_m, m, 33); secp256k1_sha256_write(&sha256_m, proof, offset); - for(i = 0; i < rings - 1; i++) { + for(i = 0; i < header.n_rings - 1; i++) { signs[i] = (proof[offset + ( i>> 3)] & (1 << (i & 7))) != 0; } - offset += (rings + 6) >> 3; - if ((rings - 1) & 7) { + offset += (header.n_rings + 6) >> 3; + if ((header.n_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) { + if ((proof[offset - 1] >> ((header.n_rings - 1) & 7)) != 0) { return 0; } } - npub = 0; + pub_idx = 0; secp256k1_gej_set_infinity(&accj); if (*min_value) { secp256k1_pedersen_ecmult_small(&accj, *min_value, genp); } - for(i = 0; i < rings - 1; i++) { + for(i = 0; i < header.n_rings - 1; i++) { secp256k1_fe fe; + secp256k1_ge c; if (!secp256k1_fe_set_b32(&fe, &proof[offset]) || !secp256k1_ge_set_xquad(&c, &fe)) { return 0; @@ -618,21 +680,21 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm * serialized form already. */ secp256k1_sha256_write(&sha256_m, &signs[i], 1); secp256k1_sha256_write(&sha256_m, &proof[offset], 32); - secp256k1_gej_set_ge(&pubs[npub], &c); + secp256k1_gej_set_ge(&pubs[pub_idx], &c); secp256k1_gej_add_ge_var(&accj, &accj, &c, NULL); offset += 32; - npub += rsizes[i]; + pub_idx += header.rsizes[i]; } secp256k1_gej_neg(&accj, &accj); - secp256k1_gej_add_ge_var(&pubs[npub], &accj, commit, NULL); - if (secp256k1_gej_is_infinity(&pubs[npub])) { + secp256k1_gej_add_ge_var(&pubs[pub_idx], &accj, commit, NULL); + if (secp256k1_gej_is_infinity(&pubs[pub_idx])) { return 0; } - secp256k1_rangeproof_pub_expand(pubs, exp, rsizes, rings, genp); - npub += rsizes[rings - 1]; + secp256k1_rangeproof_pub_expand(pubs, header.exp, header.rsizes, header.n_rings, genp); e0 = &proof[offset]; offset += 32; - for (i = 0; i < npub; i++) { + for (i = 0; i < header.n_pubs; i++) { + int overflow; secp256k1_scalar_set_b32(&s[i], &proof[offset], &overflow); if (overflow) { return 0; @@ -647,7 +709,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm secp256k1_sha256_write(&sha256_m, extra_commit, extra_commit_len); } secp256k1_sha256_finalize(&sha256_m, m); - ret = secp256k1_borromean_verify(nonce ? evalues : NULL, e0, s, pubs, rsizes, rings, m, 32); + ret = secp256k1_borromean_verify(nonce ? evalues : NULL, e0, s, pubs, header.rsizes, header.n_rings, m, 32); if (ret && nonce) { /* Given the nonce, try rewinding the witness to recover its initial state. */ secp256k1_scalar blind; @@ -655,12 +717,12 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm 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, genp)) { + if (!secp256k1_rangeproof_rewind_inner(&blind, &vv, message_out, outlen, evalues, s, &header, nonce, commit, proof, offset_post_header, genp)) { 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; + vv = (vv * header.scale) + header.min_value; secp256k1_pedersen_ecmult(ecmult_gen_ctx, &accj, &blind, vv, genp); if (secp256k1_gej_is_infinity(&accj)) { return 0; diff --git a/src/modules/rangeproof/tests_impl.h b/src/modules/rangeproof/tests_impl.h index c2482550c..f6a9f82c9 100644 --- a/src/modules/rangeproof/tests_impl.h +++ b/src/modules/rangeproof/tests_impl.h @@ -312,11 +312,23 @@ static void test_pedersen(void) { CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1)); } +/* Hack size_t closure that will just index into a given array */ +static size_t secp256k1_borromean_sz_closure_test_call(const secp256k1_borromean_sz_closure* self, size_t index) { + const size_t* secidx = (const size_t*) (size_t) self->input; + return secidx[index]; +} + +static secp256k1_borromean_sz_closure secp256k1_borromean_sz_closure_test(const size_t* secidx) { + secp256k1_borromean_sz_closure ret; + ret.input = (uint64_t) (size_t) secidx; + ret.call = secp256k1_borromean_sz_closure_test_call; + return ret; +} + static 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; @@ -327,6 +339,7 @@ static void test_borromean(void) { size_t i; size_t j; int c; + secp256k1_borromean_sz_closure secidx_closure = secp256k1_borromean_sz_closure_test(secidx); secp256k1_testrand256_test(m); nrings = 1 + (secp256k1_testrand32()&7); c = 0; @@ -338,13 +351,9 @@ static void test_borromean(void) { rsizes[i] = 1 + (secp256k1_testrand32()&7); secidx[i] = secp256k1_testrand32() % rsizes[i]; random_scalar_order(&sec[i]); - random_scalar_order(&k[i]); if(secp256k1_testrand32()&7) { sec[i] = one; } - if(secp256k1_testrand32()&7) { - k[i] = one; - } for (j = 0; j < rsizes[i]; j++) { random_scalar_order(&s[c + j]); if(secp256k1_testrand32()&7) { @@ -359,7 +368,7 @@ static void test_borromean(void) { } c += rsizes[i]; } - CHECK(secp256k1_borromean_sign(&ctx->ecmult_gen_ctx, e0, s, pubs, k, sec, rsizes, secidx, nrings, m, 32)); + CHECK(secp256k1_borromean_sign(&ctx->ecmult_gen_ctx, e0, s, pubs, sec, rsizes, &secidx_closure, nrings, m, 32)); CHECK(secp256k1_borromean_verify(NULL, e0, s, pubs, rsizes, nrings, m, 32)); i = secp256k1_testrand32() % c; secp256k1_scalar_negate(&s[i],&s[i]); @@ -541,8 +550,95 @@ static void test_rangeproof(void) { } } +static void test_single_value_proof(uint64_t val) { + unsigned char proof[5000]; + secp256k1_pedersen_commitment commit; + unsigned char blind[32]; + unsigned char blind_out[32]; + unsigned char nonce[32]; + const unsigned char message[1] = " "; /* no message will fit into a single-value proof */ + unsigned char message_out[sizeof(proof)] = { 0 }; + size_t plen = sizeof(proof); + uint64_t min_val_out = 0; + uint64_t max_val_out = 0; + uint64_t val_out = 0; + size_t m_len_out = 0; + + secp256k1_testrand256(blind); + secp256k1_testrand256(nonce); + CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, val, secp256k1_generator_h)); + + CHECK(secp256k1_rangeproof_sign( + ctx, + proof, &plen, + val, /* min_val */ + &commit, blind, nonce, + -1, /* exp: -1 is magic value to indicate a single-value proof */ + 0, /* min_bits */ + val, /* val */ + message, sizeof(message), /* Will cause this to fail */ + NULL, 0, + secp256k1_generator_h + ) == 0); + + plen = sizeof(proof); + CHECK(secp256k1_rangeproof_sign( + ctx, + proof, &plen, + val, /* min_val */ + &commit, blind, nonce, + -1, /* exp: -1 is magic value to indicate a single-value proof */ + 0, /* min_bits */ + val, /* val */ + NULL, 0, + NULL, 0, + secp256k1_generator_h + ) == 1); + + /* Different proof sizes are unfortunate but is caused by `min_value` of + * zero being special-cased and encoded more efficiently. */ + if (val == 0) { + CHECK(plen == 65); + } else { + CHECK(plen == 73); + } + + CHECK(secp256k1_rangeproof_verify( + ctx, + &min_val_out, &max_val_out, + &commit, + proof, plen, + NULL, 0, + secp256k1_generator_h + ) == 1); + CHECK(min_val_out == val); + CHECK(max_val_out == val); + + memset(message_out, 0, sizeof(message_out)); + m_len_out = sizeof(message_out); + CHECK(secp256k1_rangeproof_rewind( + ctx, + blind_out, &val_out, + message_out, &m_len_out, + nonce, + &min_val_out, &max_val_out, + &commit, + proof, plen, + NULL, 0, + secp256k1_generator_h + )); + CHECK(val_out == val); + CHECK(min_val_out == val); + CHECK(max_val_out == val); + CHECK(m_len_out == 0); + CHECK(memcmp(blind, blind_out, 32) == 0); + for (m_len_out = 0; m_len_out < sizeof(message_out); m_len_out++) { + CHECK(message_out[m_len_out] == 0); + } +} + #define MAX_N_GENS 30 -void test_multiple_generators(void) { +static void test_multiple_generators(void) { const size_t n_inputs = (secp256k1_testrand32() % (MAX_N_GENS / 2)) + 1; const size_t n_outputs = (secp256k1_testrand32() % (MAX_N_GENS / 2)) + 1; const size_t n_generators = n_inputs + n_outputs; @@ -604,7 +700,18 @@ void test_multiple_generators(void) { } void test_rangeproof_fixed_vectors(void) { - const unsigned char vector_1[] = { + size_t i; + unsigned char blind[32]; + uint64_t value; + uint64_t min_value; + uint64_t max_value; + secp256k1_pedersen_commitment pc; + unsigned char message[4000] = {0}; + size_t m_len = sizeof(message); + + /* Vector 1: no message */ +{ + static const unsigned char vector_1[] = { 0x62, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x02, 0x2a, 0x5c, 0x42, 0x0e, 0x1d, 0x51, 0xe1, 0xb7, 0xf3, 0x69, 0x04, 0xb5, 0xbb, 0x9b, 0x41, 0x66, 0x14, 0xf3, 0x64, 0x42, 0x26, 0xe3, 0xa7, 0x6a, 0x06, 0xbb, 0xa8, 0x5a, 0x49, 0x6f, 0x19, 0x76, 0xfb, 0xe5, 0x75, 0x77, 0x88, @@ -647,25 +754,175 @@ void test_rangeproof_fixed_vectors(void) { 0xa6, 0x45, 0xf6, 0xce, 0xcf, 0x48, 0xf6, 0x1e, 0x3d, 0xd2, 0xcf, 0xcb, 0x3a, 0xcd, 0xbb, 0x92, 0x29, 0x24, 0x16, 0x7f, 0x8a, 0xa8, 0x5c, 0x0c, 0x45, 0x71, 0x33 }; - const unsigned char commit_1[] = { + static const unsigned char commit_1[] = { 0x08, 0xf5, 0x1e, 0x0d, 0xc5, 0x86, 0x78, 0x51, 0xa9, 0x00, 0x00, 0xef, 0x4d, 0xe2, 0x94, 0x60, 0x89, 0x83, 0x04, 0xb4, 0x0e, 0x90, 0x10, 0x05, 0x1c, 0x7f, 0xd7, 0x33, 0x92, 0x1f, 0xe7, 0x74, 0x59 }; - uint64_t min_value_1; - uint64_t max_value_1; - secp256k1_pedersen_commitment pc; + static const unsigned char blind_1[] = { + 0x98, 0x44, 0xfc, 0x7a, 0x64, 0xa9, 0xca, 0xdf, 0xf3, 0x2f, 0x9f, 0x02, 0xba, 0x46, 0xc7, 0xd9, + 0x77, 0x47, 0xa4, 0xd3, 0x53, 0x17, 0xc6, 0x44, 0x30, 0x73, 0x84, 0xeb, 0x1f, 0xbe, 0xa1, 0xfb + }; CHECK(secp256k1_pedersen_commitment_parse(ctx, &pc, commit_1)); - CHECK(secp256k1_rangeproof_verify( ctx, - &min_value_1, &max_value_1, + &min_value, &max_value, &pc, vector_1, sizeof(vector_1), NULL, 0, secp256k1_generator_h )); + CHECK(min_value == 86); + CHECK(max_value == 25586); + + CHECK(secp256k1_rangeproof_rewind( + ctx, + blind, &value, + message, &m_len, + pc.data, + &min_value, &max_value, + &pc, + vector_1, sizeof(vector_1), + NULL, 0, + secp256k1_generator_h + )); + + CHECK(memcmp(blind, blind_1, 32) == 0); + CHECK(value == 86); + CHECK(min_value == 86); + CHECK(max_value == 25586); + CHECK(m_len == 448); /* length of the sidechannel in the proof */ + for (i = 0; i < m_len; i++) { + /* No message encoded in this vector */ + CHECK(message[i] == 0); + } +} + + /* Vector 2: embedded message */ +{ + static const unsigned char vector_2[] = { + 0x40, 0x03, 0x00, 0x90, 0x1a, 0x61, 0x64, 0xbb, 0x85, 0x1a, 0x78, 0x35, 0x1e, 0xe0, 0xd5, 0x96, + 0x71, 0x0f, 0x18, 0x8e, 0xf3, 0x33, 0xf0, 0x75, 0xfe, 0xd6, 0xc6, 0x11, 0x6b, 0x42, 0x89, 0xea, + 0xa2, 0x0c, 0x89, 0x25, 0x37, 0x81, 0x10, 0xf9, 0xf0, 0x9b, 0xda, 0x68, 0x2a, 0xd9, 0x2e, 0x0c, + 0x45, 0x17, 0x54, 0x6d, 0x02, 0xd2, 0x21, 0x5d, 0xbc, 0x10, 0xf8, 0x8f, 0xf1, 0x92, 0x40, 0xa9, + 0xc7, 0x24, 0x00, 0x1b, 0xc8, 0x75, 0x0f, 0xf6, 0x8f, 0x93, 0x8b, 0x78, 0x62, 0x73, 0x3c, 0x86, + 0x4b, 0x61, 0x7c, 0x0f, 0xc6, 0x41, 0xc9, 0xb3, 0xc1, 0x30, 0x7f, 0xd4, 0xee, 0x9f, 0x37, 0x08, + 0x9b, 0x64, 0x23, 0xd5, 0xe6, 0x1a, 0x03, 0x54, 0x74, 0x9b, 0x0b, 0xae, 0x6f, 0x2b, 0x1e, 0xf5, + 0x40, 0x44, 0xaa, 0x12, 0xe8, 0xbd, 0xe0, 0xa6, 0x85, 0x89, 0xf1, 0xa9, 0xd0, 0x3f, 0x2e, 0xc6, + 0x1f, 0x11, 0xf5, 0x44, 0x69, 0x99, 0x31, 0x10, 0x2e, 0x64, 0xc6, 0x44, 0xdb, 0x47, 0x06, 0x6d, + 0xd5, 0xf2, 0x8d, 0x19, 0x00, 0x39, 0xb8, 0xca, 0xda, 0x5c, 0x1d, 0x83, 0xbd, 0xa3, 0x6d, 0xbf, + 0x97, 0xdd, 0x83, 0x86, 0xc9, 0x56, 0xe2, 0xbb, 0x37, 0x4b, 0x2d, 0xb5, 0x9d, 0xf2, 0x7a, 0x6a, + 0x25, 0x47, 0xfa, 0x03, 0x05, 0xc5, 0xda, 0x73, 0xe1, 0x96, 0x15, 0x21, 0x23, 0xe5, 0xef, 0x55, + 0x36, 0xdd, 0xf1, 0xb1, 0x3f, 0x33, 0x1a, 0x91, 0x6c, 0x73, 0x64, 0xd3, 0x88, 0xe7, 0xc6, 0xc9, + 0x04, 0x29, 0xae, 0x55, 0x27, 0xa0, 0x80, 0x60, 0xaf, 0x0c, 0x09, 0x2f, 0xc8, 0x1b, 0xe6, 0x16, + 0x9e, 0xed, 0x29, 0xc7, 0x93, 0xce, 0xc7, 0x0d, 0xdf, 0x1f, 0x28, 0xba, 0xf3, 0x38, 0xc3, 0xaa, + 0x99, 0xd9, 0x21, 0x41, 0xb8, 0x10, 0xa5, 0x48, 0x37, 0xec, 0x60, 0xda, 0x64, 0x5a, 0x73, 0x55, + 0xd7, 0xff, 0x23, 0xfa, 0xf6, 0xc6, 0xf4, 0xe2, 0xca, 0x99, 0x2f, 0x30, 0x36, 0x48, 0x73, 0x8b, + 0x57, 0xa6, 0x62, 0x12, 0xa3, 0xe7, 0x5c, 0xa8, 0xd1, 0xe6, 0x85, 0x05, 0x59, 0xfe, 0x2b, 0x44, + 0xe4, 0x73, 0x1c, 0xc3, 0x56, 0x32, 0x07, 0x65, 0x4a, 0x58, 0xaf, 0x2b, 0x3f, 0x36, 0xca, 0xb4, + 0x1d, 0x5c, 0x2a, 0x46, 0x1f, 0xf7, 0x63, 0x59, 0x4f, 0x2b, 0xd0, 0xf6, 0xfc, 0xcf, 0x04, 0x09, + 0xb7, 0x65, 0x1b + }; + static const unsigned char commit_2[] = { + 0x09, + 0x25, 0xa4, 0xbd, 0xc4, 0x57, 0x69, 0xeb, 0x4f, 0x34, 0x0f, 0xea, 0xb8, 0xe4, 0x72, 0x04, 0x54, + 0x06, 0xe5, 0xd6, 0x85, 0x15, 0x42, 0xea, 0x6e, 0x1d, 0x11, 0x11, 0x9c, 0x56, 0xf8, 0x10, 0x45 + }; + static const unsigned char blind_2[] = { + 0xdc, 0x79, 0x07, 0x89, 0x2d, 0xc4, 0xe3, 0x76, 0xf9, 0x13, 0x38, 0xd6, 0x4b, 0x46, 0xed, 0x9d, + 0x9b, 0xf6, 0x70, 0x3d, 0x04, 0xcf, 0x96, 0x8c, 0xfd, 0xb5, 0xff, 0x0a, 0x06, 0xc7, 0x08, 0x8b + }; + static const unsigned char message_2[] = "When I see my own likeness in the depths of someone else's consciousness, I always experience a moment of panic."; + + CHECK(secp256k1_pedersen_commitment_parse(ctx, &pc, commit_2)); + CHECK(secp256k1_rangeproof_verify( + ctx, + &min_value, &max_value, + &pc, + vector_2, sizeof(vector_2), + NULL, 0, + secp256k1_generator_h + )); + CHECK(min_value == 0); + CHECK(max_value == 15); + + CHECK(secp256k1_rangeproof_rewind( + ctx, + blind, &value, + message, &m_len, + pc.data, + &min_value, &max_value, + &pc, + vector_2, sizeof(vector_2), + NULL, 0, + secp256k1_generator_h + )); + + CHECK(memcmp(blind, blind_2, 32) == 0); + CHECK(value == 11); + CHECK(min_value == 0); + CHECK(max_value == 15); + CHECK(m_len == 192); /* length of the sidechannel in the proof */ + CHECK(memcmp(message, message_2, sizeof(message_2)) == 0); + for (i = sizeof(message_2); i < m_len; i++) { + /* No message encoded in this vector */ + CHECK(message[i] == 0); + } +} + + /* Vector 3: single-value proof of UINT64_MAX */ +{ + static const unsigned char vector_3[] = { + 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdc, 0x7d, 0x0b, 0x79, 0x0e, 0xaf, 0x41, + 0xa5, 0x8e, 0x9b, 0x0c, 0x5b, 0xa3, 0xee, 0x7d, 0xfd, 0x3d, 0x6b, 0xf3, 0xac, 0x04, 0x8a, 0x43, + 0x75, 0xb0, 0xb7, 0x0e, 0x92, 0xd7, 0xdf, 0xf0, 0x76, 0xc4, 0xa5, 0xb6, 0x2f, 0xf1, 0xb5, 0xfb, + 0xb4, 0xb6, 0x29, 0xea, 0x34, 0x9b, 0x16, 0x30, 0x0d, 0x06, 0xf1, 0xb4, 0x3f, 0x0d, 0x73, 0x59, + 0x75, 0xbf, 0x5d, 0x19, 0x59, 0xef, 0x11, 0xf0, 0xbf + }; + static const unsigned char commit_3[] = { + 0x08, + 0xc7, 0xea, 0x40, 0x7d, 0x26, 0x38, 0xa2, 0x99, 0xb9, 0x40, 0x22, 0x78, 0x17, 0x57, 0x65, 0xb3, + 0x36, 0x82, 0x18, 0x42, 0xc5, 0x57, 0x04, 0x5e, 0x58, 0x5e, 0xf6, 0x40, 0x8b, 0x24, 0x73, 0x10 + }; + static const unsigned char nonce_3[] = { + 0x84, 0x50, 0x94, 0x69, 0xa3, 0x4b, 0x6c, 0x62, 0x1a, 0xc7, 0xe2, 0x0e, 0x07, 0x9a, 0x6f, 0x85, + 0x5f, 0x26, 0x50, 0xcd, 0x88, 0x5a, 0x9f, 0xaa, 0x23, 0x5e, 0x0a, 0xe0, 0x7e, 0xc5, 0xe9, 0xf1 + }; + static const unsigned char blind_3[] = { + 0x68, 0x89, 0x47, 0x8c, 0x77, 0xec, 0xcc, 0x2b, 0x65, 0x01, 0x78, 0x6b, 0x06, 0x8b, 0x38, 0x94, + 0xc0, 0x6b, 0x9b, 0x4c, 0x02, 0xa6, 0xc8, 0xf6, 0xc0, 0x34, 0xea, 0x35, 0x57, 0xf4, 0xe1, 0x37 + }; + + CHECK(secp256k1_pedersen_commitment_parse(ctx, &pc, commit_3)); + CHECK(secp256k1_rangeproof_verify( + ctx, + &min_value, &max_value, + &pc, + vector_3, sizeof(vector_3), + NULL, 0, + secp256k1_generator_h + )); + CHECK(min_value == UINT64_MAX); + CHECK(max_value == UINT64_MAX); + + CHECK(secp256k1_rangeproof_rewind( + ctx, + blind, &value, + message, &m_len, + nonce_3, + &min_value, &max_value, + &pc, + vector_3, sizeof(vector_3), + NULL, 0, + secp256k1_generator_h + )); + CHECK(memcmp(blind, blind_3, 32) == 0); + CHECK(value == UINT64_MAX); + CHECK(min_value == UINT64_MAX); + CHECK(max_value == UINT64_MAX); + CHECK(m_len == 0); +} } void test_pedersen_commitment_fixed_vector(void) { @@ -690,6 +947,11 @@ void test_pedersen_commitment_fixed_vector(void) { void run_rangeproof_tests(void) { int i; test_api(); + + test_single_value_proof(0); + test_single_value_proof(12345678); + test_single_value_proof(UINT64_MAX); + test_rangeproof_fixed_vectors(); test_pedersen_commitment_fixed_vector(); for (i = 0; i < count / 2 + 1; i++) { diff --git a/src/modules/surjection/main_impl.h b/src/modules/surjection/main_impl.h index b8f145e5f..0521ecd07 100644 --- a/src/modules/surjection/main_impl.h +++ b/src/modules/surjection/main_impl.h @@ -275,10 +275,8 @@ int secp256k1_surjectionproof_initialize(const secp256k1_context* ctx, secp256k1 int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_surjectionproof* proof, const secp256k1_generator* ephemeral_input_tags, size_t n_ephemeral_input_tags, const secp256k1_generator* ephemeral_output_tag, size_t input_index, const unsigned char *input_blinding_key, const unsigned char *output_blinding_key) { secp256k1_scalar blinding_key; secp256k1_scalar tmps; - secp256k1_scalar nonce; int overflow = 0; size_t rsizes[1]; /* array needed for borromean sig API */ - size_t indices[1]; /* array needed for borromean sig API */ size_t i; size_t n_total_pubkeys; size_t n_used_pubkeys; @@ -286,6 +284,7 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s secp256k1_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS]; secp256k1_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS]; unsigned char msg32[32]; + secp256k1_borromean_sz_closure secidx_closure; VERIFY_CHECK(ctx != NULL); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); @@ -328,17 +327,12 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s /* Produce signature */ rsizes[0] = (int) n_used_pubkeys; - indices[0] = (int) ring_input_index; 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) { return 0; } - /* Borromean sign will overwrite one of the s values we just generated, so use - * it as a nonce instead. This avoids extra random generation and also is an - * homage to the rangeproof code which does this very cleverly to encode messages. */ - nonce = borromean_s[ring_input_index]; - secp256k1_scalar_clear(&borromean_s[ring_input_index]); - if (secp256k1_borromean_sign(&ctx->ecmult_gen_ctx, &proof->data[0], borromean_s, ring_pubkeys, &nonce, &blinding_key, rsizes, indices, 1, msg32, 32) == 0) { + secidx_closure = secp256k1_borromean_sz_closure_const(ring_input_index); + if (secp256k1_borromean_sign(&ctx->ecmult_gen_ctx, &proof->data[0], borromean_s, ring_pubkeys, &blinding_key, rsizes, &secidx_closure, 1, msg32, 32) == 0) { return 0; } for (i = 0; i < n_used_pubkeys; i++) { diff --git a/src/modules/whitelist/main_impl.h b/src/modules/whitelist/main_impl.h index 5ce780d45..00c841c1b 100644 --- a/src/modules/whitelist/main_impl.h +++ b/src/modules/whitelist/main_impl.h @@ -15,7 +15,7 @@ int secp256k1_whitelist_sign(const secp256k1_context* ctx, secp256k1_whitelist_signature *sig, const secp256k1_pubkey *online_pubkeys, const secp256k1_pubkey *offline_pubkeys, const size_t n_keys, const secp256k1_pubkey *sub_pubkey, const unsigned char *online_seckey, const unsigned char *summed_seckey, const size_t index, secp256k1_nonce_function noncefp, const void *noncedata) { secp256k1_gej pubs[MAX_KEYS]; secp256k1_scalar s[MAX_KEYS]; - secp256k1_scalar sec, non; + secp256k1_scalar sec; unsigned char msg32[32]; int ret; @@ -51,19 +51,7 @@ int secp256k1_whitelist_sign(const secp256k1_context* ctx, secp256k1_whitelist_s secp256k1_scalar_get_b32(seckey32, &sec); while (1) { size_t i; - unsigned char nonce32[32]; - int done; - ret = noncefp(nonce32, msg32, seckey32, NULL, (void*)noncedata, count); - if (!ret) { - break; - } - secp256k1_scalar_set_b32(&non, nonce32, &overflow); - memset(nonce32, 0, 32); - if (overflow || secp256k1_scalar_is_zero(&non)) { - count++; - continue; - } - done = 1; + int done = 1; for (i = 0; i < n_keys; i++) { msg32[0] ^= i + 1; msg32[1] ^= (i + 1) / 0x100; @@ -88,13 +76,13 @@ int secp256k1_whitelist_sign(const secp256k1_context* ctx, secp256k1_whitelist_s } /* Actually sign */ if (ret) { + secp256k1_borromean_sz_closure secidx_closure = secp256k1_borromean_sz_closure_const(index); sig->n_keys = n_keys; - ret = secp256k1_borromean_sign(&ctx->ecmult_gen_ctx, &sig->data[0], s, pubs, &non, &sec, &n_keys, &index, 1, msg32, 32); + ret = secp256k1_borromean_sign(&ctx->ecmult_gen_ctx, &sig->data[0], s, pubs, &sec, &n_keys, &secidx_closure, 1, msg32, 32); /* Signing will change s[index], so update in the sig structure */ secp256k1_scalar_get_b32(&sig->data[32 * (index + 1)], &s[index]); } - secp256k1_scalar_clear(&non); secp256k1_scalar_clear(&sec); return ret; }