diff --git a/.gitignore b/.gitignore index 107f08ae2..5f9f3f374 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ bench bench_ecmult bench_generator bench_rangeproof +bench_whitelist bench_internal tests exhaustive_tests @@ -60,4 +61,4 @@ src/stamp-h1 libsecp256k1.pc contrib/gh-pr-create.sh -example_musig \ No newline at end of file +example_musig diff --git a/include/secp256k1_rangeproof.h b/include/secp256k1_rangeproof.h index d4f35de7a..8e966a7cc 100644 --- a/include/secp256k1_rangeproof.h +++ b/include/secp256k1_rangeproof.h @@ -10,6 +10,15 @@ extern "C" { #include +/** Length of a message that can be embedded into a maximally-sized rangeproof + * + * It is not be possible to fit a message of this size into a non-maximally-sized + * rangeproof, but it is guaranteed that any embeddable message can fit into an + * array of this size. This constant is intended to be used for memory allocations + * and sanity checks. + */ +#define SECP256K1_RANGEPROOF_MAX_MESSAGE_LEN 3968 + /** Opaque data structure that stores a Pedersen commitment * * The exact representation of data inside is implementation defined and not diff --git a/src/modules/rangeproof/borromean.h b/src/modules/rangeproof/borromean.h index efd4da162..f988caf45 100644 --- a/src/modules/rangeproof/borromean.h +++ b/src/modules/rangeproof/borromean.h @@ -18,7 +18,7 @@ int secp256k1_borromean_verify(secp256k1_scalar *evalues, const unsigned char *e 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, + unsigned char *e0, secp256k1_scalar *s, const secp256k1_gej *pubs, const secp256k1_scalar *sec, const size_t *rsizes, const size_t *secidx, 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..7d2efb208 100644 --- a/src/modules/rangeproof/borromean_impl.h +++ b/src/modules/rangeproof/borromean_impl.h @@ -109,7 +109,7 @@ 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, + unsigned char *e0, secp256k1_scalar *s, const secp256k1_gej *pubs, const secp256k1_scalar *sec, const size_t *rsizes, const size_t *secidx, size_t nrings, const unsigned char *m, size_t mlen) { secp256k1_gej rgej; secp256k1_ge rge; @@ -125,7 +125,6 @@ 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); @@ -135,7 +134,8 @@ int secp256k1_borromean_sign(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, count = 0; for (i = 0; i < nrings; 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; @@ -165,6 +165,10 @@ 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++) { + /* 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); @@ -186,7 +190,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/main_impl.h b/src/modules/rangeproof/main_impl.h index 9129e4c30..96d3043ca 100644 --- a/src/modules/rangeproof/main_impl.h +++ b/src/modules/rangeproof/main_impl.h @@ -231,17 +231,22 @@ 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..ea0fe3496 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 - 1]. 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. Will be 0 for an exact proof. + * + * 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 - 1). + * + * 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..14ec7eaa5 100644 --- a/src/modules/rangeproof/rangeproof_impl.h +++ b/src/modules/rangeproof/rangeproof_impl.h @@ -17,6 +17,210 @@ #include "modules/rangeproof/pedersen.h" #include "modules/rangeproof/borromean.h" +#include "modules/rangeproof/rangeproof.h" + +/** 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->exp == -1) { + 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 > 0); + VERIFY_CHECK(header->n_rings <= 32); + VERIFY_CHECK(header->n_pubs <= 128); + VERIFY_CHECK(header->n_pubs >= 1); + + 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, + 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 (header->mantissa > 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; + } + /* Reduce mantissa to keep within a uint64_t's range (essentially copied from 2015 code) */ + { + const unsigned int max_bits = min_value ? secp256k1_clz64_var(min_value) : 64; + if (header->mantissa > max_bits) { + header->mantissa = max_bits; + } + } + { + /* If the user has asked for more bits of proof then there is room for in the exponent, reduce the exponent. */ + uint64_t max = header->mantissa ? (UINT64_MAX >> (64 - header->mantissa)) : 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); + + /* Did we get all the bits? */ + VERIFY_CHECK(header->mantissa > 0); + VERIFY_CHECK((*proven_value & ~(UINT64_MAX >> (64 - header->mantissa))) == 0); + + /* We may have changed `mantissa`, `exp` and `min_value`, all of which would + * affect the derived values, so re-expand the header. */ + 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,32 +263,53 @@ 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; - secp256k1_scalar acc; - int overflow; - int ret; - size_t i; - 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); + secp256k1_rfc6979_hmac_sha256_initialize(rng, rngseed, 32 + 33 + 33 + len); +} + +SECP256K1_INLINE static int secp256k1_rangeproof_genrand_sign( + secp256k1_scalar *sec, + secp256k1_scalar *s, + const unsigned char* blind, + const unsigned char* message, + const size_t msg_len, + const secp256k1_rangeproof_header* header, + const uint64_t proven_value, + secp256k1_rfc6979_hmac_sha256* rng +) { + unsigned char tmp[32]; + secp256k1_scalar acc; + int overflow; + int ret; + size_t i; + size_t npub; + secp256k1_scalar_set_b32(&acc, blind, &overflow); + if (overflow) { + return 0; + } + secp256k1_scalar_negate(&acc, &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++) { + size_t j; + 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,12 +317,31 @@ 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); - if (message) { + for (j = 0; j < header->rsizes[i]; j++) { + secp256k1_rfc6979_hmac_sha256_generate(rng, tmp, 32); + if (message && i < header->n_rings - 1) { + /* encode the message side-channel */ + int b; for (b = 0; b < 32; b++) { - tmp[b] ^= message[(i * 4 + j) * 32 + b]; - message[(i * 4 + j) * 32 + b] = tmp[b]; + if ((i * 4 + j) * 32 + b < msg_len) { + tmp[b] ^= message[(i * 4 + j) * 32 + b]; + } + } + } else if (i == header->n_rings - 1) { + /* encode the value in the final ring thrice, both to inform the rewinder + * which indices are real and to signal to the rewinder that its nonce is + * correct and it is decoding something non-random */ + size_t jidx = header->rsizes[i] - 1; + jidx -= (proven_value >> (2 * i)) == jidx; + if (j == jidx) { + size_t k; + tmp[0] ^= 128; + for (k = 0; k < 8; k++) { + unsigned char xor = (proven_value >> (56 - k * 8)) & 255; + tmp[8 + k] ^= xor; + tmp[16 + k] ^= xor; + tmp[24 + k] ^= xor; + } } } secp256k1_scalar_set_b32(&s[npub], tmp, &overflow); @@ -105,87 +349,58 @@ 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) { +SECP256K1_INLINE static int secp256k1_rangeproof_genrand_rewind( + 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; 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; + size_t j; + int b; + size_t npub; + secp256k1_scalar_clear(&acc); + npub = 0; + ret = 1; + 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_scalar_set_b32(&sec[i], tmp, &overflow); + } while (overflow || secp256k1_scalar_is_zero(&sec[i])); + secp256k1_scalar_add(&acc, &acc, &sec[i]); + } else { + secp256k1_scalar_negate(&acc, &acc); + sec[i] = acc; } - 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; + for (j = 0; j < header->rsizes[i]; j++) { + secp256k1_rfc6979_hmac_sha256_generate(rng, tmp, 32); + if (message) { + for (b = 0; b < 32; b++) { + message[(i * 4 + j) * 32 + b] = tmp[b]; + } + } + secp256k1_scalar_set_b32(&s[npub], tmp, &overflow); + ret &= !(overflow || secp256k1_scalar_is_zero(&s[npub])); + npub++; } - /* 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; + } + secp256k1_rfc6979_hmac_sha256_finalize(rng); + secp256k1_scalar_clear(&acc); + memset(tmp, 0, 32); + return ret; } /* 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. */ @@ -193,54 +408,48 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul 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; size_t len; /* Number of bytes used so far. */ size_t i; - int overflow; - size_t npub; + size_t pub_idx; 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; + if (header.exp >= 0) { + for (i = 0; i < header.n_rings; i++) { + secidx[i] = (v >> (i * 2)) & 3; } - len += 8; + } else { + secidx[0] = 0; } + + VERIFY_CHECK(v * header.scale + header.min_value == value); + + 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); @@ -250,63 +459,30 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul secp256k1_sha256_write(&sha256_m, tmp, 33); secp256k1_sha256_write(&sha256_m, proof, len); - memset(prep, 0, 4096); - if (message != NULL) { - memcpy(prep, message, msg_len); - } - /* Note, the data corresponding to the blinding factors must be zero. */ - if (rsizes[rings - 1] > 1) { - size_t idx; - /* Value encoding sidechannel. */ - idx = rsizes[rings - 1] - 1; - idx -= secidx[rings - 1] == idx; - idx = ((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)) { - 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 - * all the digits in the proof from the commitment. This lets the prover skip sending the - * 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_rangeproof_init_rng(&genrand_rng, nonce, commit, proof, len, genp); + if (!secp256k1_rangeproof_genrand_sign(sec, s, blind, message, msg_len, &header, v, &genrand_rng)) { 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++) { /*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], ((uint64_t)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,24 +490,24 @@ 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); + VERIFY_CHECK(pub_idx == header.n_pubs); + 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, 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); *plen = len; - memset(prep, 0, 4096); return 1; } @@ -362,29 +538,29 @@ 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; unsigned char prep[4096]; unsigned char tmp[32]; uint64_t value = 0; + size_t final_x_pos; size_t offset; size_t i; size_t j; int b; - 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_rewind(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 +571,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 = header->n_pubs - 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,21 +596,11 @@ SECP256K1_INLINE static int secp256k1_rangeproof_rewind_inner(secp256k1_scalar * } return 0; } - skip1 = rsizes[rings - 1] - 1 - j; - skip2 = ((value >> ((rings - 1) << 1)) & 3); - if (skip1 == skip2) { - /*Value is in wrong position.*/ - if (mlen) { - *mlen = 0; - } - return 0; - } - skip1 += (rings - 1) << 2; - skip2 += (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]); + final_x_pos = 4 * (header->n_rings - 1) + ((*v >> (2 * (header->n_rings - 1))) & 3); + secp256k1_rangeproof_recover_x(&stmp, &s_orig[final_x_pos], &ev[final_x_pos], &s[final_x_pos]); + 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,14 +610,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 - 1; i++) { size_t idx; idx = (value >> (i << 1)) & 3; - for (j = 0; j < rsizes[i]; j++) { - if (npub == skip1 || npub == skip2) { - npub++; - continue; - } + for (j = 0; j < header->rsizes[i]; j++) { if (idx == j) { /** For the non-forged signatures the signature is calculated instead of random, instead we recover the prover's nonces. * this could just as well recover the blinding factors and messages could be put there as is done for recovering the @@ -483,105 +644,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 +677,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 +706,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 +735,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 +743,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 41c4d616f..7d8470d48 100644 --- a/src/modules/rangeproof/tests_impl.h +++ b/src/modules/rangeproof/tests_impl.h @@ -196,7 +196,7 @@ static void test_rangeproof_api(const secp256k1_context *none, const secp256k1_c CHECK(max_value >= val); CHECK(value_out == val); CHECK(message_len == sizeof(message_out)); - CHECK(memcmp(message, message_out, sizeof(message_out)) == 0); + CHECK(secp256k1_memcmp_var(message, message_out, sizeof(message_out)) == 0); CHECK(secp256k1_rangeproof_rewind(both, NULL, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0); CHECK(*ecount == 21); /* blindout may be NULL */ @@ -322,7 +322,6 @@ 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; @@ -344,13 +343,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) { @@ -365,7 +360,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, 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]); @@ -434,13 +429,13 @@ static void test_rangeproof(void) { mlen = 4096; 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); + CHECK(secp256k1_memcmp_var(message, input_message, input_message_len) == 0); } for (j = input_message_len; j < mlen; j++) { CHECK(message[j] == 0); } CHECK(mlen <= 4096); - CHECK(memcmp(blindout, blind, 32) == 0); + CHECK(secp256k1_memcmp_var(blindout, blind, 32) == 0); CHECK(vout == v); CHECK(minv <= v); CHECK(maxv >= v); @@ -448,7 +443,7 @@ static void test_rangeproof(void) { 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, NULL, 0, secp256k1_generator_h)); - CHECK(memcmp(blindout, blind, 32) == 0); + CHECK(secp256k1_memcmp_var(blindout, blind, 32) == 0); CHECK(vout == v); CHECK(minv == v); CHECK(maxv == v); @@ -460,7 +455,7 @@ static void test_rangeproof(void) { 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(secp256k1_memcmp_var(blindout, blind, 32) == 0); CHECK(vout == v); CHECK(minv == v); CHECK(maxv == v); @@ -527,7 +522,7 @@ static void test_rangeproof(void) { CHECK(message[j] == 0); } CHECK(mlen <= 4096); - CHECK(memcmp(blindout, blind, 32) == 0); + CHECK(secp256k1_memcmp_var(blindout, blind, 32) == 0); CHECK(minv <= v); CHECK(maxv >= v); @@ -545,10 +540,115 @@ static void test_rangeproof(void) { len = secp256k1_testrandi64(0, 3072); CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit2, proof, len, NULL, 0, secp256k1_generator_h)); } + { + /* Some large values for value and minimum value make signing fail */ + v = (uint64_t)INT64_MAX+1; + vmin = 1; + CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h)); + CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, 0, 0, v, NULL, 0, NULL, 0, secp256k1_generator_h) == 0); + + vmin = INT64_MAX; + v = vmin; + CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h)); + CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, 0, 0, v, NULL, 0, NULL, 0, secp256k1_generator_h) == 1); + CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h)); + CHECK(minv == vmin); + CHECK(maxv >= v); + CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h)); + CHECK(secp256k1_memcmp_var(blindout, blind, 32) == 0); + CHECK(vout == v); + } +} + +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(secp256k1_memcmp_var(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; @@ -610,7 +710,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, @@ -653,25 +764,699 @@ 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(secp256k1_memcmp_var(blind, blind_1, 32) == 0); + CHECK(value == 86); + CHECK(min_value == 86); + CHECK(max_value == 25586); + CHECK(m_len == 384); /* 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(secp256k1_memcmp_var(blind, blind_2, 32) == 0); + CHECK(value == 11); + CHECK(min_value == 0); + CHECK(max_value == 15); + CHECK(m_len == 128); /* length of the sidechannel in the proof */ + CHECK(secp256k1_memcmp_var(message, message_2, sizeof(message_2)) == 0); + for (i = sizeof(message_2); i < m_len; i++) { + 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(secp256k1_memcmp_var(blind, blind_3, 32) == 0); + CHECK(value == UINT64_MAX); + CHECK(min_value == UINT64_MAX); + CHECK(max_value == UINT64_MAX); + CHECK(m_len == 0); +} +} + +static void print_vector_helper(unsigned char *buf, size_t buf_len) { + size_t j; + printf(" "); + for (j = 0; j < buf_len; j++) { + printf("0x%02x", buf[j]); + if (j == buf_len-1) { + printf(",\n"); + } else if ((j+1) % 16 != 0) { + printf(", "); + } else { + printf(",\n"); + printf(" "); + } + } + printf("};\n"); +} + +static void print_vector(int i, unsigned char *proof, size_t p_len, secp256k1_pedersen_commitment *commit) { + unsigned char commit_output[33]; + + printf("unsigned char vector_%d[] = {\n", i); + print_vector_helper(proof, p_len); + + CHECK(secp256k1_pedersen_commitment_serialize(ctx, commit_output, commit)); + printf("unsigned char commit_%d[] = {\n", i); + print_vector_helper(commit_output, sizeof(commit_output)); +} + + +/* Use same nonce and blinding value for all "reproducible" test vectors */ +static unsigned char vector_blind[] = { + 0x48, 0x26, 0xad, 0x41, 0x37, 0x4c, 0x25, 0x62, 0x52, 0x14, 0x78, 0x82, 0x89, 0x9c, 0x86, 0x27, + 0xa1, 0x19, 0xf6, 0xe1, 0xfa, 0x44, 0xe4, 0x29, 0x08, 0xa7, 0xb3, 0x45, 0xad, 0x35, 0xb2, 0xd9, +}; +static unsigned char vector_nonce[] = { + 0xc8, 0x5c, 0x7e, 0x6c, 0xa1, 0xfa, 0x11, 0x35, 0xc7, 0x45, 0x24, 0x8a, 0xb5, 0x28, 0x6d, 0x1a, + 0x88, 0x00, 0xff, 0xca, 0x96, 0x0f, 0xc7, 0x77, 0xa5, 0x96, 0x7a, 0x5e, 0xf8, 0x88, 0x2d, 0xd4, +}; + +/* Maximum length of a message that can be embedded into a rangeproof */ +void test_rangeproof_fixed_vectors_reproducible_helper(unsigned char *vector, size_t vector_len, unsigned char *commit, uint64_t *value_r, uint64_t *min_value_r, uint64_t *max_value_r, unsigned char *message_r, size_t *m_len_r) { + secp256k1_pedersen_commitment pc; + unsigned char blind_r[32]; + + CHECK(secp256k1_pedersen_commitment_parse(ctx, &pc, commit)); + CHECK(secp256k1_rangeproof_verify( + ctx, + min_value_r, max_value_r, + &pc, + vector, vector_len, + NULL, 0, + secp256k1_generator_h + )); + + *m_len_r = SECP256K1_RANGEPROOF_MAX_MESSAGE_LEN; + CHECK(secp256k1_rangeproof_rewind( + ctx, + blind_r, value_r, + message_r, m_len_r, + vector_nonce, + min_value_r, max_value_r, + &pc, + vector, vector_len, + NULL, 0, + secp256k1_generator_h + )); + CHECK(secp256k1_memcmp_var(blind_r, vector_blind, sizeof(vector_blind)) == 0); +} + +void test_rangeproof_fixed_vectors_reproducible(void) { + uint64_t value_r; + uint64_t min_value_r; + uint64_t max_value_r; + unsigned char message[SECP256K1_RANGEPROOF_MAX_MESSAGE_LEN], message_r[SECP256K1_RANGEPROOF_MAX_MESSAGE_LEN]; + size_t m_len_r; + memset(message, 0xFF, sizeof(message)); + + /* Test maximum values for value, min_bits, m_len and exp */ + { + uint64_t value = UINT64_MAX; + uint64_t min_value = 0; + size_t m_len = sizeof(message); /* maximum message length */ + + /* Uncomment this to recreate test vector */ + /* int min_bits = 64; */ + /* int exp = 18; */ + /* unsigned char proof[5126]; */ + /* size_t p_len = sizeof(proof); */ + /* secp256k1_pedersen_commitment pc; */ + /* CHECK(secp256k1_pedersen_commit(ctx, &pc, vector_blind, value, secp256k1_generator_h)); */ + /* CHECK(secp256k1_rangeproof_sign(ctx, proof, &p_len, min_value, &pc, vector_blind, vector_nonce, exp, min_bits, value, message, m_len, NULL, 0, secp256k1_generator_h)); */ + /* CHECK(p_len == sizeof(proof)); */ + /* print_vector(0, proof, p_len, &pc); */ + + unsigned char vector_0[] = { + 0x40, 0x3f, 0xd1, 0x77, 0x65, 0x05, 0x87, 0x88, 0xd0, 0x3d, 0xb2, 0x24, 0x60, 0x7a, 0x08, 0x76, + 0xf8, 0x9f, 0x5a, 0x00, 0x73, 0x32, 0x6b, 0x5b, 0x0b, 0x59, 0xda, 0xa0, 0x6d, 0x2b, 0x66, 0xb8, + 0xfa, 0xa4, 0x8c, 0xf9, 0x78, 0x5e, 0xe3, 0xc7, 0x30, 0xea, 0xb4, 0x31, 0x77, 0x3a, 0xe4, 0xe3, + 0xf0, 0x76, 0x15, 0x21, 0x07, 0xb3, 0x6e, 0x84, 0x36, 0xdb, 0x45, 0xe6, 0x2b, 0x14, 0x50, 0xf3, + 0x53, 0x5d, 0x79, 0xf8, 0x6d, 0xc4, 0x99, 0x36, 0xa4, 0x7c, 0xc1, 0x14, 0x90, 0x99, 0xa8, 0x4b, + 0xf0, 0x01, 0x9f, 0xe7, 0xd4, 0xf9, 0xf1, 0x74, 0xb0, 0x7f, 0xf5, 0x90, 0x8d, 0x27, 0x9e, 0x61, + 0x9e, 0xc5, 0xd0, 0xa6, 0x32, 0xe8, 0x64, 0x4a, 0x02, 0x8b, 0xbf, 0xf7, 0xb8, 0x31, 0xa3, 0x4d, + 0x99, 0xbe, 0x12, 0x77, 0x4b, 0x07, 0x4a, 0xef, 0x75, 0xb4, 0xb3, 0x6e, 0x96, 0x95, 0xff, 0xe9, + 0xf7, 0xfc, 0x27, 0x17, 0x62, 0xfa, 0x99, 0xed, 0x00, 0x3c, 0xdd, 0xaa, 0xae, 0x9e, 0x80, 0xc1, + 0x29, 0x73, 0x4d, 0xfc, 0x41, 0xe6, 0xb4, 0x21, 0xe2, 0x62, 0x78, 0xf5, 0x46, 0xef, 0xcd, 0xcf, + 0x15, 0x2a, 0x05, 0x80, 0xb9, 0x95, 0xaa, 0xa5, 0xe9, 0x69, 0x5f, 0xfd, 0x58, 0x12, 0x00, 0x51, + 0xc4, 0x8f, 0xa2, 0xce, 0x03, 0x7f, 0x16, 0x19, 0xb1, 0x77, 0xc2, 0x98, 0xbe, 0xaa, 0x18, 0x6a, + 0x80, 0x0b, 0x4a, 0x81, 0x85, 0xc0, 0xc2, 0x62, 0xb3, 0xec, 0xae, 0xe7, 0x95, 0xbf, 0xd3, 0xe0, + 0xcd, 0xa3, 0xdd, 0x02, 0x70, 0x98, 0x6c, 0xf3, 0x4b, 0x43, 0xec, 0x8d, 0x07, 0xf4, 0x3e, 0xb0, + 0x00, 0x7c, 0xb7, 0x1a, 0x85, 0x9a, 0x94, 0xe8, 0x57, 0xc9, 0x7e, 0x24, 0xb4, 0x7a, 0x84, 0x17, + 0x08, 0xe6, 0xae, 0x91, 0x14, 0xcb, 0x94, 0xf3, 0xe9, 0x13, 0x25, 0x35, 0x54, 0xbf, 0x22, 0xe9, + 0xab, 0x8e, 0xa4, 0xa1, 0x18, 0x78, 0x6c, 0xee, 0x13, 0x26, 0xfc, 0x79, 0xf1, 0xe5, 0x51, 0x1e, + 0x0c, 0xac, 0xa5, 0xef, 0x0d, 0xee, 0xe8, 0x5f, 0x93, 0xa4, 0x88, 0x4a, 0x32, 0x95, 0x8a, 0x61, + 0x76, 0xd8, 0xac, 0x2d, 0x36, 0x9a, 0x6b, 0xa4, 0x7c, 0x30, 0xa3, 0x09, 0x38, 0xbb, 0xbc, 0x51, + 0x1a, 0x10, 0xae, 0x9e, 0x18, 0x9f, 0xd8, 0xc8, 0xce, 0xfa, 0x63, 0xab, 0x28, 0xc9, 0x76, 0x28, + 0x32, 0x61, 0x39, 0x83, 0x99, 0x0a, 0x41, 0xc0, 0x55, 0x1c, 0x65, 0x6c, 0xcf, 0xc3, 0x72, 0x47, + 0xe7, 0xb1, 0x99, 0xb5, 0x04, 0x44, 0xb9, 0xde, 0x4b, 0x83, 0x37, 0x66, 0xb2, 0xee, 0x9f, 0x07, + 0xf1, 0x4f, 0x4d, 0x59, 0xee, 0x37, 0x79, 0x47, 0x0e, 0x31, 0x70, 0x3a, 0xfa, 0xe0, 0xa1, 0xef, + 0xa2, 0x1f, 0xeb, 0xe8, 0xd7, 0x4f, 0xcb, 0xc2, 0xce, 0xdc, 0x82, 0xa6, 0x36, 0xed, 0x1d, 0xdd, + 0xa6, 0x40, 0x10, 0x38, 0x4f, 0x28, 0x90, 0xc3, 0xe3, 0xb6, 0xa4, 0x74, 0xbb, 0x56, 0x23, 0x01, + 0x3a, 0xb6, 0xb1, 0xad, 0x94, 0x4b, 0x52, 0x42, 0x0a, 0x9d, 0xd6, 0x89, 0xdd, 0xa7, 0x0f, 0x66, + 0xdb, 0x4e, 0x5b, 0xa4, 0xc2, 0x11, 0xd7, 0xd5, 0xf7, 0x0a, 0xf1, 0xc8, 0x35, 0x16, 0xc0, 0x7d, + 0x29, 0x5d, 0x5c, 0x62, 0x6b, 0xe0, 0x1b, 0x74, 0x8d, 0x14, 0x9e, 0x08, 0xb6, 0x18, 0x0d, 0x2b, + 0x3a, 0xfb, 0x22, 0x9e, 0xd6, 0x77, 0x05, 0x1b, 0xd4, 0x5d, 0x25, 0x27, 0x97, 0x40, 0x93, 0x58, + 0x35, 0xad, 0xc5, 0x19, 0x96, 0x62, 0xbb, 0x10, 0x2d, 0x4e, 0x24, 0x62, 0xc0, 0x1a, 0xe6, 0x12, + 0x84, 0xac, 0x1b, 0x5e, 0x25, 0xa9, 0xc7, 0x5d, 0xa0, 0x34, 0x85, 0x70, 0xf1, 0x08, 0xd8, 0xf9, + 0x1c, 0x1b, 0x71, 0xcc, 0x72, 0xec, 0xce, 0x30, 0x91, 0x67, 0xac, 0xe5, 0x4e, 0x51, 0xa6, 0x47, + 0x74, 0x09, 0x19, 0xee, 0x9d, 0x2d, 0x3f, 0xf2, 0x49, 0x5a, 0xf0, 0x6c, 0x8f, 0xe9, 0x1f, 0x10, + 0xcc, 0x32, 0x2f, 0x8d, 0x3e, 0xfa, 0xba, 0x0c, 0x37, 0x51, 0xe2, 0x3e, 0xcc, 0xdd, 0x81, 0xd5, + 0xef, 0xef, 0x56, 0x3a, 0xd2, 0x96, 0x10, 0xfb, 0x19, 0xce, 0x90, 0xbf, 0x82, 0x11, 0xf6, 0xe6, + 0x28, 0x7e, 0x4d, 0x16, 0x61, 0x87, 0xdd, 0xc5, 0x61, 0x5d, 0x85, 0xa9, 0x02, 0xea, 0xdf, 0x7a, + 0x2c, 0x92, 0xdd, 0xc3, 0xa3, 0xc9, 0xec, 0xd9, 0xc0, 0x54, 0xbd, 0xf2, 0x77, 0x00, 0x5e, 0x18, + 0x8c, 0x0a, 0x63, 0xdf, 0x8f, 0xf9, 0x1e, 0x45, 0x1c, 0xd1, 0xf7, 0x11, 0x1e, 0xbd, 0x20, 0x30, + 0x1c, 0x27, 0x45, 0xfe, 0xb7, 0xe6, 0x93, 0xae, 0x2a, 0xc1, 0xdc, 0xe2, 0xf6, 0xd1, 0x54, 0x42, + 0xa3, 0x26, 0x79, 0xd6, 0xb3, 0x5c, 0xb0, 0xd2, 0x97, 0x3e, 0xc0, 0x0e, 0xce, 0xf4, 0x82, 0x42, + 0x99, 0x49, 0xb7, 0xad, 0x33, 0xd6, 0x67, 0x81, 0xaf, 0x40, 0xa2, 0xbd, 0x71, 0x7e, 0x82, 0x66, + 0x8d, 0x97, 0x3b, 0x9d, 0x30, 0xe8, 0x4b, 0x4d, 0xcd, 0xf0, 0x1e, 0xfb, 0x33, 0xbd, 0xcd, 0xb2, + 0xca, 0x7e, 0x5d, 0xa2, 0xe5, 0x6a, 0xa1, 0xc0, 0xbd, 0xae, 0x8c, 0x65, 0x93, 0x9d, 0x53, 0x6f, + 0x8d, 0xce, 0x4f, 0xc2, 0xb1, 0x54, 0x7d, 0x7a, 0x59, 0x08, 0xc0, 0xaa, 0xfc, 0x12, 0xa9, 0x41, + 0x9b, 0x11, 0x3c, 0x24, 0x3a, 0x89, 0x8f, 0x2f, 0x5a, 0x49, 0x44, 0x64, 0x83, 0x17, 0xbe, 0xa2, + 0xff, 0x6f, 0xcb, 0x65, 0x04, 0x6f, 0x75, 0x4c, 0x5d, 0x15, 0x06, 0x7b, 0x3b, 0x3e, 0xc1, 0xed, + 0xcb, 0xdc, 0xde, 0x04, 0x03, 0x30, 0x74, 0xc2, 0x6b, 0x50, 0x53, 0x6b, 0x8c, 0xcd, 0x1b, 0xe7, + 0xd5, 0xf8, 0x42, 0xe5, 0x07, 0x16, 0xc3, 0x70, 0x83, 0x49, 0x25, 0xa4, 0x1e, 0x61, 0xa8, 0xc4, + 0x13, 0x82, 0xfe, 0x56, 0xd7, 0x04, 0xbe, 0x4d, 0x59, 0x05, 0xb8, 0x35, 0xcc, 0xd2, 0xaf, 0x40, + 0x24, 0xf3, 0xbc, 0x48, 0x58, 0x0e, 0x01, 0xe6, 0x47, 0x19, 0x9d, 0xb6, 0xe3, 0x6f, 0x17, 0x5e, + 0xab, 0x6c, 0xa3, 0x5a, 0x9a, 0xdd, 0x95, 0x2a, 0x18, 0x22, 0x42, 0x36, 0x07, 0xa0, 0x47, 0xb1, + 0x2e, 0x8f, 0xc8, 0x78, 0xcc, 0x7d, 0x16, 0x61, 0x5f, 0x34, 0x66, 0xee, 0x01, 0x17, 0x60, 0xa3, + 0x3f, 0x4d, 0xb1, 0xcc, 0xcc, 0x13, 0x99, 0x51, 0x3e, 0x78, 0x69, 0x7b, 0x83, 0x49, 0x5f, 0xf3, + 0x89, 0xa9, 0x9e, 0x24, 0x18, 0x08, 0x4d, 0xdb, 0x8a, 0xb1, 0xd8, 0xd7, 0xae, 0x30, 0x82, 0x4d, + 0x3d, 0x4f, 0xce, 0xbe, 0x17, 0xe5, 0x47, 0x5d, 0xa6, 0x03, 0x8c, 0xae, 0xe7, 0xa2, 0x63, 0xf3, + 0xe8, 0x88, 0x21, 0xf4, 0xfd, 0xa9, 0x32, 0x15, 0x93, 0x0c, 0xbe, 0x61, 0xe8, 0x35, 0x6c, 0xb5, + 0xc9, 0xa9, 0xec, 0x1c, 0x7f, 0x34, 0x5b, 0xb0, 0x80, 0x6d, 0x0a, 0x52, 0x87, 0x74, 0x12, 0x90, + 0x3a, 0xf7, 0x40, 0x41, 0xe1, 0x62, 0xa5, 0xb7, 0xf0, 0x5d, 0x45, 0x3e, 0x55, 0x1a, 0x30, 0xec, + 0x5d, 0x52, 0x00, 0x76, 0x38, 0x10, 0x0d, 0xf0, 0x2f, 0x7f, 0xf2, 0x3e, 0x34, 0x1f, 0x1a, 0xd9, + 0xf8, 0xb9, 0x86, 0xf9, 0xdc, 0x05, 0xe0, 0xcf, 0x28, 0x49, 0xfd, 0x21, 0x64, 0xf6, 0xa1, 0xc4, + 0xf7, 0xce, 0x91, 0xb2, 0x15, 0xdf, 0x82, 0x39, 0x30, 0x60, 0xf3, 0xd1, 0xa6, 0x18, 0xc4, 0x3b, + 0xf7, 0xd2, 0x64, 0xe8, 0xab, 0x67, 0x23, 0xb8, 0x2c, 0x57, 0x84, 0x17, 0xc0, 0x2c, 0x21, 0xfc, + 0x55, 0x8b, 0xb6, 0x06, 0xbf, 0x79, 0x7e, 0x29, 0x5a, 0xfb, 0x5c, 0xa5, 0x5a, 0xe4, 0x46, 0xac, + 0x16, 0x8e, 0xf4, 0x03, 0xb7, 0xbb, 0xb0, 0x7b, 0xbf, 0xd3, 0x84, 0xbe, 0xb5, 0x6a, 0xc8, 0x28, + 0xe8, 0x2c, 0x2d, 0x0b, 0x7d, 0x0a, 0x65, 0xd3, 0xee, 0x54, 0x8c, 0xbf, 0xd9, 0xda, 0x84, 0x21, + 0x80, 0x07, 0x68, 0x09, 0x75, 0xbd, 0xa8, 0xd0, 0xbf, 0xa0, 0xf3, 0xc7, 0xc5, 0xb5, 0xf2, 0xf8, + 0xf1, 0x74, 0x6e, 0x7d, 0xad, 0x80, 0xbd, 0x87, 0xe9, 0x83, 0x2e, 0xda, 0x61, 0x28, 0x03, 0x74, + 0xe5, 0x45, 0x74, 0x0d, 0x1f, 0x47, 0x46, 0x10, 0x7f, 0xef, 0x12, 0x9f, 0x78, 0xec, 0x03, 0xed, + 0x22, 0x86, 0x6f, 0x1a, 0x31, 0x14, 0xf4, 0x3a, 0x7f, 0xef, 0x98, 0x3e, 0x64, 0x86, 0xb9, 0x0e, + 0x5b, 0x0d, 0x55, 0xba, 0xcc, 0x6d, 0x04, 0xc7, 0x9c, 0x1e, 0xd4, 0xf7, 0xf0, 0x60, 0x6d, 0x54, + 0x75, 0x70, 0x3b, 0x99, 0xd3, 0x01, 0x9f, 0x34, 0x44, 0x98, 0xab, 0xd1, 0x6b, 0xc8, 0xaa, 0xfd, + 0xd9, 0x5a, 0xd3, 0xee, 0x5d, 0x2c, 0x54, 0x38, 0x06, 0x1f, 0x93, 0xb3, 0x5c, 0x87, 0x10, 0x5e, + 0xcb, 0xcd, 0xd3, 0x4a, 0x89, 0xd2, 0x0d, 0xac, 0xeb, 0x42, 0x67, 0x2b, 0xd1, 0x75, 0x12, 0x58, + 0xdd, 0x19, 0xe3, 0x21, 0x33, 0x75, 0xf6, 0x51, 0x25, 0xeb, 0xa6, 0x43, 0x44, 0x82, 0x64, 0xae, + 0xb8, 0x97, 0x01, 0xff, 0x17, 0x8f, 0xce, 0x96, 0xc8, 0xc3, 0x86, 0xa0, 0x05, 0xb2, 0x2c, 0x33, + 0x01, 0x27, 0x25, 0x84, 0x83, 0x85, 0x33, 0xe2, 0xd0, 0xc5, 0x65, 0x89, 0x85, 0x45, 0x81, 0x3f, + 0x2d, 0xb4, 0xb1, 0x8b, 0x1d, 0x04, 0x5d, 0x4c, 0xd8, 0x46, 0x8a, 0x04, 0x3a, 0x3b, 0xa7, 0x76, + 0x47, 0x5e, 0xcc, 0xc0, 0x16, 0xb2, 0x3a, 0x38, 0x9a, 0x6a, 0x50, 0x3a, 0x8b, 0x82, 0xb7, 0x6b, + 0xf2, 0x60, 0x53, 0x4e, 0xdf, 0x8a, 0x02, 0x9f, 0xc6, 0x27, 0x4f, 0xf5, 0x2a, 0xf1, 0xf1, 0x2f, + 0x4a, 0xaa, 0xc7, 0x94, 0xc0, 0xdc, 0xdb, 0x8c, 0x41, 0xd9, 0x16, 0x13, 0xa2, 0xae, 0x37, 0x2a, + 0x7e, 0x26, 0x6f, 0xdf, 0x46, 0x07, 0x74, 0x88, 0x62, 0xab, 0x28, 0x64, 0x12, 0x7c, 0xca, 0xd5, + 0xbb, 0x6f, 0x7f, 0x3b, 0x44, 0x99, 0x20, 0x93, 0x9a, 0xa0, 0xac, 0x17, 0xed, 0x82, 0xf9, 0x43, + 0xc2, 0x98, 0x6b, 0xcf, 0x54, 0x91, 0xfe, 0x3c, 0x9e, 0xfa, 0x7b, 0x57, 0x38, 0xe2, 0x64, 0x58, + 0x9c, 0xe0, 0x41, 0x95, 0x8a, 0xa0, 0xa3, 0x3d, 0x7b, 0x3e, 0x99, 0xea, 0xc7, 0xec, 0x82, 0xc8, + 0xa8, 0xae, 0xbd, 0xf9, 0x5c, 0x7e, 0xa2, 0x20, 0x78, 0xce, 0x4a, 0x6c, 0x74, 0x2a, 0xe7, 0x31, + 0xdb, 0xc1, 0x02, 0x49, 0x4b, 0x83, 0x0b, 0x0e, 0x7e, 0xeb, 0x69, 0x59, 0xf9, 0x3c, 0x13, 0x47, + 0xaf, 0xbd, 0x58, 0xec, 0x7f, 0xae, 0x7e, 0x4b, 0xf3, 0x3d, 0x18, 0xbf, 0xb0, 0x79, 0x92, 0x59, + 0x9e, 0x5f, 0x03, 0x30, 0x15, 0xba, 0xec, 0xd1, 0xaf, 0x2e, 0xf7, 0x88, 0xde, 0x50, 0xae, 0x9e, + 0x59, 0x14, 0xf3, 0xa5, 0x78, 0x25, 0xd7, 0xd9, 0x1a, 0x33, 0x81, 0x29, 0x8b, 0x93, 0xf6, 0xfa, + 0x90, 0x3d, 0x13, 0xaa, 0x0d, 0xa7, 0x8e, 0x79, 0xc0, 0x36, 0x45, 0x29, 0xa5, 0xf1, 0xfe, 0x92, + 0x1b, 0x57, 0x42, 0x58, 0xe0, 0x85, 0x15, 0xa2, 0xc9, 0xb1, 0x50, 0x08, 0x6a, 0x02, 0x46, 0xc6, + 0x1d, 0xd0, 0xf0, 0xb4, 0x5a, 0xcc, 0xd5, 0x54, 0x9d, 0xab, 0x13, 0x47, 0x9f, 0x82, 0x60, 0x9b, + 0x11, 0x64, 0x35, 0xfa, 0xef, 0x89, 0xb4, 0x87, 0x43, 0x48, 0x6e, 0x78, 0x64, 0x01, 0xbe, 0x09, + 0xd1, 0xd0, 0x40, 0xdf, 0x77, 0x6b, 0xee, 0x92, 0xc5, 0xff, 0x77, 0xcf, 0x20, 0x95, 0x36, 0x78, + 0x35, 0x1f, 0x1e, 0xaf, 0x4b, 0xa7, 0x66, 0x71, 0x9d, 0x5e, 0xb7, 0xd9, 0x70, 0x6e, 0xaa, 0x35, + 0x49, 0x3c, 0x9a, 0x23, 0x53, 0xaf, 0x3e, 0x9d, 0x60, 0x72, 0xb5, 0x27, 0x33, 0x80, 0x33, 0xd2, + 0x11, 0x4b, 0xff, 0xfb, 0x53, 0xab, 0x14, 0x4c, 0xe4, 0xe7, 0xbc, 0x2f, 0x5c, 0xd8, 0xbf, 0x81, + 0x5c, 0xf7, 0x4d, 0x5d, 0xb8, 0x84, 0x62, 0xf3, 0xd2, 0x0a, 0x53, 0x66, 0xd3, 0x13, 0xff, 0xb0, + 0xeb, 0x4b, 0x1f, 0x10, 0x1d, 0xa9, 0xba, 0x5c, 0xad, 0xe2, 0x52, 0x91, 0xae, 0xbe, 0x5d, 0x05, + 0x54, 0x6d, 0x72, 0x1e, 0xc1, 0x14, 0xb5, 0x9b, 0x22, 0x3f, 0x78, 0x73, 0x5e, 0x99, 0x50, 0xde, + 0xa8, 0x41, 0x31, 0xd0, 0x44, 0xf3, 0x2f, 0x31, 0xd9, 0x0b, 0x72, 0x1a, 0xd3, 0x70, 0xbe, 0x84, + 0xfc, 0xe1, 0xed, 0x15, 0xb9, 0xe9, 0x69, 0xe2, 0xbe, 0x50, 0xa2, 0xda, 0x4e, 0x7a, 0x83, 0xc5, + 0x56, 0xea, 0xaf, 0x2c, 0xc9, 0x8f, 0xcc, 0x83, 0x1a, 0xa5, 0x0e, 0x74, 0xaa, 0x64, 0x96, 0xb5, + 0x5a, 0x4a, 0x72, 0xad, 0x86, 0x5a, 0xb8, 0x5a, 0x04, 0x0d, 0x68, 0x21, 0x63, 0x23, 0x7b, 0x17, + 0x9d, 0xfd, 0x1b, 0x3f, 0xac, 0x80, 0x98, 0x97, 0xb5, 0xd4, 0xb7, 0x08, 0x50, 0xf4, 0x18, 0xf9, + 0x16, 0xb1, 0x57, 0xfa, 0xff, 0xa8, 0x02, 0x6e, 0x62, 0x7b, 0x15, 0x8d, 0xc0, 0x17, 0xdd, 0xa3, + 0x45, 0x98, 0x5a, 0xa0, 0xda, 0xe2, 0xd1, 0x17, 0x91, 0x3d, 0xda, 0x18, 0x16, 0x19, 0x3a, 0xfb, + 0xfd, 0x44, 0x72, 0x03, 0x97, 0x72, 0x1d, 0xbf, 0x11, 0xca, 0x95, 0x05, 0x6a, 0x9e, 0x41, 0x3d, + 0x85, 0xb4, 0xd9, 0xb3, 0x88, 0xd4, 0xd9, 0xfb, 0x1c, 0xd2, 0x35, 0x31, 0x12, 0xcc, 0xf3, 0x03, + 0x50, 0x8a, 0xfb, 0x0e, 0x72, 0xeb, 0x86, 0x65, 0xd5, 0x96, 0x0f, 0x53, 0x1e, 0x13, 0x99, 0x91, + 0xa7, 0x70, 0xab, 0x4c, 0xa6, 0x1a, 0xb7, 0x0d, 0x71, 0x0e, 0xb6, 0x17, 0x85, 0xdf, 0x9b, 0x74, + 0x19, 0x4a, 0xc7, 0x55, 0x0e, 0xe9, 0x22, 0x6b, 0x8e, 0xa8, 0x5e, 0x45, 0xc4, 0x0f, 0x36, 0xbb, + 0x21, 0xda, 0x97, 0xcf, 0xed, 0x41, 0xb5, 0x00, 0x26, 0xb1, 0x70, 0x43, 0x5c, 0x60, 0x59, 0x23, + 0x19, 0xc5, 0xdb, 0x49, 0xef, 0xdd, 0x5d, 0x19, 0x5f, 0x58, 0xaa, 0x20, 0xd9, 0x09, 0x17, 0x09, + 0xc7, 0x5f, 0xb9, 0x65, 0x8f, 0x0a, 0xe8, 0x4d, 0x7d, 0x60, 0x88, 0x7a, 0x53, 0x9e, 0xf1, 0x25, + 0xcd, 0xa1, 0x3e, 0xc6, 0xc5, 0x86, 0xf2, 0xee, 0x60, 0x0f, 0x11, 0x3e, 0xe3, 0x90, 0x4d, 0xff, + 0x49, 0x0b, 0x2f, 0x85, 0x7f, 0x18, 0x53, 0x4e, 0xe2, 0x5c, 0x06, 0x61, 0x51, 0x08, 0xca, 0x55, + 0x80, 0x83, 0xa4, 0x80, 0x05, 0x26, 0xe7, 0x29, 0xdb, 0xab, 0x94, 0x66, 0xe9, 0xbf, 0xf8, 0xd2, + 0x79, 0x71, 0x61, 0x05, 0x33, 0xc8, 0x6b, 0x5c, 0x62, 0x01, 0x7f, 0x82, 0xef, 0x5f, 0xa3, 0xf6, + 0x29, 0x86, 0xb6, 0x0a, 0xa5, 0xed, 0x3a, 0xae, 0x34, 0x12, 0xba, 0xb0, 0x80, 0xd4, 0x53, 0x79, + 0x57, 0x7d, 0xa2, 0x38, 0xfd, 0x39, 0xc1, 0xaf, 0x07, 0x8d, 0x23, 0x6b, 0xcd, 0x97, 0xe0, 0xf6, + 0x83, 0x74, 0x7c, 0x3c, 0x95, 0xdb, 0xb1, 0xf0, 0xf7, 0x9e, 0xe9, 0xe4, 0x68, 0x67, 0x18, 0x0e, + 0x00, 0x12, 0x70, 0x79, 0xc2, 0xfe, 0xde, 0x00, 0x12, 0x87, 0x00, 0xd3, 0x8a, 0xc5, 0x1b, 0xb4, + 0xd7, 0x46, 0x1d, 0x73, 0x5c, 0x51, 0x93, 0x19, 0x83, 0x1b, 0x28, 0xb9, 0x70, 0x87, 0x20, 0x34, + 0xb6, 0x7e, 0xb9, 0x1f, 0x9d, 0x15, 0xdb, 0xd7, 0xfb, 0x30, 0x92, 0xe8, 0x21, 0x6c, 0x5c, 0xdb, + 0xaf, 0x5c, 0xd5, 0xa5, 0x76, 0x4b, 0x5f, 0xc3, 0xa8, 0x73, 0x9a, 0x42, 0x04, 0x21, 0xf1, 0x49, + 0xbc, 0x47, 0xa0, 0xa7, 0x4a, 0xda, 0x16, 0x34, 0xcd, 0x62, 0xe1, 0xe0, 0x9a, 0x35, 0xf2, 0xf9, + 0xb2, 0x3c, 0xcf, 0xa6, 0x4f, 0xd7, 0x23, 0xc2, 0xd2, 0xa5, 0x5a, 0xf9, 0xfd, 0x7d, 0x25, 0x84, + 0xda, 0xda, 0x66, 0xb9, 0x99, 0x7f, 0xec, 0xfc, 0x82, 0x7c, 0xea, 0x6b, 0x23, 0x89, 0x6e, 0xab, + 0xe9, 0x43, 0xcb, 0x88, 0xcd, 0x18, 0x6e, 0xae, 0x2d, 0xf5, 0xc7, 0xe3, 0x92, 0x55, 0x0b, 0xc0, + 0x4d, 0xc8, 0xee, 0x4b, 0x7e, 0xfe, 0x84, 0x8c, 0x32, 0x33, 0xc8, 0xf1, 0xfb, 0xd8, 0x11, 0x22, + 0xd9, 0x0d, 0x2b, 0x16, 0x19, 0xba, 0x65, 0xe4, 0x99, 0x26, 0x7b, 0xa7, 0x04, 0x11, 0xfc, 0xb8, + 0x05, 0x48, 0x36, 0x43, 0x82, 0x14, 0xb7, 0x31, 0x50, 0xfd, 0x38, 0x89, 0xc1, 0x36, 0xa1, 0xd5, + 0x8e, 0x52, 0x76, 0x99, 0xc8, 0x38, 0x49, 0xb4, 0x94, 0x02, 0x96, 0x35, 0x8c, 0xc1, 0x9c, 0x7c, + 0x2b, 0xbe, 0x73, 0x62, 0x0a, 0xd3, 0x57, 0x3d, 0xdb, 0x81, 0x14, 0x7c, 0xd0, 0x4a, 0xe5, 0x2f, + 0x63, 0xbd, 0xac, 0xcf, 0x83, 0x10, 0xfd, 0x06, 0x54, 0xc0, 0x5c, 0xba, 0x96, 0x72, 0x0b, 0xcf, + 0x0a, 0x74, 0xe2, 0xbf, 0xbc, 0x1c, 0xc6, 0xd8, 0x9e, 0x7f, 0x5f, 0xbb, 0x00, 0xfe, 0x2a, 0xbd, + 0x36, 0x02, 0x56, 0x5b, 0xa2, 0x30, 0x75, 0x44, 0x62, 0xf8, 0x22, 0x24, 0x14, 0x04, 0x30, 0x26, + 0xe5, 0xb4, 0x06, 0x3d, 0xfe, 0x5c, 0x3a, 0xc7, 0xd8, 0x1d, 0x1b, 0xc9, 0x99, 0xbb, 0xa5, 0x2c, + 0x92, 0x3b, 0xaa, 0x92, 0xf2, 0x12, 0x59, 0xc1, 0xd7, 0xec, 0xae, 0x89, 0x45, 0xfb, 0xe6, 0x15, + 0xa7, 0xe8, 0xad, 0x26, 0xf9, 0xb3, 0xe0, 0xd5, 0x57, 0xab, 0x4c, 0xab, 0xda, 0xe0, 0xc2, 0x9d, + 0xb1, 0x12, 0x6f, 0xc9, 0x84, 0x2b, 0x66, 0x89, 0x05, 0x37, 0x2a, 0x6b, 0x8d, 0xe8, 0x21, 0xa4, + 0xbb, 0x28, 0xc4, 0xb4, 0xa6, 0x93, 0xc2, 0xc9, 0x54, 0x39, 0x38, 0x84, 0xae, 0x70, 0x9b, 0xcf, + 0xc5, 0xc5, 0x3c, 0x56, 0x21, 0xb4, 0x95, 0xb0, 0xa7, 0x2a, 0x30, 0xd8, 0xcb, 0x18, 0x22, 0x31, + 0x59, 0x01, 0x62, 0x43, 0xe2, 0x65, 0xb9, 0xf3, 0xc6, 0x5c, 0x9c, 0xe1, 0xea, 0x48, 0x6f, 0x10, + 0xc2, 0x27, 0x3a, 0xd6, 0xd1, 0x15, 0xeb, 0x7f, 0xc9, 0x2b, 0x21, 0x25, 0xae, 0x91, 0x34, 0xd0, + 0x6b, 0xfe, 0xe3, 0x79, 0x52, 0xb9, 0xb2, 0x17, 0xd6, 0x6b, 0xf0, 0xfa, 0x3f, 0x15, 0xb5, 0x74, + 0x10, 0xf9, 0xd9, 0xb0, 0xc5, 0xdb, 0x72, 0x1a, 0x76, 0xeb, 0x41, 0x6f, 0xb5, 0x9b, 0x8d, 0xb9, + 0x8f, 0x75, 0x6d, 0xc8, 0x25, 0xfa, 0xee, 0xdb, 0x1c, 0x3c, 0x01, 0x80, 0x38, 0x5b, 0x83, 0x01, + 0xc0, 0x02, 0xa1, 0x1c, 0x71, 0xef, 0xbc, 0x58, 0xa5, 0xf6, 0x49, 0xb7, 0xef, 0x9c, 0xa7, 0x7d, + 0x39, 0xcc, 0x2a, 0x0b, 0xdb, 0x78, 0xb7, 0x5d, 0x22, 0x36, 0xb1, 0x36, 0x72, 0x56, 0x62, 0x19, + 0xf1, 0x5c, 0x0a, 0x63, 0x02, 0x6a, 0x59, 0x8e, 0x24, 0xb6, 0x32, 0x21, 0x11, 0x96, 0xd2, 0x8c, + 0xf1, 0xaf, 0x84, 0x3f, 0xf5, 0x98, 0x0d, 0x22, 0x14, 0x15, 0xda, 0x9f, 0x44, 0x0b, 0x08, 0x33, + 0x13, 0x11, 0x53, 0x78, 0xe1, 0xf1, 0x4b, 0x40, 0x1c, 0x43, 0x73, 0x5d, 0x86, 0x06, 0xe1, 0x02, + 0x79, 0x3f, 0x68, 0x00, 0xb7, 0xb0, 0xcb, 0x3b, 0x2e, 0x12, 0x4e, 0x81, 0x77, 0x2a, 0xc5, 0x74, + 0xc4, 0xd9, 0xa0, 0x1e, 0xa3, 0x74, 0x17, 0x61, 0x15, 0xaf, 0xa7, 0xb4, 0x25, 0x61, 0x85, 0x60, + 0x70, 0x85, 0xfb, 0x43, 0xb9, 0x43, 0x4f, 0x87, 0x44, 0x1a, 0x7b, 0xee, 0x68, 0xbb, 0x74, 0x99, + 0xff, 0x81, 0x22, 0xb4, 0x8d, 0x94, 0xf0, 0x4a, 0x3e, 0x28, 0xf5, 0xbd, 0x5c, 0xa1, 0x7f, 0x5c, + 0xea, 0xe6, 0xba, 0xf2, 0x5d, 0x85, 0xf2, 0xed, 0xd7, 0xfd, 0x93, 0xf0, 0xbb, 0xba, 0x86, 0x23, + 0xb5, 0xee, 0xb5, 0x5b, 0xd9, 0x91, 0xbf, 0xdc, 0xe3, 0xdc, 0xbe, 0x82, 0x92, 0xce, 0xb4, 0x0f, + 0xbf, 0xf1, 0x80, 0x0f, 0xe8, 0xc3, 0x04, 0x49, 0x3e, 0x95, 0x72, 0xf8, 0x36, 0x44, 0xce, 0xf4, + 0x3a, 0x6a, 0xeb, 0xdd, 0x88, 0x28, 0x8d, 0xf3, 0x04, 0x65, 0xd8, 0xfd, 0x9d, 0xb1, 0x22, 0xbd, + 0x44, 0xe7, 0xcf, 0x0f, 0x2f, 0xfc, 0xb6, 0xd6, 0x60, 0x7a, 0x6e, 0x6a, 0x93, 0x83, 0xf1, 0x86, + 0xf4, 0xf1, 0x23, 0xb2, 0xfd, 0x4a, 0xb6, 0xcf, 0x97, 0x70, 0xae, 0xa9, 0x44, 0x94, 0x7a, 0x4e, + 0xf9, 0x1e, 0xf8, 0xdc, 0x1f, 0xf0, 0x06, 0x16, 0xdf, 0x69, 0xde, 0x70, 0xea, 0x64, 0x98, 0xe6, + 0x1f, 0x9f, 0x3a, 0xcf, 0xf6, 0xb6, 0x10, 0xb1, 0x3c, 0xd1, 0x76, 0x67, 0x6c, 0xaf, 0x3c, 0x0a, + 0xc3, 0x46, 0x31, 0x89, 0xf7, 0x7a, 0x0f, 0x9b, 0x7d, 0xd8, 0x9a, 0x81, 0x57, 0x0c, 0x37, 0xda, + 0xf7, 0xc3, 0xe5, 0x4b, 0x14, 0xe9, 0x0e, 0x8c, 0x27, 0xdc, 0x68, 0xdb, 0xd8, 0xdb, 0x8b, 0xee, + 0x4e, 0x9f, 0x93, 0x18, 0x4c, 0x75, 0xec, 0x41, 0x6f, 0xbe, 0x89, 0xe3, 0x77, 0x64, 0xbd, 0x22, + 0xa1, 0x0a, 0x16, 0x93, 0xbc, 0x7a, 0xec, 0x6e, 0x3c, 0x2d, 0x97, 0x4a, 0xb1, 0x7d, 0xb6, 0xfc, + 0x01, 0x8b, 0x87, 0x2b, 0x60, 0xe4, 0x53, 0xde, 0x72, 0xef, 0xa5, 0xdf, 0xeb, 0x2d, 0x3c, 0x01, + 0xdc, 0xfd, 0xd8, 0x3b, 0x2a, 0x16, 0x74, 0x1b, 0x26, 0x40, 0x5c, 0x4d, 0x11, 0x7f, 0xa8, 0x3f, + 0xc9, 0xe8, 0x8f, 0x6b, 0xe4, 0x96, 0x3f, 0x2b, 0x4e, 0xfa, 0x1f, 0xa5, 0x73, 0x85, 0xbb, 0xe5, + 0x6f, 0xd7, 0x0c, 0xf4, 0x46, 0x81, 0xfd, 0x0d, 0x0f, 0x70, 0x3c, 0x51, 0x46, 0x47, 0x5d, 0x37, + 0x02, 0x94, 0x52, 0x44, 0x4b, 0xac, 0x30, 0xc3, 0x72, 0xd1, 0x50, 0x5e, 0x29, 0xa2, 0x4a, 0xfb, + 0xbe, 0x8e, 0x60, 0x16, 0xb0, 0xb1, 0x82, 0xd8, 0x29, 0xf5, 0x3c, 0x72, 0x3c, 0x79, 0x9d, 0xa8, + 0x64, 0x15, 0x57, 0x7a, 0x10, 0x0f, 0xb4, 0xc0, 0x02, 0xdb, 0xc6, 0x6c, 0x37, 0xa1, 0xf3, 0x52, + 0x5c, 0xb5, 0xcd, 0x42, 0xf1, 0x43, 0x31, 0xfe, 0x0b, 0xaa, 0xcb, 0xd5, 0x0a, 0xf4, 0x69, 0x64, + 0xf5, 0x98, 0x41, 0x53, 0xed, 0x04, 0x27, 0x56, 0x4a, 0xe9, 0x4c, 0x96, 0x64, 0x29, 0xff, 0xe2, + 0xe1, 0x79, 0xf5, 0x78, 0x69, 0x43, 0xe6, 0x4e, 0x4e, 0xa8, 0x8a, 0x50, 0x15, 0x37, 0x44, 0x73, + 0x41, 0xe8, 0x21, 0xe4, 0x0a, 0x2e, 0x43, 0x2d, 0x4b, 0xd1, 0xfe, 0xf5, 0xc5, 0x30, 0x31, 0x39, + 0xfa, 0x53, 0x7a, 0x3c, 0xd5, 0x63, 0x7a, 0x5c, 0xff, 0x18, 0xf8, 0x79, 0x84, 0x73, 0x84, 0x55, + 0x61, 0x17, 0x2f, 0xad, 0x34, 0xd3, 0xf2, 0xf3, 0x2b, 0xe6, 0xe3, 0xc2, 0x0e, 0x2b, 0x28, 0xc4, + 0x92, 0xd0, 0xd3, 0x14, 0x06, 0x58, 0xbb, 0x2f, 0xdf, 0xe6, 0x3d, 0x0d, 0x6b, 0x71, 0x40, 0xc2, + 0xbf, 0x6b, 0x41, 0xae, 0x85, 0x39, 0x1c, 0xdf, 0x02, 0xf3, 0x6e, 0x85, 0x15, 0x1d, 0xb8, 0xe4, + 0xbe, 0x32, 0x77, 0x70, 0x22, 0x5b, 0xe7, 0x03, 0xd6, 0x1c, 0xab, 0x90, 0x9b, 0x0d, 0x03, 0x40, + 0x0f, 0x3d, 0x82, 0x9b, 0xb8, 0x32, 0x03, 0x99, 0xee, 0xe4, 0xa9, 0x63, 0x35, 0xec, 0xe2, 0x29, + 0xb3, 0xda, 0x4c, 0x3c, 0x4c, 0x6b, 0x4f, 0x67, 0x0a, 0x8e, 0x35, 0xe2, 0xe5, 0x3d, 0x97, 0xe6, + 0xec, 0xb2, 0x99, 0xa2, 0x7d, 0x1c, 0xf0, 0xb0, 0x6d, 0xc7, 0x14, 0xe6, 0xb1, 0x77, 0x75, 0x2d, + 0x73, 0x0e, 0xa6, 0x3b, 0x4b, 0x90, 0xac, 0xe4, 0x34, 0x60, 0x6d, 0x03, 0xba, 0xb2, 0xb4, 0xb8, + 0x11, 0xe1, 0x1c, 0xb2, 0x27, 0xbb, 0x39, 0x61, 0x47, 0x53, 0x3e, 0xb0, 0x5b, 0x0d, 0x5a, 0xc9, + 0x36, 0xd5, 0xd3, 0x99, 0xa8, 0xdb, 0x74, 0x32, 0x5b, 0x05, 0x95, 0x0d, 0x2f, 0x19, 0xa7, 0x99, + 0x2e, 0x57, 0x19, 0xde, 0x4b, 0xb9, 0x08, 0x57, 0xdc, 0x37, 0x15, 0x7d, 0x1f, 0xe5, 0x12, 0x33, + 0x91, 0xa1, 0xdd, 0xe3, 0x30, 0x2b, 0x84, 0x4c, 0xe9, 0xbd, 0x0c, 0x8b, 0x6d, 0xe4, 0x75, 0x12, + 0x41, 0x98, 0x4b, 0xab, 0x25, 0xda, 0x4b, 0xc0, 0x92, 0xb1, 0x4a, 0x32, 0x06, 0x5a, 0xac, 0x93, + 0xf2, 0x6f, 0x01, 0x4d, 0xc1, 0xac, 0xf2, 0x37, 0x8b, 0x4e, 0x03, 0xbb, 0xd0, 0x06, 0x4f, 0xfa, + 0x7d, 0xb5, 0xdc, 0x1e, 0xf3, 0x2d, 0x05, 0x29, 0x1b, 0x7e, 0x6e, 0x0e, 0x26, 0x3c, 0x11, 0x5c, + 0xaf, 0x97, 0x55, 0x5a, 0xc9, 0x4f, 0x75, 0xb5, 0x24, 0x72, 0xa7, 0x07, 0x0b, 0x02, 0xd9, 0xa2, + 0xa3, 0xb0, 0xde, 0x30, 0x22, 0xfc, 0x54, 0x14, 0xfa, 0x7b, 0x19, 0x58, 0x19, 0x59, 0x9f, 0x7d, + 0x8a, 0x63, 0xd7, 0x27, 0x66, 0xe0, 0x52, 0x05, 0x3d, 0x4e, 0x14, 0xad, 0xf5, 0xaa, 0xc5, 0x79, + 0x1a, 0x02, 0x78, 0x03, 0x2c, 0xe4, 0x86, 0x14, 0x51, 0xbc, 0xc7, 0x31, 0x58, 0x04, 0x39, 0xe9, + 0xac, 0xae, 0xaf, 0x74, 0x97, 0xef, 0x9a, 0x5a, 0x97, 0x7c, 0xf5, 0xcd, 0xa1, 0x19, 0xd6, 0x31, + 0xc2, 0x0b, 0x5e, 0x66, 0x9a, 0x7f, 0x96, 0x09, 0x59, 0xc5, 0x17, 0x5c, 0x39, 0x66, 0xa7, 0x29, + 0x31, 0xb9, 0x6d, 0xad, 0x4e, 0xc1, 0x90, 0xb9, 0x94, 0x02, 0xc3, 0xe0, 0x69, 0xb8, 0x44, 0x6b, + 0xa3, 0xa6, 0xab, 0x7e, 0xfe, 0xfa, 0x8f, 0x89, 0x60, 0xf5, 0x7e, 0x68, 0x62, 0xcf, 0x58, 0xa2, + 0x96, 0xca, 0xe5, 0x36, 0x23, 0xd9, 0x88, 0x6e, 0x8b, 0x17, 0x7e, 0xf3, 0xe5, 0xd7, 0x63, 0xb0, + 0x96, 0x82, 0x18, 0xf3, 0x10, 0x13, 0x09, 0xce, 0x7b, 0xe3, 0xd8, 0xb6, 0x5b, 0x6f, 0x0e, 0x13, + 0x1b, 0xd3, 0x49, 0x57, 0x8b, 0xa1, 0xf8, 0xbd, 0xda, 0xed, 0x0d, 0x9c, 0x6c, 0x32, 0x61, 0x03, + 0xdd, 0x39, 0x63, 0x9c, 0x6f, 0xe3, 0xe5, 0xc1, 0xd6, 0xdb, 0x26, 0x1d, 0xa2, 0x60, 0x7e, 0x7b, + 0xb2, 0x51, 0x80, 0x8f, 0x78, 0x89, 0x43, 0xaa, 0x9d, 0x76, 0xef, 0x1e, 0xdb, 0xd0, 0x51, 0xb4, + 0x8e, 0xed, 0x14, 0x42, 0xfb, 0x63, 0x5d, 0x21, 0x99, 0x30, 0x99, 0x05, 0x53, 0x25, 0xe8, 0xec, + 0xe7, 0xf1, 0x40, 0x8c, 0xba, 0xb6, 0x6a, 0xe0, 0xc7, 0x73, 0x68, 0x6c, 0x15, 0x4b, 0x42, 0xe3, + 0xda, 0x97, 0x0e, 0x40, 0xc5, 0xff, 0x98, 0x2b, 0xf2, 0x19, 0xca, 0x3d, 0x49, 0x72, 0x7a, 0x96, + 0xd5, 0x16, 0xd4, 0x2a, 0xf4, 0x5d, 0x1d, 0xd2, 0x1d, 0x22, 0x60, 0xe0, 0x18, 0xf7, 0x38, 0x04, + 0x01, 0x94, 0x45, 0xb2, 0x5f, 0xc0, 0x10, 0xce, 0x65, 0x62, 0x33, 0x61, 0x6d, 0x65, 0x15, 0x7d, + 0x39, 0xc0, 0xcf, 0xcb, 0x4c, 0xa2, 0x23, 0x1c, 0xa8, 0x42, 0x46, 0x99, 0x81, 0xdc, 0x28, 0xad, + 0xd6, 0xcc, 0x92, 0xdd, 0x06, 0x58, 0x02, 0x0c, 0xe1, 0x67, 0xf2, 0x4f, 0x7a, 0xe3, 0xde, 0xb9, + 0x65, 0x81, 0xb4, 0x59, 0x13, 0xfc, 0xa4, 0x12, 0x13, 0x41, 0x9f, 0xd2, 0xe2, 0x9e, 0xea, 0x87, + 0x6a, 0x95, 0xba, 0xae, 0x27, 0x4d, 0x12, 0xc4, 0x58, 0x2a, 0x4c, 0x18, 0x68, 0x6b, 0x3b, 0xd6, + 0xfa, 0xc5, 0x47, 0x0c, 0xfe, 0x40, 0x66, 0x5b, 0x0e, 0xe9, 0xe9, 0x01, 0x4f, 0x1c, 0x48, 0x52, + 0x19, 0xc8, 0x9d, 0xa3, 0xbe, 0x81, 0x04, 0xa1, 0xd8, 0x4e, 0x6f, 0x6e, 0x80, 0xcd, 0xf7, 0x38, + 0x63, 0x16, 0x1f, 0x27, 0x4e, 0x5e, 0x4a, 0xcb, 0xc8, 0x15, 0x62, 0x15, 0x9e, 0x4e, 0xbc, 0xfc, + 0xa3, 0x26, 0x85, 0x54, 0xe0, 0x56, 0xb9, 0xef, 0xc0, 0x6c, 0x42, 0x87, 0x35, 0x9a, 0x28, 0xc1, + 0x90, 0x2c, 0xa2, 0xc6, 0xbe, 0x9e, 0xbb, 0x11, 0x1b, 0x88, 0xa7, 0xea, 0x03, 0x82, 0x8b, 0xf5, + 0xb5, 0x72, 0x76, 0xb8, 0x30, 0x2d, 0x07, 0xb3, 0x2f, 0x35, 0x48, 0xf5, 0xc5, 0x6c, 0xd3, 0x30, + 0x98, 0x55, 0xe1, 0x68, 0x0d, 0x47, 0xcf, 0xbe, 0x29, 0x8f, 0xcf, 0x48, 0x7b, 0x79, 0x2d, 0xd8, + 0xbf, 0x52, 0xce, 0x1d, 0xdc, 0xb2, 0x22, 0xe6, 0x86, 0x30, 0x98, 0x50, 0xf4, 0x56, 0x53, 0x49, + 0x38, 0x5f, 0x6d, 0xce, 0xe9, 0x35, 0x2f, 0xcf, 0x44, 0x8a, 0x96, 0xe5, 0x0a, 0xd8, 0x62, 0x64, + 0x1b, 0xfe, 0x38, 0x83, 0x36, 0x60, 0xd4, 0x31, 0xa4, 0x63, 0x4a, 0xd7, 0xa0, 0x9b, 0x1a, 0xca, + 0x84, 0xaa, 0x30, 0xba, 0xea, 0xcc, 0x48, 0xb2, 0xb0, 0x51, 0xc5, 0x0e, 0xd6, 0x3b, 0x1b, 0xab, + 0x20, 0x4a, 0xd0, 0xd9, 0xc8, 0xf3, 0x19, 0x63, 0x07, 0x10, 0x7c, 0xcd, 0xa6, 0x5a, 0xa5, 0xcd, + 0x3b, 0x8e, 0x09, 0x7f, 0xf0, 0x54, 0xba, 0xc8, 0x2a, 0xbb, 0x1d, 0x0d, 0x76, 0xdd, 0xb1, 0x47, + 0xed, 0xb9, 0x41, 0x25, 0x43, 0x97, 0x2d, 0x27, 0xc0, 0x89, 0x81, 0x69, 0xfb, 0x02, 0x21, 0xd3, + 0xc6, 0x59, 0x65, 0x11, 0x42, 0xbc, 0x88, 0x98, 0xa0, 0x0a, 0xa1, 0xdc, 0xb1, 0xb7, 0x03, 0xc1, + 0x64, 0x8f, 0x95, 0xb3, 0x37, 0x67, 0x87, 0x5f, 0xe5, 0xf1, 0x93, 0x27, 0xe7, 0x12, 0x62, 0x5e, + 0x87, 0x52, 0x4b, 0x44, 0x5f, 0xe5, 0x45, 0x58, 0xc0, 0xfb, 0x06, 0xbc, 0x8a, 0xe0, 0xd4, 0xe5, + 0x9f, 0xf3, 0x2c, 0x20, 0x30, 0x64, 0xfe, 0x46, 0xf5, 0xf3, 0xda, 0x53, 0x42, 0x8f, 0x99, 0x7d, + 0xfb, 0x47, 0xb7, 0x4a, 0xbe, 0x66, 0xf6, 0xe1, 0x2e, 0x62, 0x87, 0x26, 0xce, 0x02, 0x9a, 0xe2, + 0xeb, 0xca, 0x64, 0xc4, 0xaa, 0x0d, 0xbc, 0x9b, 0x1e, 0x32, 0xc3, 0xf8, 0xec, 0xaf, 0x1b, 0xdb, + 0xff, 0x0c, 0x71, 0x69, 0xc6, 0xb2, 0xc0, 0x3a, 0x66, 0xee, 0xd2, 0xc9, 0x16, 0x4d, 0xaf, 0x24, + 0xfa, 0x65, 0x18, 0x75, 0xfb, 0x45, 0x25, 0xa6, 0x26, 0xfb, 0x66, 0x2a, 0x15, 0x9c, 0x85, 0xf4, + 0xda, 0x1d, 0x4f, 0x3b, 0xe2, 0x4d, 0x23, 0xeb, 0x8c, 0x57, 0xb1, 0xb5, 0x4c, 0x90, 0x23, 0x7f, + 0x01, 0xfa, 0x06, 0x9d, 0x35, 0x4c, 0x6a, 0xb5, 0x79, 0xb9, 0x00, 0x17, 0x46, 0x46, 0x54, 0x45, + 0x60, 0xed, 0xe8, 0x86, 0xc3, 0xde, 0x65, 0xdf, 0x5b, 0x40, 0x97, 0xcd, 0x77, 0x25, 0x41, 0xcd, + 0xf2, 0x89, 0xbf, 0xfe, 0x55, 0xa1, 0xf9, 0xf5, 0x7a, 0x18, 0x2d, 0x6c, 0xec, 0x28, 0xed, 0xd1, + 0x44, 0xa1, 0x98, 0x77, 0x73, 0x6f, 0xc0, 0x4c, 0x7f, 0x05, 0xc0, 0x9c, 0x19, 0xed, 0x90, 0x3c, + 0x56, 0xb6, 0xf4, 0x86, 0x2f, 0x60, 0xb3, 0x1b, 0x95, 0x58, 0x26, 0x40, 0xc2, 0xc0, 0xda, 0x24, + 0x26, 0xcb, 0x06, 0x26, 0x53, 0x30, 0x12, 0x35, 0x0b, 0xe5, 0x39, 0x80, 0x3a, 0xf7, 0xd5, 0xae, + 0xb8, 0xcb, 0xea, 0xf6, 0x4c, 0x3d, 0x81, 0xb4, 0x1f, 0x97, 0x88, 0x2c, 0x9f, 0x9c, 0x70, 0x70, + 0xd5, 0x34, 0xe8, 0x65, 0xb7, 0xdb, 0xb3, 0x33, 0x26, 0xcf, 0x95, 0xa3, 0x31, 0x6a, 0x90, 0x9f, + 0xde, 0xd3, 0x17, 0x8a, 0x24, 0xdc, 0xe1, 0x57, 0xb8, 0x28, 0x70, 0x79, 0x52, 0xd7, 0x9d, 0x6b, + 0x99, 0xbb, 0xf7, 0x14, 0x5e, 0xc0, 0x05, 0xff, 0xbc, 0x82, 0xc2, 0x20, 0x57, 0x6c, 0xbe, 0xbe, + 0x71, 0xf7, 0xdb, 0x24, 0xc3, 0x33, 0xe6, 0x26, 0x50, 0x9a, 0xfc, 0xd6, 0x35, 0xb7, 0x42, 0xc4, + 0x63, 0x22, 0x3d, 0x4c, 0x52, 0x1b, 0xf3, 0x6a, 0x38, 0x5c, 0x9b, 0xf5, 0x9b, 0xfb, 0x5f, 0x0b, + 0x37, 0x9a, 0xf2, 0x25, 0xd3, 0xd9, 0xa7, 0xc5, 0x02, 0x0f, 0x86, 0xaa, 0xee, 0x71, 0x49, 0xa2, + 0x22, 0xc2, 0x9d, 0x92, 0xc2, 0x3e, 0x8f, 0x26, 0x7f, 0x5c, 0x23, 0x62, 0xe4, 0xb5, 0xf5, 0x9e, + 0xea, 0x2f, 0xbc, 0xe8, 0x4b, 0x4d, 0xd1, 0xbd, 0x2e, 0x39, 0x04, 0x56, 0xfc, 0x0f, 0xd3, 0xd6, + 0x10, 0x16, 0xe5, 0x02, 0x11, 0x5c, 0xbc, 0x66, 0x90, 0xf1, 0xb7, 0xf6, 0x4f, 0x56, 0x0f, 0x87, + 0x2c, 0xa8, 0xb6, 0xa9, 0x30, 0xf6, 0x17, 0x1b, 0xda, 0x2c, 0x2a, 0x75, 0x09, 0xcc, 0x32, 0xe2, + 0x77, 0xc8, 0xd8, 0x98, 0x7b, 0xd4, 0x8a, 0x73, 0xda, 0xe2, 0x76, 0x78, 0x04, 0x82, 0xab, 0x11, + 0x71, 0xe3, 0x73, 0x79, 0x5e, 0xdb, 0x86, 0x79, 0x52, 0x1d, 0x28, 0xc1, 0x87, 0xa8, 0x2f, 0xca, + 0xbc, 0xb9, 0xba, 0x58, 0x4e, 0xb3, 0x89, 0x4d, 0x74, 0x88, 0x37, 0x36, 0xbb, 0x1d, 0x1d, 0xe8, + 0xc9, 0xd4, 0xe8, 0xa4, 0x31, 0x17, 0x56, 0xf4, 0x72, 0xc0, 0x00, 0x58, 0x1c, 0x76, 0xab, 0x2d, + 0x75, 0xe6, 0x90, 0x85, 0xbf, 0xdc, 0x57, 0x2f, 0xbe, 0xb1, 0xa9, 0x3c, 0xd1, 0xf6, 0x58, 0x80, + 0xcf, 0x43, 0x60, 0xb4, 0x1b, 0x82, 0x02, 0x90, 0x3c, 0xad, 0xfc, 0xef, 0xc4, 0xce, 0x9a, 0xec, + 0xea, 0x26, 0x57, 0xb9, 0x7e, 0xf7, 0x69, 0xa3, 0x06, 0x52, 0xc2, 0x51, 0x83, 0x8f, 0xf4, 0x0d, + 0xb7, 0xa3, 0xfc, 0xae, 0x29, 0x81, 0xcc, 0xdc, 0xbb, 0x2d, 0xed, 0x38, 0xf4, 0x40, 0x7a, 0x16, + 0x56, 0x11, 0x7f, 0x33, 0x50, 0x44, 0xc0, 0xb9, 0x77, 0x66, 0x6b, 0xce, 0x18, 0xd6, 0xdf, 0x39, + 0x9e, 0xa6, 0xa1, 0xbd, 0xed, 0x0e, 0xd7, 0x14, 0xe1, 0xb9, 0x6a, 0x51, 0x4b, 0x5c, 0x00, 0xdc, + 0xd7, 0xdb, 0x76, 0x69, 0xef, 0xfa, 0x2e, 0xcf, 0x4f, 0xa8, 0x2e, 0x59, 0x26, 0xa0, 0x55, 0x7e, + 0x9b, 0x55, 0xfc, 0x7c, 0x32, 0xff, 0xbf, 0x08, 0x90, 0xb5, 0x7a, 0x4f, 0xf2, 0x26, 0x05, 0x85, + 0xf6, 0x56, 0x7b, 0x56, 0x41, 0xdc, 0x95, 0xcf, 0x03, 0x45, 0xef, 0x78, 0x34, 0x30, 0x61, 0x9a, + 0x44, 0x8f, 0xbc, 0xb5, 0x5c, 0xf4, 0x64, 0x2c, 0x13, 0x21, 0x3c, 0xa5, 0x1b, 0xe7, 0x9c, 0x60, + 0x9b, 0x49, 0xe1, 0x34, 0x8a, 0xef, 0x72, 0xa7, 0xa9, 0x71, 0x6f, 0x32, 0x52, 0x64, 0x0a, 0xa0, + 0x4a, 0xf3, 0xa2, 0xee, 0x16, 0x1a, 0xbe, 0x93, 0x0a, 0xa2, 0xd8, 0xb0, 0x82, 0x3b, 0x4d, 0x7d, + 0x24, 0xe2, 0x09, 0xef, 0x6b, 0xdd, 0x92, 0x00, 0x6f, 0x76, 0xd1, 0x41, 0xde, 0xdb, 0xab, 0x6c, + 0x39, 0x4d, 0x26, 0x54, 0xb4, 0x56, 0xce, 0x4c, 0x19, 0x95, 0x2a, 0x51, 0xa9, 0xf1, 0xad, 0x58, + 0xf8, 0x6d, 0xeb, 0x32, 0xc2, 0x30, 0x03, 0x15, 0x0e, 0x9d, 0x76, 0x74, 0x5d, 0xe0, 0x62, 0xd9, + 0xc3, 0x83, 0xe4, 0xd5, 0x33, 0x1d, 0x7b, 0xfe, 0x6f, 0x16, 0x5c, 0xaf, 0x34, 0xe9, 0x2c, 0x20, + 0xca, 0x99, 0xac, 0x57, 0x47, 0x81, 0x0d, 0x57, 0x65, 0x33, 0x1a, 0x5b, 0x0c, 0xaa, 0x13, 0x00, + 0xf9, 0x3d, 0x02, 0x2c, 0xc1, 0x23, 0x7d, 0x55, 0x47, 0xdb, 0x8b, 0xcb, 0x50, 0xc1, 0xd2, 0x95, + 0xff, 0x0b, 0x8a, 0xb3, 0x38, 0x43, 0x51, 0xe1, 0x3b, 0x3b, 0xc3, 0x4b, 0x5e, 0xc9, 0xac, 0x0f, + 0xb3, 0x81, 0x32, 0xf1, 0x2e, 0xa2, 0x51, 0xea, 0xb2, 0x85, 0x1a, 0x48, 0xee, 0x35, 0xa0, 0x86, + 0x05, 0x14, 0x05, 0xc3, 0xf5, 0xe2, 0xa1, 0xdf, 0x47, 0xb0, 0xe2, 0x04, 0x21, 0x85, 0xbd, 0x0b, + 0x00, 0x98, 0xe4, 0xdb, 0xe1, 0x7a, 0xf7, 0xfd, 0x7a, 0x92, 0x45, 0x15, 0x57, 0xd7, 0xcf, 0x18, + 0xb7, 0xa3, 0xf2, 0xd5, 0xcf, 0x18, 0x7a, 0xe5, 0xa4, 0x4b, 0x0c, 0xe1, 0x66, 0xd9, 0x1b, 0x3f, + 0x60, 0x47, 0x90, 0xd1, 0xe9, 0xb8, 0xf5, 0xa8, 0x36, 0x1f, 0xab, 0x7d, 0x85, 0x9a, 0x57, 0xc6, + 0xdb, 0x9c, 0xf8, 0x90, 0xbf, 0xc7, 0xb7, 0xf5, 0xa3, 0x1d, 0x69, 0x6d, 0xe8, 0xda, 0x3d, 0xa6, + 0xaa, 0x38, 0x55, 0x30, 0x9d, 0x7a, 0xc0, 0x6d, 0x42, 0xeb, 0xc6, 0x97, 0xf3, 0x84, 0xa1, 0x0a, + 0x4c, 0x78, 0xc3, 0xdb, 0x9f, 0x29, 0x85, 0x08, 0x4d, 0x8f, 0xbe, 0x8e, 0xba, 0x68, 0x1a, 0x97, + 0x74, 0xa7, 0xd2, 0xec, 0xb9, 0x8b, 0xbf, 0x8c, 0xd7, 0xb6, 0x2e, 0x3d, 0x3b, 0x7d, 0xf8, 0x84, + 0x2b, 0x30, 0xe6, 0x40, 0x13, 0x53, 0xbe, 0x47, 0xd9, 0x14, 0x16, 0xdf, 0x05, 0xeb, 0xa3, 0x6c, + 0x74, 0xd4, 0xba, 0x8d, 0xf5, 0x80, 0xab, 0xc8, 0x40, 0x3c, 0xd5, 0x00, 0x47, 0x86, 0x66, 0x73, + 0x6b, 0x36, 0xc5, 0xa2, 0x81, 0x92, 0xd8, 0xfd, 0xde, 0x61, 0x34, 0xc3, 0x34, 0xaa, 0x1a, 0x40, + 0x3c, 0x95, 0x8f, 0x75, 0x2f, 0xc6, 0x22, 0xbb, 0x45, 0xfa, 0x68, 0x10, 0xd7, 0x22, 0x09, 0x59, + 0x36, 0x25, 0x45, 0x06, 0x9b, 0xa2, 0x33, 0xf9, 0x34, 0x63, 0xe2, 0x2b, 0x18, 0xa7, 0xbe, 0x25, + 0xf2, 0xe6, 0x9d, 0x99, 0x97, 0xb1, 0x0d, 0x64, 0x3a, 0x53, 0xcb, 0xe5, 0x73, 0xc6, 0x47, 0x3c, + 0x76, 0x87, 0xae, 0x74, 0x1f, 0x4f, 0x84, 0x2e, 0x4f, 0x10, 0xda, 0x4e, 0x32, 0x40, 0x71, 0xc4, + 0xd9, 0xac, 0x85, 0x4c, 0x6e, 0x10, 0x37, 0x66, 0xcd, 0x49, 0x83, 0x20, 0xa7, 0xe7, 0x47, 0x70, + 0xaf, 0x38, 0x6c, 0x95, 0x32, 0x6e, 0x7f, 0x21, 0x9e, 0x2b, 0xbd, 0x09, 0x6a, 0xe0, 0xd9, 0xdf, + 0x27, 0x1e, 0x41, 0x0b, 0x1a, 0xc3, 0x6c, 0x83, 0x9f, 0x1a, 0x57, 0x5e, 0x94, 0x72, 0xc5, 0x8d, + 0x9f, 0x61, 0xe4, 0x47, 0x56, 0xb1, 0x80, 0x32, 0x3c, 0x23, 0x4c, 0x21, 0x0d, 0xdd, 0x4e, 0x5f, + 0x61, 0x8a, 0xcf, 0xee, 0x59, 0x87, 0x36, 0xe4, 0x0a, 0x24, 0x7c, 0x03, 0xda, 0x64, 0x76, 0x3c, + 0x80, 0x04, 0x3c, 0x89, 0x91, 0x9e, 0x56, 0xba, 0x66, 0x98, 0xb2, 0xfc, 0x8d, 0x81, 0xdf, 0xf4, + 0x3c, 0x0c, 0x0c, 0x03, 0xee, 0xd9, 0xb4, 0xb0, 0x0a, 0xcf, 0x6d, 0x0b, 0xf6, 0xe7, 0xa6, 0x21, + 0x1c, 0xe7, 0x9f, 0xa5, 0x74, 0xea, 0x18, 0x3f, 0xf7, 0x2c, 0x3c, 0x09, 0x53, 0xd6, 0xcc, 0x71, + 0xd7, 0x07, 0x9d, 0x3d, 0x59, 0xb4, 0xec, 0x86, 0xe9, 0x8b, 0xa0, 0x14, 0x99, 0xf8, 0xa6, 0x9b, + 0x59, 0xe2, 0x6e, 0x73, 0x78, 0xe0, 0xf3, 0xcb, 0xce, 0x06, 0xd0, 0x1b, 0x70, 0xd8, 0x15, 0xc2, + 0xbf, 0x04, 0xe8, 0xcb, 0x31, 0x1d, 0x04, 0x9f, 0x9d, 0xf2, 0xa1, 0x60, 0x1f, 0x63, 0x49, 0x64, + 0x56, 0x3e, 0xa1, 0x64, 0xf2, 0xb0, 0xaa, 0xdc, 0x5f, 0xa3, 0x3b, 0x8d, 0x16, 0x07, 0xa1, 0xf3, + 0xec, 0xc5, 0x7f, 0xe2, 0x1c, 0xeb, 0xb7, 0x81, 0xd3, 0xdf, 0x5f, 0xee, 0xa0, 0xe1, 0x82, 0x25, + 0x7a, 0xe2, 0x3f, 0xce, 0x3b, 0x89, 0x1f, 0xbe, 0x73, 0x9e, 0xe4, 0x46, 0x11, 0x39, 0xfc, 0x6b, + 0xe6, 0x99, 0xd6, 0x98, 0x9f, 0x8f, 0x19, 0x41, 0x90, 0x5d, 0xf1, 0x85, 0x94, 0xe7, 0x13, 0x91, + 0xe3, 0x01, 0xfd, 0x41, 0x29, 0x1d, 0xcb, 0x11, 0x13, 0xcd, 0x4c, 0x92, 0x6c, 0x15, 0x7c, 0xd1, + 0xbc, 0x50, 0x68, 0x4c, 0x46, 0xe3, 0x0f, 0x25, 0xd5, 0x6c, 0x3b, 0x53, 0x0b, 0x2f, 0x1d, 0xd2, + 0x52, 0xca, 0x97, 0x29, 0x5c, 0xdf, 0x24, 0xa8, 0xc6, 0xbe, 0xd1, 0xc1, 0x14, 0x20, 0x24, 0x4f, + 0xfa, 0xd4, 0xe5, 0xb0, 0x93, 0x45, 0xe1, 0xc9, 0xf2, 0xbe, 0x0d, 0xc2, 0xd1, 0x4c, 0xab, 0x2f, + 0x85, 0xc1, 0x0b, 0x51, 0x40, 0x7c, 0xdf, 0x7f, 0x74, 0xa1, 0x3d, 0xb8, 0x4d, 0x4f, 0x26, 0x24, + 0x11, 0x61, 0x64, 0xd3, 0x0e, 0x5b, 0x29, 0x87, 0x05, 0xfe, 0xb9, 0x78, 0xde, 0xad, 0xf9, 0xe8, + 0xc4, 0x47, 0x4d, 0xfb, 0xa8, 0x54, 0x99, 0x50, 0x1d, 0xe7, 0xaf, 0x1a, 0x12, 0x20, 0x8d, 0xcd, + 0xde, 0x8e, 0xf8, 0x26, 0x65, 0x8b, + }; + unsigned char commit_0[] = { + 0x09, 0x9e, 0x56, 0x8d, 0x5b, 0x9d, 0x2a, 0xd6, 0x1f, 0xe0, 0x81, 0x21, 0xcc, 0x15, 0xb3, 0x66, + 0x6d, 0xb4, 0xbb, 0xac, 0xdd, 0x28, 0x08, 0xab, 0x21, 0x6e, 0x35, 0xac, 0xa7, 0xe0, 0x0a, 0xa8, + 0xef, + }; + + test_rangeproof_fixed_vectors_reproducible_helper(vector_0, sizeof(vector_0), commit_0, &value_r, &min_value_r, &max_value_r, message_r, &m_len_r); + CHECK(value_r == value); + CHECK(m_len_r == m_len); + CHECK(secp256k1_memcmp_var(message_r, message, m_len_r) == 0); + CHECK(min_value_r == min_value); + CHECK(max_value_r == UINT64_MAX); + memset(message_r, 0, sizeof(message_r)); + } + + /* Test min_bits = 3 */ + { + uint64_t value = 13; + size_t m_len = 128; /* maximum message length with min_bits = 3 */ + + /* Uncomment this to recreate test vector */ + /* uint64_t min_value = 1; */ + /* int min_bits = 3; */ + /* int exp = 1; */ + /* unsigned char proof[267]; */ + /* size_t p_len = sizeof(proof); */ + /* secp256k1_pedersen_commitment pc; */ + /* CHECK(secp256k1_pedersen_commit(ctx, &pc, vector_blind, value, secp256k1_generator_h)); */ + /* CHECK(secp256k1_rangeproof_sign(ctx, proof, &p_len, min_value, &pc, vector_blind, vector_nonce, exp, min_bits, value, message, m_len, NULL, 0, secp256k1_generator_h)); */ + /* CHECK(p_len == sizeof(proof)); */ + /* print_vector(1, proof, p_len, &pc); */ + + unsigned char vector_1[] = { + 0x61, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0xcb, 0xdc, 0xbe, 0x42, 0xe6, + 0x44, 0x1e, 0xc4, 0x63, 0x9d, 0xb1, 0x93, 0x7b, 0x49, 0xdc, 0xd5, 0x6e, 0x55, 0xdd, 0x3b, 0x1e, + 0x41, 0x1c, 0x0e, 0xd7, 0x47, 0xd7, 0xf0, 0x26, 0xf7, 0xe4, 0x36, 0xbd, 0x51, 0xb9, 0x77, 0x90, + 0x33, 0xdd, 0x64, 0xe7, 0x47, 0x38, 0x49, 0x29, 0x12, 0xa8, 0x12, 0x79, 0xbc, 0x62, 0xea, 0xf9, + 0xb5, 0x51, 0x8f, 0x51, 0xea, 0x28, 0x5d, 0x30, 0x9f, 0x30, 0xd5, 0x93, 0x31, 0x56, 0x61, 0x01, + 0xd7, 0x7f, 0xa4, 0xec, 0xfc, 0xe5, 0x83, 0x52, 0x5a, 0xe0, 0x80, 0x76, 0x40, 0xb8, 0x8d, 0x67, + 0x23, 0x46, 0x8c, 0xb8, 0x74, 0x2a, 0x20, 0x12, 0x86, 0x4d, 0xd8, 0x8c, 0x23, 0x73, 0x2f, 0xbe, + 0x99, 0xa5, 0xd5, 0x8c, 0x11, 0xc7, 0xb2, 0xf9, 0xd3, 0x7c, 0x88, 0x16, 0x4d, 0x21, 0x80, 0x10, + 0x70, 0xfc, 0x1f, 0x9b, 0x0b, 0x5e, 0xbe, 0xe3, 0x65, 0xe2, 0x4f, 0xbd, 0x1d, 0xb0, 0x64, 0x0a, + 0xc5, 0xe0, 0x94, 0x8b, 0x49, 0xf7, 0xc4, 0x88, 0x5e, 0xc0, 0x2d, 0xbb, 0x98, 0x60, 0x5f, 0xd2, + 0x7a, 0x9a, 0xff, 0x9e, 0x1c, 0x1f, 0x45, 0x34, 0x08, 0x96, 0xa9, 0xd3, 0xa5, 0x4d, 0x95, 0x9c, + 0x1f, 0xe6, 0xe5, 0xdc, 0x32, 0xbb, 0x18, 0x4a, 0x76, 0x22, 0xe9, 0x75, 0x1f, 0x45, 0x6b, 0x81, + 0x70, 0x4a, 0xc8, 0x00, 0x72, 0x7a, 0xc8, 0xee, 0xed, 0xc5, 0x19, 0x8f, 0xec, 0x7b, 0x4b, 0xfd, + 0x7f, 0xc8, 0x51, 0xda, 0x28, 0x0e, 0x95, 0xd3, 0xc6, 0xc1, 0x29, 0x28, 0x3f, 0xd8, 0x3d, 0x41, + 0xde, 0xdf, 0xfc, 0x2b, 0x71, 0x3a, 0xdb, 0x78, 0xa4, 0x0e, 0x50, 0xb8, 0xf9, 0xae, 0xdb, 0x7b, + 0xb1, 0x31, 0x81, 0xc2, 0xf2, 0xb5, 0x01, 0x64, 0x8e, 0x86, 0xe2, 0x8b, 0x67, 0x13, 0xec, 0x7e, + 0xf5, 0xad, 0x9d, 0x57, 0x2b, 0x5d, 0x0c, 0x94, 0xa9, 0x89, 0x92, + }; + unsigned char commit_1[] = { + 0x09, 0xe5, 0xb3, 0x27, 0x82, 0x88, 0xeb, 0x21, 0xcd, 0xb2, 0x56, 0x37, 0x61, 0x84, 0xce, 0xc1, + 0x66, 0x16, 0x2e, 0x44, 0xc8, 0x65, 0x8e, 0xe6, 0x3a, 0x1a, 0x57, 0x2c, 0xb9, 0x6c, 0x07, 0x85, + 0xf0, + }; + + test_rangeproof_fixed_vectors_reproducible_helper(vector_1, sizeof(vector_1), commit_1, &value_r, &min_value_r, &max_value_r, message_r, &m_len_r); + CHECK(value_r == value); + CHECK(m_len_r == m_len); + CHECK(secp256k1_memcmp_var(message_r, message, m_len_r) == 0); + CHECK(min_value_r == 3); + CHECK(max_value_r == 73); + memset(message_r, 0, sizeof(message_r)); + } + + /* Test large min_value */ + { + uint64_t value = INT64_MAX; + size_t m_len = 0; /* maximum message length with min_bits = 3 */ + + /* Uncomment this to recreate test vector */ + /* uint64_t min_value = INT64_MAX-1; */ + /* int min_bits = 1; */ + /* int exp = 0; */ + /* unsigned char proof[106]; */ + /* size_t p_len = sizeof(proof); */ + /* secp256k1_pedersen_commitment pc; */ + /* CHECK(secp256k1_pedersen_commit(ctx, &pc, vector_blind, value, secp256k1_generator_h)); */ + /* CHECK(secp256k1_rangeproof_sign(ctx, proof, &p_len, min_value, &pc, vector_blind, vector_nonce, exp, min_bits, value, message, m_len, NULL, 0, secp256k1_generator_h)); */ + /* CHECK(p_len == sizeof(proof)); */ + /* print_vector(2, proof, p_len, &pc); */ + + unsigned char vector_2[] = { + 0x60, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x81, 0xd8, 0x21, 0x12, 0x4d, 0xa4, + 0x84, 0xdd, 0x2c, 0xd1, 0x04, 0xe7, 0x08, 0x9a, 0xd3, 0x6f, 0xa5, 0xd8, 0xfc, 0x52, 0x4c, 0xba, + 0xf0, 0x83, 0xeb, 0x76, 0x9f, 0x1c, 0x03, 0xe3, 0xcf, 0x23, 0x1e, 0x40, 0x18, 0xc6, 0x6d, 0xf9, + 0x25, 0x56, 0x80, 0x3c, 0x83, 0xdd, 0x58, 0x36, 0x43, 0xe3, 0x56, 0xa0, 0xb7, 0xf0, 0x0e, 0xf9, + 0xe2, 0x8b, 0x82, 0x5a, 0x77, 0xa7, 0xbe, 0x36, 0x98, 0x10, 0x99, 0x2e, 0xaa, 0x21, 0x24, 0xe6, + 0x78, 0xa8, 0xcc, 0xc7, 0x06, 0x1c, 0x06, 0xb0, 0x03, 0x87, 0x86, 0x89, 0xce, 0x85, 0x88, 0xea, + 0xa1, 0x9d, 0x4d, 0xfd, 0x8d, 0x65, 0xbd, 0xa9, 0xd0, 0x0f, + }; + unsigned char commit_2[] = { + 0x09, 0x2a, 0x74, 0xa1, 0x9c, 0xee, 0xcb, 0x6a, 0xd1, 0xa7, 0x97, 0xbe, 0x97, 0xe7, 0xb6, 0x37, + 0x90, 0x96, 0xc2, 0x5a, 0xe5, 0xfc, 0xed, 0x91, 0xff, 0x4c, 0x67, 0x07, 0x96, 0x1d, 0x2a, 0xb3, + 0x70, + }; + + test_rangeproof_fixed_vectors_reproducible_helper(vector_2, sizeof(vector_2), commit_2, &value_r, &min_value_r, &max_value_r, message_r, &m_len_r); + CHECK(value_r == value); + CHECK(m_len_r == m_len); + CHECK(secp256k1_memcmp_var(message_r, message, m_len_r) == 0); + CHECK(min_value_r == INT64_MAX-1); + CHECK(max_value_r == INT64_MAX); + memset(message_r, 0, sizeof(message_r)); + } } void test_pedersen_commitment_fixed_vector(void) { @@ -685,7 +1470,7 @@ void test_pedersen_commitment_fixed_vector(void) { CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, two_g)); CHECK(secp256k1_pedersen_commitment_serialize(ctx, result, &parse)); - CHECK(memcmp(two_g, result, 33) == 0); + CHECK(secp256k1_memcmp_var(two_g, result, 33) == 0); result[0] = 0x08; CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, result)); @@ -696,7 +1481,13 @@ 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_rangeproof_fixed_vectors_reproducible(); test_pedersen_commitment_fixed_vector(); for (i = 0; i < count / 2 + 1; i++) { test_pedersen(); diff --git a/src/modules/surjection/main_impl.h b/src/modules/surjection/main_impl.h index b8f145e5f..6146c3963 100644 --- a/src/modules/surjection/main_impl.h +++ b/src/modules/surjection/main_impl.h @@ -275,7 +275,6 @@ 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 */ @@ -333,12 +332,7 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s 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) { + if (secp256k1_borromean_sign(&ctx->ecmult_gen_ctx, &proof->data[0], borromean_s, ring_pubkeys, &blinding_key, rsizes, indices, 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 a37e16ffe..f3e3e2444 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_gej pubs[MAX_KEYS]; secp256k1_scalar s[MAX_KEYS]; - secp256k1_scalar sec, non; + secp256k1_scalar sec; unsigned char msg32[32]; int ret; @@ -47,19 +47,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 = secp256k1_nonce_function_default(nonce32, msg32, seckey32, NULL, NULL, 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; @@ -85,12 +73,11 @@ int secp256k1_whitelist_sign(const secp256k1_context* ctx, secp256k1_whitelist_s /* Actually sign */ if (ret) { 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, &index, 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; }