From 87373f51451bed948340d6885111d04051cbfc02 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 27 Aug 2022 14:55:38 +0000 Subject: [PATCH 01/18] MOVE ONLY: move Pedersen commitment stuff to generator module from rangeproof module You can verify this commit with `git diff --color-moved=zebra` --- include/secp256k1_generator.h | 148 ++++++++++++ include/secp256k1_rangeproof.h | 148 ------------ src/modules/generator/Makefile.am.include | 2 + src/modules/generator/main_impl.h | 219 +++++++++++++++++ .../{rangeproof => generator}/pedersen.h | 0 .../{rangeproof => generator}/pedersen_impl.h | 0 src/modules/generator/tests_impl.h | 163 +++++++++++++ src/modules/rangeproof/Makefile.am.include | 2 - src/modules/rangeproof/main_impl.h | 222 +----------------- src/modules/rangeproof/rangeproof_impl.h | 6 +- src/modules/rangeproof/tests_impl.h | 142 ----------- src/secp256k1.c | 2 - 12 files changed, 538 insertions(+), 516 deletions(-) rename src/modules/{rangeproof => generator}/pedersen.h (100%) rename src/modules/{rangeproof => generator}/pedersen_impl.h (100%) diff --git a/include/secp256k1_generator.h b/include/secp256k1_generator.h index cb55af91c..5479fc819 100644 --- a/include/secp256k1_generator.h +++ b/include/secp256k1_generator.h @@ -21,6 +21,11 @@ typedef struct { unsigned char data[64]; } secp256k1_generator; +/** + * Static constant generator 'h' maintained for historical reasons. + */ +SECP256K1_API extern const secp256k1_generator *secp256k1_generator_h; + /** Parse a 33-byte generator byte sequence into a generator object. * * Returns: 1 if input contains a valid generator. @@ -86,6 +91,149 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate_blin const unsigned char *blind32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); +/** Opaque data structure that stores a Pedersen commitment + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use secp256k1_pedersen_commitment_serialize and + * secp256k1_pedersen_commitment_parse. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_pedersen_commitment; + +/** Parse a 33-byte commitment into a commitment object. + * + * Returns: 1 if input contains a valid commitment. + * Args: ctx: a secp256k1 context object. + * Out: commit: pointer to the output commitment object + * In: input: pointer to a 33-byte serialized commitment key + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commitment_parse( + const secp256k1_context* ctx, + secp256k1_pedersen_commitment* commit, + const unsigned char *input +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a commitment object into a serialized byte sequence. + * + * Returns: 1 always. + * Args: ctx: a secp256k1 context object. + * Out: output: a pointer to a 33-byte byte array + * In: commit: a pointer to a secp256k1_pedersen_commitment containing an + * initialized commitment + */ +SECP256K1_API int secp256k1_pedersen_commitment_serialize( + const secp256k1_context* ctx, + unsigned char *output, + const secp256k1_pedersen_commitment* commit +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Generate a pedersen commitment. + * Returns 1: Commitment successfully created. + * 0: Error. The blinding factor is larger than the group order + * (probability for random 32 byte number < 2^-127) or results in the + * point at infinity. Retry with a different factor. + * In: ctx: pointer to a context object, initialized for signing and Pedersen commitment (cannot be NULL) + * blind: pointer to a 32-byte blinding factor (cannot be NULL) + * value: unsigned 64-bit integer value to commit to. + * gen: additional generator 'h' + * Out: commit: pointer to the commitment (cannot be NULL) + * + * Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit( + const secp256k1_context* ctx, + secp256k1_pedersen_commitment *commit, + const unsigned char *blind, + uint64_t value, + const secp256k1_generator *gen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); + +/** Computes the sum of multiple positive and negative blinding factors. + * Returns 1: Sum successfully computed. + * 0: Error. A blinding factor is larger than the group order + * (probability for random 32 byte number < 2^-127). Retry with + * different factors. + * In: ctx: pointer to a context object (cannot be NULL) + * blinds: pointer to pointers to 32-byte character arrays for blinding factors. (cannot be NULL) + * n: number of factors pointed to by blinds. + * npositive: how many of the initial factors should be treated with a positive sign. + * Out: blind_out: pointer to a 32-byte array for the sum (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum( + const secp256k1_context* ctx, + unsigned char *blind_out, + const unsigned char * const *blinds, + size_t n, + size_t npositive +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Verify a tally of pedersen commitments + * Returns 1: commitments successfully sum to zero. + * 0: Commitments do not sum to zero or other error. + * In: ctx: pointer to a context object (cannot be NULL) + * commits: pointer to array of pointers to the commitments. (cannot be NULL if pcnt is non-zero) + * pcnt: number of commitments pointed to by commits. + * ncommits: pointer to array of pointers to the negative commitments. (cannot be NULL if ncnt is non-zero) + * ncnt: number of commitments pointed to by ncommits. + * + * This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) == 0. + * + * A pedersen commitment is xG + vA where G and A are generators for the secp256k1 group and x is a blinding factor, + * while v is the committed value. For a collection of commitments to sum to zero, for each distinct generator + * A all blinding factors and all values must sum to zero. + * + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally( + const secp256k1_context* ctx, + const secp256k1_pedersen_commitment * const* commits, + size_t pcnt, + const secp256k1_pedersen_commitment * const* ncommits, + size_t ncnt +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); + +/** Sets the final Pedersen blinding factor correctly when the generators themselves + * have blinding factors. + * + * Consider a generator of the form A' = A + rG, where A is the "real" generator + * but A' is the generator provided to verifiers. Then a Pedersen commitment + * P = vA' + r'G really has the form vA + (vr + r')G. To get all these (vr + r') + * to sum to zero for multiple commitments, we take three arrays consisting of + * the `v`s, `r`s, and `r'`s, respectively called `value`s, `generator_blind`s + * and `blinding_factor`s, and sum them. + * + * The function then subtracts the sum of all (vr + r') from the last element + * of the `blinding_factor` array, setting the total sum to zero. + * + * Returns 1: Blinding factor successfully computed. + * 0: Error. A blinding_factor or generator_blind are larger than the group + * order (probability for random 32 byte number < 2^-127). Retry with + * different values. + * + * In: ctx: pointer to a context object + * value: array of asset values, `v` in the above paragraph. + * May not be NULL unless `n_total` is 0. + * generator_blind: array of asset blinding factors, `r` in the above paragraph + * May not be NULL unless `n_total` is 0. + * n_total: Total size of the above arrays + * n_inputs: How many of the initial array elements represent commitments that + * will be negated in the final sum + * In/Out: blinding_factor: array of commitment blinding factors, `r'` in the above paragraph + * May not be NULL unless `n_total` is 0. + * the last value will be modified to get the total sum to zero. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_generator_blind_sum( + const secp256k1_context* ctx, + const uint64_t *value, + const unsigned char* const* generator_blind, + unsigned char* const* blinding_factor, + size_t n_total, + size_t n_inputs +); + # ifdef __cplusplus } # endif diff --git a/include/secp256k1_rangeproof.h b/include/secp256k1_rangeproof.h index 9bb014545..2d86ab067 100644 --- a/include/secp256k1_rangeproof.h +++ b/include/secp256k1_rangeproof.h @@ -19,154 +19,6 @@ extern "C" { */ #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 - * guaranteed to be portable between different platforms or versions. It is - * however guaranteed to be 64 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage, transmission, or - * comparison, use secp256k1_pedersen_commitment_serialize and - * secp256k1_pedersen_commitment_parse. - */ -typedef struct { - unsigned char data[64]; -} secp256k1_pedersen_commitment; - -/** - * Static constant generator 'h' maintained for historical reasons. - */ -SECP256K1_API extern const secp256k1_generator *secp256k1_generator_h; - -/** Parse a 33-byte commitment into a commitment object. - * - * Returns: 1 if input contains a valid commitment. - * Args: ctx: a secp256k1 context object. - * Out: commit: pointer to the output commitment object - * In: input: pointer to a 33-byte serialized commitment key - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commitment_parse( - const secp256k1_context* ctx, - secp256k1_pedersen_commitment* commit, - const unsigned char *input -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize a commitment object into a serialized byte sequence. - * - * Returns: 1 always. - * Args: ctx: a secp256k1 context object. - * Out: output: a pointer to a 33-byte byte array - * In: commit: a pointer to a secp256k1_pedersen_commitment containing an - * initialized commitment - */ -SECP256K1_API int secp256k1_pedersen_commitment_serialize( - const secp256k1_context* ctx, - unsigned char *output, - const secp256k1_pedersen_commitment* commit -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Generate a pedersen commitment. - * Returns 1: Commitment successfully created. - * 0: Error. The blinding factor is larger than the group order - * (probability for random 32 byte number < 2^-127) or results in the - * point at infinity. Retry with a different factor. - * In: ctx: pointer to a context object, initialized for signing and Pedersen commitment (cannot be NULL) - * blind: pointer to a 32-byte blinding factor (cannot be NULL) - * value: unsigned 64-bit integer value to commit to. - * gen: additional generator 'h' - * Out: commit: pointer to the commitment (cannot be NULL) - * - * Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit( - const secp256k1_context* ctx, - secp256k1_pedersen_commitment *commit, - const unsigned char *blind, - uint64_t value, - const secp256k1_generator *gen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); - -/** Computes the sum of multiple positive and negative blinding factors. - * Returns 1: Sum successfully computed. - * 0: Error. A blinding factor is larger than the group order - * (probability for random 32 byte number < 2^-127). Retry with - * different factors. - * In: ctx: pointer to a context object (cannot be NULL) - * blinds: pointer to pointers to 32-byte character arrays for blinding factors. (cannot be NULL) - * n: number of factors pointed to by blinds. - * npositive: how many of the initial factors should be treated with a positive sign. - * Out: blind_out: pointer to a 32-byte array for the sum (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum( - const secp256k1_context* ctx, - unsigned char *blind_out, - const unsigned char * const *blinds, - size_t n, - size_t npositive -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Verify a tally of pedersen commitments - * Returns 1: commitments successfully sum to zero. - * 0: Commitments do not sum to zero or other error. - * In: ctx: pointer to a context object (cannot be NULL) - * commits: pointer to array of pointers to the commitments. (cannot be NULL if pcnt is non-zero) - * pcnt: number of commitments pointed to by commits. - * ncommits: pointer to array of pointers to the negative commitments. (cannot be NULL if ncnt is non-zero) - * ncnt: number of commitments pointed to by ncommits. - * - * This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) == 0. - * - * A pedersen commitment is xG + vA where G and A are generators for the secp256k1 group and x is a blinding factor, - * while v is the committed value. For a collection of commitments to sum to zero, for each distinct generator - * A all blinding factors and all values must sum to zero. - * - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally( - const secp256k1_context* ctx, - const secp256k1_pedersen_commitment * const* commits, - size_t pcnt, - const secp256k1_pedersen_commitment * const* ncommits, - size_t ncnt -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); - -/** Sets the final Pedersen blinding factor correctly when the generators themselves - * have blinding factors. - * - * Consider a generator of the form A' = A + rG, where A is the "real" generator - * but A' is the generator provided to verifiers. Then a Pedersen commitment - * P = vA' + r'G really has the form vA + (vr + r')G. To get all these (vr + r') - * to sum to zero for multiple commitments, we take three arrays consisting of - * the `v`s, `r`s, and `r'`s, respectively called `value`s, `generator_blind`s - * and `blinding_factor`s, and sum them. - * - * The function then subtracts the sum of all (vr + r') from the last element - * of the `blinding_factor` array, setting the total sum to zero. - * - * Returns 1: Blinding factor successfully computed. - * 0: Error. A blinding_factor or generator_blind are larger than the group - * order (probability for random 32 byte number < 2^-127). Retry with - * different values. - * - * In: ctx: pointer to a context object - * value: array of asset values, `v` in the above paragraph. - * May not be NULL unless `n_total` is 0. - * generator_blind: array of asset blinding factors, `r` in the above paragraph - * May not be NULL unless `n_total` is 0. - * n_total: Total size of the above arrays - * n_inputs: How many of the initial array elements represent commitments that - * will be negated in the final sum - * In/Out: blinding_factor: array of commitment blinding factors, `r'` in the above paragraph - * May not be NULL unless `n_total` is 0. - * the last value will be modified to get the total sum to zero. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_generator_blind_sum( - const secp256k1_context* ctx, - const uint64_t *value, - const unsigned char* const* generator_blind, - unsigned char* const* blinding_factor, - size_t n_total, - size_t n_inputs -); - /** Verify a proof that a committed value is within a range. * Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs. * 0: Proof failed or other error. diff --git a/src/modules/generator/Makefile.am.include b/src/modules/generator/Makefile.am.include index 69933e999..4119966cc 100644 --- a/src/modules/generator/Makefile.am.include +++ b/src/modules/generator/Makefile.am.include @@ -1,4 +1,6 @@ include_HEADERS += include/secp256k1_generator.h +noinst_HEADERS += src/modules/generator/pedersen.h +noinst_HEADERS += src/modules/generator/pedersen_impl.h noinst_HEADERS += src/modules/generator/main_impl.h noinst_HEADERS += src/modules/generator/tests_impl.h if USE_BENCHMARK diff --git a/src/modules/generator/main_impl.h b/src/modules/generator/main_impl.h index c915c791f..c9f6ec8b0 100644 --- a/src/modules/generator/main_impl.h +++ b/src/modules/generator/main_impl.h @@ -14,6 +14,29 @@ #include "../../hash.h" #include "../../scalar.h" +#include "modules/generator/pedersen_impl.h" + +/** Alternative generator for secp256k1. + * This is the sha256 of 'g' after standard encoding (without compression), + * which happens to be a point on the curve. More precisely, the generator is + * derived by running the following script with the sage mathematics software. + + import hashlib + F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) + G = '0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8' + H = EllipticCurve ([F (0), F (7)]).lift_x(F(int(hashlib.sha256(G.decode('hex')).hexdigest(),16))) + print('%x %x' % H.xy()) + */ +static const secp256k1_generator secp256k1_generator_h_internal = {{ + 0x50, 0x92, 0x9b, 0x74, 0xc1, 0xa0, 0x49, 0x54, 0xb7, 0x8b, 0x4b, 0x60, 0x35, 0xe9, 0x7a, 0x5e, + 0x07, 0x8a, 0x5a, 0x0f, 0x28, 0xec, 0x96, 0xd5, 0x47, 0xbf, 0xee, 0x9a, 0xce, 0x80, 0x3a, 0xc0, + 0x31, 0xd3, 0xc6, 0x86, 0x39, 0x73, 0x92, 0x6e, 0x04, 0x9e, 0x63, 0x7c, 0xb1, 0xb5, 0xf4, 0x0a, + 0x36, 0xda, 0xc2, 0x8a, 0xf1, 0x76, 0x69, 0x68, 0xc3, 0x0c, 0x23, 0x13, 0xf3, 0xa3, 0x89, 0x04 +}}; + +const secp256k1_generator *secp256k1_generator_h = &secp256k1_generator_h_internal; + + static void secp256k1_generator_load(secp256k1_ge* ge, const secp256k1_generator* gen) { int succeed; succeed = secp256k1_fe_set_b32(&ge->x, &gen->data[0]); @@ -219,4 +242,200 @@ int secp256k1_generator_generate_blinded(const secp256k1_context* ctx, secp256k1 return secp256k1_generator_generate_internal(ctx, gen, key32, blind32); } +static void secp256k1_pedersen_commitment_load(secp256k1_ge* ge, const secp256k1_pedersen_commitment* commit) { + secp256k1_fe fe; + secp256k1_fe_set_b32(&fe, &commit->data[1]); + secp256k1_ge_set_xquad(ge, &fe); + if (commit->data[0] & 1) { + secp256k1_ge_neg(ge, ge); + } +} + +static void secp256k1_pedersen_commitment_save(secp256k1_pedersen_commitment* commit, secp256k1_ge* ge) { + secp256k1_fe_normalize(&ge->x); + secp256k1_fe_get_b32(&commit->data[1], &ge->x); + commit->data[0] = 9 ^ secp256k1_fe_is_quad_var(&ge->y); +} + +int secp256k1_pedersen_commitment_parse(const secp256k1_context* ctx, secp256k1_pedersen_commitment* commit, const unsigned char *input) { + secp256k1_fe x; + secp256k1_ge ge; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(commit != NULL); + ARG_CHECK(input != NULL); + (void) ctx; + + if ((input[0] & 0xFE) != 8 || + !secp256k1_fe_set_b32(&x, &input[1]) || + !secp256k1_ge_set_xquad(&ge, &x)) { + return 0; + } + if (input[0] & 1) { + secp256k1_ge_neg(&ge, &ge); + } + secp256k1_pedersen_commitment_save(commit, &ge); + return 1; +} + +int secp256k1_pedersen_commitment_serialize(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pedersen_commitment* commit) { + secp256k1_ge ge; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(commit != NULL); + + secp256k1_pedersen_commitment_load(&ge, commit); + + output[0] = 9 ^ secp256k1_fe_is_quad_var(&ge.y); + secp256k1_fe_normalize_var(&ge.x); + secp256k1_fe_get_b32(&output[1], &ge.x); + return 1; +} + +/* Generates a pedersen commitment: *commit = blind * G + value * G2. The blinding factor is 32 bytes.*/ +int secp256k1_pedersen_commit(const secp256k1_context* ctx, secp256k1_pedersen_commitment *commit, const unsigned char *blind, uint64_t value, const secp256k1_generator* gen) { + secp256k1_ge genp; + secp256k1_gej rj; + secp256k1_ge r; + secp256k1_scalar sec; + int overflow; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(commit != NULL); + ARG_CHECK(blind != NULL); + ARG_CHECK(gen != NULL); + secp256k1_generator_load(&genp, gen); + secp256k1_scalar_set_b32(&sec, blind, &overflow); + if (!overflow) { + secp256k1_pedersen_ecmult(&ctx->ecmult_gen_ctx, &rj, &sec, value, &genp); + if (!secp256k1_gej_is_infinity(&rj)) { + secp256k1_ge_set_gej(&r, &rj); + secp256k1_pedersen_commitment_save(commit, &r); + ret = 1; + } + secp256k1_gej_clear(&rj); + secp256k1_ge_clear(&r); + } + secp256k1_scalar_clear(&sec); + return ret; +} + +/** Takes a list of n pointers to 32 byte blinding values, the first negs of which are treated with positive sign and the rest + * negative, then calculates an additional blinding value that adds to zero. + */ +int secp256k1_pedersen_blind_sum(const secp256k1_context* ctx, unsigned char *blind_out, const unsigned char * const *blinds, size_t n, size_t npositive) { + secp256k1_scalar acc; + secp256k1_scalar x; + size_t i; + int overflow; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(blind_out != NULL); + ARG_CHECK(blinds != NULL); + ARG_CHECK(npositive <= n); + (void) ctx; + secp256k1_scalar_set_int(&acc, 0); + for (i = 0; i < n; i++) { + secp256k1_scalar_set_b32(&x, blinds[i], &overflow); + if (overflow) { + return 0; + } + if (i >= npositive) { + secp256k1_scalar_negate(&x, &x); + } + secp256k1_scalar_add(&acc, &acc, &x); + } + secp256k1_scalar_get_b32(blind_out, &acc); + secp256k1_scalar_clear(&acc); + secp256k1_scalar_clear(&x); + return 1; +} + +/* Takes two lists of commitments and sums the first set and subtracts the second and verifies that they sum to excess. */ +int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const secp256k1_pedersen_commitment * const* commits, size_t pcnt, const secp256k1_pedersen_commitment * const* ncommits, size_t ncnt) { + secp256k1_gej accj; + secp256k1_ge add; + size_t i; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(!pcnt || (commits != NULL)); + ARG_CHECK(!ncnt || (ncommits != NULL)); + (void) ctx; + secp256k1_gej_set_infinity(&accj); + for (i = 0; i < ncnt; i++) { + secp256k1_pedersen_commitment_load(&add, ncommits[i]); + secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL); + } + secp256k1_gej_neg(&accj, &accj); + for (i = 0; i < pcnt; i++) { + secp256k1_pedersen_commitment_load(&add, commits[i]); + secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL); + } + return secp256k1_gej_is_infinity(&accj); +} + +int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, const uint64_t *value, const unsigned char* const* generator_blind, unsigned char* const* blinding_factor, size_t n_total, size_t n_inputs) { + secp256k1_scalar sum; + secp256k1_scalar tmp; + size_t i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(n_total == 0 || value != NULL); + ARG_CHECK(n_total == 0 || generator_blind != NULL); + ARG_CHECK(n_total == 0 || blinding_factor != NULL); + ARG_CHECK(n_total > n_inputs); + (void) ctx; + + if (n_total == 0) { + return 1; + } + + secp256k1_scalar_set_int(&sum, 0); + + /* Here, n_total > 0. Thus the loop runs at least once. + Thus we may use a do-while loop, which checks the loop + condition only at the end. + + The do-while loop helps GCC prove that the loop runs at least + once and suppresses a -Wmaybe-uninitialized warning. */ + i = 0; + do { + int overflow = 0; + secp256k1_scalar addend; + secp256k1_scalar_set_u64(&addend, value[i]); /* s = v */ + + secp256k1_scalar_set_b32(&tmp, generator_blind[i], &overflow); + if (overflow == 1) { + secp256k1_scalar_clear(&tmp); + secp256k1_scalar_clear(&addend); + secp256k1_scalar_clear(&sum); + return 0; + } + secp256k1_scalar_mul(&addend, &addend, &tmp); /* s = vr */ + + secp256k1_scalar_set_b32(&tmp, blinding_factor[i], &overflow); + if (overflow == 1) { + secp256k1_scalar_clear(&tmp); + secp256k1_scalar_clear(&addend); + secp256k1_scalar_clear(&sum); + return 0; + } + secp256k1_scalar_add(&addend, &addend, &tmp); /* s = vr + r' */ + secp256k1_scalar_cond_negate(&addend, i < n_inputs); /* s is negated if it's an input */ + secp256k1_scalar_add(&sum, &sum, &addend); /* sum += s */ + secp256k1_scalar_clear(&addend); + + i++; + } while (i < n_total); + + /* Right now tmp has the last pedersen blinding factor. Subtract the sum from it. */ + secp256k1_scalar_negate(&sum, &sum); + secp256k1_scalar_add(&tmp, &tmp, &sum); + secp256k1_scalar_get_b32(blinding_factor[n_total - 1], &tmp); + + secp256k1_scalar_clear(&tmp); + secp256k1_scalar_clear(&sum); + return 1; +} + #endif diff --git a/src/modules/rangeproof/pedersen.h b/src/modules/generator/pedersen.h similarity index 100% rename from src/modules/rangeproof/pedersen.h rename to src/modules/generator/pedersen.h diff --git a/src/modules/rangeproof/pedersen_impl.h b/src/modules/generator/pedersen_impl.h similarity index 100% rename from src/modules/rangeproof/pedersen_impl.h rename to src/modules/generator/pedersen_impl.h diff --git a/src/modules/generator/tests_impl.h b/src/modules/generator/tests_impl.h index 9f36f83de..b49ecae9a 100644 --- a/src/modules/generator/tests_impl.h +++ b/src/modules/generator/tests_impl.h @@ -223,11 +223,174 @@ void test_generator_fixed_vector(void) { CHECK(!secp256k1_generator_parse(ctx, &parse, result)); } +static void test_pedersen_api(void) { + secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_no_precomp); + secp256k1_pedersen_commitment commit; + const secp256k1_pedersen_commitment *commit_ptr = &commit; + unsigned char blind[32]; + unsigned char blind_out[32]; + const unsigned char *blind_ptr = blind; + unsigned char *blind_out_ptr = blind_out; + uint64_t val = secp256k1_testrand32(); + int32_t ecount = 0; + + secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); + + secp256k1_testrand256(blind); + CHECK(secp256k1_pedersen_commit(none, &commit, blind, val, secp256k1_generator_h) != 0); + CHECK(secp256k1_pedersen_commit(vrfy, &commit, blind, val, secp256k1_generator_h) != 0); + CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0); + CHECK(ecount == 0); + CHECK(secp256k1_pedersen_commit(sttc, &commit, blind, val, secp256k1_generator_h) == 0); + CHECK(ecount == 1); + + CHECK(secp256k1_pedersen_commit(sign, NULL, blind, val, secp256k1_generator_h) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_pedersen_commit(sign, &commit, NULL, val, secp256k1_generator_h) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, NULL) == 0); + CHECK(ecount == 4); + + CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 1, 1) != 0); + CHECK(ecount == 4); + CHECK(secp256k1_pedersen_blind_sum(none, NULL, &blind_ptr, 1, 1) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_pedersen_blind_sum(none, blind_out, NULL, 1, 1) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 1) == 0); + CHECK(ecount == 7); + CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 0) != 0); + CHECK(ecount == 7); + + CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0); + CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, &commit_ptr, 1) != 0); + CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, &commit_ptr, 1) == 0); + CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 0) == 0); + CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, NULL, 0) != 0); + CHECK(ecount == 7); + CHECK(secp256k1_pedersen_verify_tally(none, NULL, 1, &commit_ptr, 1) == 0); + CHECK(ecount == 8); + CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 1) == 0); + CHECK(ecount == 9); + + CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 0) != 0); + CHECK(ecount == 9); + CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 1) == 0); + CHECK(ecount == 10); + CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 0, 0) == 0); + CHECK(ecount == 11); + CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, NULL, &blind_ptr, &blind_out_ptr, 1, 0) == 0); + CHECK(ecount == 12); + CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, NULL, &blind_out_ptr, 1, 0) == 0); + CHECK(ecount == 13); + CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, NULL, 1, 0) == 0); + CHECK(ecount == 14); + + secp256k1_context_destroy(none); + secp256k1_context_destroy(sign); + secp256k1_context_destroy(vrfy); + secp256k1_context_destroy(sttc); +} + +static void test_pedersen(void) { + secp256k1_pedersen_commitment commits[19]; + const secp256k1_pedersen_commitment *cptr[19]; + unsigned char blinds[32*19]; + const unsigned char *bptr[19]; + secp256k1_scalar s; + uint64_t values[19]; + int64_t totalv; + int i; + int inputs; + int outputs; + int total; + inputs = (secp256k1_testrand32() & 7) + 1; + outputs = (secp256k1_testrand32() & 7) + 2; + total = inputs + outputs; + for (i = 0; i < 19; i++) { + cptr[i] = &commits[i]; + bptr[i] = &blinds[i * 32]; + } + totalv = 0; + for (i = 0; i < inputs; i++) { + values[i] = secp256k1_testrandi64(0, INT64_MAX - totalv); + totalv += values[i]; + } + for (i = 0; i < outputs - 1; i++) { + values[i + inputs] = secp256k1_testrandi64(0, totalv); + totalv -= values[i + inputs]; + } + values[total - 1] = totalv; + + for (i = 0; i < total - 1; i++) { + random_scalar_order(&s); + secp256k1_scalar_get_b32(&blinds[i * 32], &s); + } + CHECK(secp256k1_pedersen_blind_sum(ctx, &blinds[(total - 1) * 32], bptr, total - 1, inputs)); + for (i = 0; i < total; i++) { + CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h)); + } + CHECK(secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs)); + CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[inputs], outputs, cptr, inputs)); + if (inputs > 0 && values[0] > 0) { + CHECK(!secp256k1_pedersen_verify_tally(ctx, cptr, inputs - 1, &cptr[inputs], outputs)); + } + random_scalar_order(&s); + for (i = 0; i < 4; i++) { + secp256k1_scalar_get_b32(&blinds[i * 32], &s); + } + values[0] = INT64_MAX; + values[1] = 0; + values[2] = 1; + for (i = 0; i < 3; i++) { + CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h)); + } + CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1)); + CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1)); +} + +void test_pedersen_commitment_fixed_vector(void) { + const unsigned char two_g[33] = { + 0x09, + 0xc6, 0x04, 0x7f, 0x94, 0x41, 0xed, 0x7d, 0x6d, 0x30, 0x45, 0x40, 0x6e, 0x95, 0xc0, 0x7c, 0xd8, + 0x5c, 0x77, 0x8e, 0x4b, 0x8c, 0xef, 0x3c, 0xa7, 0xab, 0xac, 0x09, 0xb9, 0x5c, 0x70, 0x9e, 0xe5 + }; + unsigned char result[33]; + secp256k1_pedersen_commitment parse; + + CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, two_g)); + CHECK(secp256k1_pedersen_commitment_serialize(ctx, result, &parse)); + CHECK(secp256k1_memcmp_var(two_g, result, 33) == 0); + + result[0] = 0x08; + CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, result)); + result[0] = 0x0c; + CHECK(!secp256k1_pedersen_commitment_parse(ctx, &parse, result)); +} + + void run_generator_tests(void) { + int i; + test_shallue_van_de_woestijne(); test_generator_fixed_vector(); test_generator_api(); test_generator_generate(); + test_pedersen_api(); + test_pedersen_commitment_fixed_vector(); + for (i = 0; i < count / 2 + 1; i++) { + test_pedersen(); + } } #endif diff --git a/src/modules/rangeproof/Makefile.am.include b/src/modules/rangeproof/Makefile.am.include index ff8b8d380..5272f2293 100644 --- a/src/modules/rangeproof/Makefile.am.include +++ b/src/modules/rangeproof/Makefile.am.include @@ -1,7 +1,5 @@ include_HEADERS += include/secp256k1_rangeproof.h noinst_HEADERS += src/modules/rangeproof/main_impl.h -noinst_HEADERS += src/modules/rangeproof/pedersen.h -noinst_HEADERS += src/modules/rangeproof/pedersen_impl.h noinst_HEADERS += src/modules/rangeproof/borromean.h noinst_HEADERS += src/modules/rangeproof/borromean_impl.h noinst_HEADERS += src/modules/rangeproof/rangeproof.h diff --git a/src/modules/rangeproof/main_impl.h b/src/modules/rangeproof/main_impl.h index 432f4b959..b1af2a5ec 100644 --- a/src/modules/rangeproof/main_impl.h +++ b/src/modules/rangeproof/main_impl.h @@ -9,225 +9,9 @@ #include "../../group.h" -#include "pedersen_impl.h" -#include "borromean_impl.h" -#include "rangeproof_impl.h" - -/** Alternative generator for secp256k1. - * This is the sha256 of 'g' after standard encoding (without compression), - * which happens to be a point on the curve. More precisely, the generator is - * derived by running the following script with the sage mathematics software. - - import hashlib - F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) - G = '0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8' - H = EllipticCurve ([F (0), F (7)]).lift_x(F(int(hashlib.sha256(G.decode('hex')).hexdigest(),16))) - print('%x %x' % H.xy()) - */ -static const secp256k1_generator secp256k1_generator_h_internal = {{ - 0x50, 0x92, 0x9b, 0x74, 0xc1, 0xa0, 0x49, 0x54, 0xb7, 0x8b, 0x4b, 0x60, 0x35, 0xe9, 0x7a, 0x5e, - 0x07, 0x8a, 0x5a, 0x0f, 0x28, 0xec, 0x96, 0xd5, 0x47, 0xbf, 0xee, 0x9a, 0xce, 0x80, 0x3a, 0xc0, - 0x31, 0xd3, 0xc6, 0x86, 0x39, 0x73, 0x92, 0x6e, 0x04, 0x9e, 0x63, 0x7c, 0xb1, 0xb5, 0xf4, 0x0a, - 0x36, 0xda, 0xc2, 0x8a, 0xf1, 0x76, 0x69, 0x68, 0xc3, 0x0c, 0x23, 0x13, 0xf3, 0xa3, 0x89, 0x04 -}}; - -const secp256k1_generator *secp256k1_generator_h = &secp256k1_generator_h_internal; - -static void secp256k1_pedersen_commitment_load(secp256k1_ge* ge, const secp256k1_pedersen_commitment* commit) { - secp256k1_fe fe; - secp256k1_fe_set_b32(&fe, &commit->data[1]); - secp256k1_ge_set_xquad(ge, &fe); - if (commit->data[0] & 1) { - secp256k1_ge_neg(ge, ge); - } -} - -static void secp256k1_pedersen_commitment_save(secp256k1_pedersen_commitment* commit, secp256k1_ge* ge) { - secp256k1_fe_normalize(&ge->x); - secp256k1_fe_get_b32(&commit->data[1], &ge->x); - commit->data[0] = 9 ^ secp256k1_fe_is_quad_var(&ge->y); -} - -int secp256k1_pedersen_commitment_parse(const secp256k1_context* ctx, secp256k1_pedersen_commitment* commit, const unsigned char *input) { - secp256k1_fe x; - secp256k1_ge ge; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(commit != NULL); - ARG_CHECK(input != NULL); - (void) ctx; - - if ((input[0] & 0xFE) != 8 || - !secp256k1_fe_set_b32(&x, &input[1]) || - !secp256k1_ge_set_xquad(&ge, &x)) { - return 0; - } - if (input[0] & 1) { - secp256k1_ge_neg(&ge, &ge); - } - secp256k1_pedersen_commitment_save(commit, &ge); - return 1; -} - -int secp256k1_pedersen_commitment_serialize(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pedersen_commitment* commit) { - secp256k1_ge ge; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output != NULL); - ARG_CHECK(commit != NULL); - - secp256k1_pedersen_commitment_load(&ge, commit); - - output[0] = 9 ^ secp256k1_fe_is_quad_var(&ge.y); - secp256k1_fe_normalize_var(&ge.x); - secp256k1_fe_get_b32(&output[1], &ge.x); - return 1; -} - -/* Generates a pedersen commitment: *commit = blind * G + value * G2. The blinding factor is 32 bytes.*/ -int secp256k1_pedersen_commit(const secp256k1_context* ctx, secp256k1_pedersen_commitment *commit, const unsigned char *blind, uint64_t value, const secp256k1_generator* gen) { - secp256k1_ge genp; - secp256k1_gej rj; - secp256k1_ge r; - secp256k1_scalar sec; - int overflow; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(commit != NULL); - ARG_CHECK(blind != NULL); - ARG_CHECK(gen != NULL); - secp256k1_generator_load(&genp, gen); - secp256k1_scalar_set_b32(&sec, blind, &overflow); - if (!overflow) { - secp256k1_pedersen_ecmult(&ctx->ecmult_gen_ctx, &rj, &sec, value, &genp); - if (!secp256k1_gej_is_infinity(&rj)) { - secp256k1_ge_set_gej(&r, &rj); - secp256k1_pedersen_commitment_save(commit, &r); - ret = 1; - } - secp256k1_gej_clear(&rj); - secp256k1_ge_clear(&r); - } - secp256k1_scalar_clear(&sec); - return ret; -} - -/** Takes a list of n pointers to 32 byte blinding values, the first negs of which are treated with positive sign and the rest - * negative, then calculates an additional blinding value that adds to zero. - */ -int secp256k1_pedersen_blind_sum(const secp256k1_context* ctx, unsigned char *blind_out, const unsigned char * const *blinds, size_t n, size_t npositive) { - secp256k1_scalar acc; - secp256k1_scalar x; - size_t i; - int overflow; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(blind_out != NULL); - ARG_CHECK(blinds != NULL); - ARG_CHECK(npositive <= n); - (void) ctx; - secp256k1_scalar_set_int(&acc, 0); - for (i = 0; i < n; i++) { - secp256k1_scalar_set_b32(&x, blinds[i], &overflow); - if (overflow) { - return 0; - } - if (i >= npositive) { - secp256k1_scalar_negate(&x, &x); - } - secp256k1_scalar_add(&acc, &acc, &x); - } - secp256k1_scalar_get_b32(blind_out, &acc); - secp256k1_scalar_clear(&acc); - secp256k1_scalar_clear(&x); - return 1; -} - -/* Takes two lists of commitments and sums the first set and subtracts the second and verifies that they sum to excess. */ -int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const secp256k1_pedersen_commitment * const* commits, size_t pcnt, const secp256k1_pedersen_commitment * const* ncommits, size_t ncnt) { - secp256k1_gej accj; - secp256k1_ge add; - size_t i; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(!pcnt || (commits != NULL)); - ARG_CHECK(!ncnt || (ncommits != NULL)); - (void) ctx; - secp256k1_gej_set_infinity(&accj); - for (i = 0; i < ncnt; i++) { - secp256k1_pedersen_commitment_load(&add, ncommits[i]); - secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL); - } - secp256k1_gej_neg(&accj, &accj); - for (i = 0; i < pcnt; i++) { - secp256k1_pedersen_commitment_load(&add, commits[i]); - secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL); - } - return secp256k1_gej_is_infinity(&accj); -} - -int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, const uint64_t *value, const unsigned char* const* generator_blind, unsigned char* const* blinding_factor, size_t n_total, size_t n_inputs) { - secp256k1_scalar sum; - secp256k1_scalar tmp; - size_t i; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(n_total == 0 || value != NULL); - ARG_CHECK(n_total == 0 || generator_blind != NULL); - ARG_CHECK(n_total == 0 || blinding_factor != NULL); - ARG_CHECK(n_total > n_inputs); - (void) ctx; - - if (n_total == 0) { - return 1; - } - - secp256k1_scalar_set_int(&sum, 0); - - /* Here, n_total > 0. Thus the loop runs at least once. - Thus we may use a do-while loop, which checks the loop - condition only at the end. - - The do-while loop helps GCC prove that the loop runs at least - once and suppresses a -Wmaybe-uninitialized warning. */ - i = 0; - do { - int overflow = 0; - secp256k1_scalar addend; - secp256k1_scalar_set_u64(&addend, value[i]); /* s = v */ - - secp256k1_scalar_set_b32(&tmp, generator_blind[i], &overflow); - if (overflow == 1) { - secp256k1_scalar_clear(&tmp); - secp256k1_scalar_clear(&addend); - secp256k1_scalar_clear(&sum); - return 0; - } - secp256k1_scalar_mul(&addend, &addend, &tmp); /* s = vr */ - - secp256k1_scalar_set_b32(&tmp, blinding_factor[i], &overflow); - if (overflow == 1) { - secp256k1_scalar_clear(&tmp); - secp256k1_scalar_clear(&addend); - secp256k1_scalar_clear(&sum); - return 0; - } - secp256k1_scalar_add(&addend, &addend, &tmp); /* s = vr + r' */ - secp256k1_scalar_cond_negate(&addend, i < n_inputs); /* s is negated if it's an input */ - secp256k1_scalar_add(&sum, &sum, &addend); /* sum += s */ - secp256k1_scalar_clear(&addend); - - i++; - } while (i < n_total); - - /* Right now tmp has the last pedersen blinding factor. Subtract the sum from it. */ - secp256k1_scalar_negate(&sum, &sum); - secp256k1_scalar_add(&tmp, &tmp, &sum); - secp256k1_scalar_get_b32(blinding_factor[n_total - 1], &tmp); - - secp256k1_scalar_clear(&tmp); - secp256k1_scalar_clear(&sum); - return 1; -} +#include "modules/generator/main_impl.h" +#include "modules/rangeproof/borromean_impl.h" +#include "modules/rangeproof/rangeproof_impl.h" 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) { diff --git a/src/modules/rangeproof/rangeproof_impl.h b/src/modules/rangeproof/rangeproof_impl.h index fbf32b291..dd79b6adb 100644 --- a/src/modules/rangeproof/rangeproof_impl.h +++ b/src/modules/rangeproof/rangeproof_impl.h @@ -13,9 +13,9 @@ #include "../../hash_impl.h" #include "../../util.h" -#include "pedersen.h" -#include "rangeproof.h" -#include "borromean.h" +#include "modules/generator/pedersen.h" +#include "modules/rangeproof/borromean.h" +#include "modules/rangeproof/rangeproof.h" SECP256K1_INLINE static void secp256k1_rangeproof_pub_expand(secp256k1_gej *pubs, int exp, size_t *rsizes, size_t rings, const secp256k1_ge* genp) { diff --git a/src/modules/rangeproof/tests_impl.h b/src/modules/rangeproof/tests_impl.h index 9c9207343..61d0492ea 100644 --- a/src/modules/rangeproof/tests_impl.h +++ b/src/modules/rangeproof/tests_impl.h @@ -16,66 +16,6 @@ #include "../../../include/secp256k1_rangeproof.h" -static void test_pedersen_api(const secp256k1_context *none, const secp256k1_context *sign, const secp256k1_context *vrfy, const secp256k1_context *sttc, const int32_t *ecount) { - secp256k1_pedersen_commitment commit; - const secp256k1_pedersen_commitment *commit_ptr = &commit; - unsigned char blind[32]; - unsigned char blind_out[32]; - const unsigned char *blind_ptr = blind; - unsigned char *blind_out_ptr = blind_out; - uint64_t val = secp256k1_testrand32(); - - secp256k1_testrand256(blind); - CHECK(secp256k1_pedersen_commit(none, &commit, blind, val, secp256k1_generator_h) != 0); - CHECK(secp256k1_pedersen_commit(vrfy, &commit, blind, val, secp256k1_generator_h) != 0); - CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0); - CHECK(*ecount == 0); - CHECK(secp256k1_pedersen_commit(sttc, &commit, blind, val, secp256k1_generator_h) == 0); - CHECK(*ecount == 1); - - CHECK(secp256k1_pedersen_commit(sign, NULL, blind, val, secp256k1_generator_h) == 0); - CHECK(*ecount == 2); - CHECK(secp256k1_pedersen_commit(sign, &commit, NULL, val, secp256k1_generator_h) == 0); - CHECK(*ecount == 3); - CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, NULL) == 0); - CHECK(*ecount == 4); - - CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 1, 1) != 0); - CHECK(*ecount == 4); - CHECK(secp256k1_pedersen_blind_sum(none, NULL, &blind_ptr, 1, 1) == 0); - CHECK(*ecount == 5); - CHECK(secp256k1_pedersen_blind_sum(none, blind_out, NULL, 1, 1) == 0); - CHECK(*ecount == 6); - CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 1) == 0); - CHECK(*ecount == 7); - CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 0) != 0); - CHECK(*ecount == 7); - - CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0); - CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, &commit_ptr, 1) != 0); - CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, &commit_ptr, 1) == 0); - CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 0) == 0); - CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, NULL, 0) != 0); - CHECK(*ecount == 7); - CHECK(secp256k1_pedersen_verify_tally(none, NULL, 1, &commit_ptr, 1) == 0); - CHECK(*ecount == 8); - CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 1) == 0); - CHECK(*ecount == 9); - - CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 0) != 0); - CHECK(*ecount == 9); - CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 1) == 0); - CHECK(*ecount == 10); - CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 0, 0) == 0); - CHECK(*ecount == 11); - CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, NULL, &blind_ptr, &blind_out_ptr, 1, 0) == 0); - CHECK(*ecount == 12); - CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, NULL, &blind_out_ptr, 1, 0) == 0); - CHECK(*ecount == 13); - CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, NULL, 1, 0) == 0); - CHECK(*ecount == 14); -} - static void test_rangeproof_api(const secp256k1_context *none, const secp256k1_context *sign, const secp256k1_context *vrfy, const secp256k1_context *both, const secp256k1_context *sttc, const int32_t *ecount) { unsigned char proof[5134]; unsigned char blind[32]; @@ -253,8 +193,6 @@ static void test_api(void) { secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); for (i = 0; i < count; i++) { - ecount = 0; - test_pedersen_api(none, sign, vrfy, sttc, &ecount); ecount = 0; test_rangeproof_api(none, sign, vrfy, both, sttc, &ecount); } @@ -266,63 +204,6 @@ static void test_api(void) { secp256k1_context_destroy(sttc); } -static void test_pedersen(void) { - secp256k1_pedersen_commitment commits[19]; - const secp256k1_pedersen_commitment *cptr[19]; - unsigned char blinds[32*19]; - const unsigned char *bptr[19]; - secp256k1_scalar s; - uint64_t values[19]; - int64_t totalv; - int i; - int inputs; - int outputs; - int total; - inputs = (secp256k1_testrand32() & 7) + 1; - outputs = (secp256k1_testrand32() & 7) + 2; - total = inputs + outputs; - for (i = 0; i < 19; i++) { - cptr[i] = &commits[i]; - bptr[i] = &blinds[i * 32]; - } - totalv = 0; - for (i = 0; i < inputs; i++) { - values[i] = secp256k1_testrandi64(0, INT64_MAX - totalv); - totalv += values[i]; - } - for (i = 0; i < outputs - 1; i++) { - values[i + inputs] = secp256k1_testrandi64(0, totalv); - totalv -= values[i + inputs]; - } - values[total - 1] = totalv; - - for (i = 0; i < total - 1; i++) { - random_scalar_order(&s); - secp256k1_scalar_get_b32(&blinds[i * 32], &s); - } - CHECK(secp256k1_pedersen_blind_sum(ctx, &blinds[(total - 1) * 32], bptr, total - 1, inputs)); - for (i = 0; i < total; i++) { - CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h)); - } - CHECK(secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs)); - CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[inputs], outputs, cptr, inputs)); - if (inputs > 0 && values[0] > 0) { - CHECK(!secp256k1_pedersen_verify_tally(ctx, cptr, inputs - 1, &cptr[inputs], outputs)); - } - random_scalar_order(&s); - for (i = 0; i < 4; i++) { - secp256k1_scalar_get_b32(&blinds[i * 32], &s); - } - values[0] = INT64_MAX; - values[1] = 0; - values[2] = 1; - for (i = 0; i < 3; i++) { - CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h)); - } - CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1)); - CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1)); -} - static void test_borromean(void) { unsigned char e0[32]; secp256k1_scalar s[64]; @@ -1523,25 +1404,6 @@ void test_rangeproof_fixed_vectors_reproducible(void) { } } -void test_pedersen_commitment_fixed_vector(void) { - const unsigned char two_g[33] = { - 0x09, - 0xc6, 0x04, 0x7f, 0x94, 0x41, 0xed, 0x7d, 0x6d, 0x30, 0x45, 0x40, 0x6e, 0x95, 0xc0, 0x7c, 0xd8, - 0x5c, 0x77, 0x8e, 0x4b, 0x8c, 0xef, 0x3c, 0xa7, 0xab, 0xac, 0x09, 0xb9, 0x5c, 0x70, 0x9e, 0xe5 - }; - unsigned char result[33]; - secp256k1_pedersen_commitment parse; - - CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, two_g)); - CHECK(secp256k1_pedersen_commitment_serialize(ctx, result, &parse)); - CHECK(secp256k1_memcmp_var(two_g, result, 33) == 0); - - result[0] = 0x08; - CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, result)); - result[0] = 0x0c; - CHECK(!secp256k1_pedersen_commitment_parse(ctx, &parse, result)); -} - void run_rangeproof_tests(void) { int i; test_api(); @@ -1552,10 +1414,6 @@ void run_rangeproof_tests(void) { test_rangeproof_fixed_vectors(); test_rangeproof_fixed_vectors_reproducible(); - test_pedersen_commitment_fixed_vector(); - for (i = 0; i < count / 2 + 1; i++) { - test_pedersen(); - } for (i = 0; i < count / 2 + 1; i++) { test_borromean(); } diff --git a/src/secp256k1.c b/src/secp256k1.c index 6c686e0b6..bf6a1c61d 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -38,8 +38,6 @@ #ifdef ENABLE_MODULE_RANGEPROOF # include "include/secp256k1_rangeproof.h" -# include "modules/rangeproof/pedersen.h" -# include "modules/rangeproof/rangeproof.h" #endif #ifdef ENABLE_MODULE_ECDSA_S2C From 0a6006989f6215a45e982cd696339c503ddfc325 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Tue, 12 Jul 2022 18:51:48 +0000 Subject: [PATCH 02/18] Revert "Remove unused scalar_sqr" This reverts commit 5437e7bdfbffddf69fdf7b4af7e997c78f5dafbf. --- src/bench_internal.c | 10 +++ src/scalar.h | 3 + src/scalar_4x64_impl.h | 166 +++++++++++++++++++++++++++++++++++++++++ src/scalar_8x32_impl.h | 89 ++++++++++++++++++++++ src/scalar_low_impl.h | 4 + src/tests.c | 14 ++++ 6 files changed, 286 insertions(+) diff --git a/src/bench_internal.c b/src/bench_internal.c index 61400519e..898c7801c 100644 --- a/src/bench_internal.c +++ b/src/bench_internal.c @@ -98,6 +98,15 @@ void bench_scalar_negate(void* arg, int iters) { } } +void bench_scalar_sqr(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_scalar_sqr(&data->scalar[0], &data->scalar[0]); + } +} + void bench_scalar_mul(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -376,6 +385,7 @@ int main(int argc, char **argv) { if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, iters*100); if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, iters*100); + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, iters*10); if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, iters*10); if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, iters); diff --git a/src/scalar.h b/src/scalar.h index 36eb0db8d..227913cb5 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -65,6 +65,9 @@ static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, * the low bits that were shifted off */ static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n); +/** Compute the square of a scalar (modulo the group order). */ +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a); + /** Compute the inverse of a scalar (modulo the group order). */ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a); diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h index 6b0b44ed9..585a4b630 100644 --- a/src/scalar_4x64_impl.h +++ b/src/scalar_4x64_impl.h @@ -224,6 +224,28 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { VERIFY_CHECK(c1 >= th); \ } +/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd2(a,b) { \ + uint64_t tl, th, th2, tl2; \ + { \ + uint128_t t = (uint128_t)a * b; \ + th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = t; \ + } \ + th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \ + c2 += (th2 < th); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ + tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \ + th2 += (tl2 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \ + c0 += tl2; /* overflow is handled on the next line */ \ + th2 += (c0 < tl2); /* second overflow is handled on the next line */ \ + c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ + c1 += th2; /* overflow is handled on the next line */ \ + c2 += (c1 < th2); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ +} + /** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ #define sumadd(a) { \ unsigned int over; \ @@ -733,10 +755,148 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c #endif } +static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar *a) { +#ifdef USE_ASM_X86_64 + __asm__ __volatile__( + /* Preload */ + "movq 0(%%rdi), %%r11\n" + "movq 8(%%rdi), %%r12\n" + "movq 16(%%rdi), %%r13\n" + "movq 24(%%rdi), %%r14\n" + /* (rax,rdx) = a0 * a0 */ + "movq %%r11, %%rax\n" + "mulq %%r11\n" + /* Extract l0 */ + "movq %%rax, 0(%%rsi)\n" + /* (r8,r9,r10) = (rdx,0) */ + "movq %%rdx, %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += 2 * a0 * a1 */ + "movq %%r11, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l1 */ + "movq %%r8, 8(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += 2 * a0 * a2 */ + "movq %%r11, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a1 * a1 */ + "movq %%r12, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l2 */ + "movq %%r9, 16(%%rsi)\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += 2 * a0 * a3 */ + "movq %%r11, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += 2 * a1 * a2 */ + "movq %%r12, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Extract l3 */ + "movq %%r10, 24(%%rsi)\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += 2 * a1 * a3 */ + "movq %%r12, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a2 * a2 */ + "movq %%r13, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l4 */ + "movq %%r8, 32(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += 2 * a2 * a3 */ + "movq %%r13, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l5 */ + "movq %%r9, 40(%%rsi)\n" + /* (r10,r8) += a3 * a3 */ + "movq %%r14, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + /* Extract l6 */ + "movq %%r10, 48(%%rsi)\n" + /* Extract l7 */ + "movq %%r8, 56(%%rsi)\n" + : + : "S"(l), "D"(a->d) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc", "memory"); +#else + /* 160 bit accumulator. */ + uint64_t c0 = 0, c1 = 0; + uint32_t c2 = 0; + + /* l[0..7] = a[0..3] * b[0..3]. */ + muladd_fast(a->d[0], a->d[0]); + extract_fast(l[0]); + muladd2(a->d[0], a->d[1]); + extract(l[1]); + muladd2(a->d[0], a->d[2]); + muladd(a->d[1], a->d[1]); + extract(l[2]); + muladd2(a->d[0], a->d[3]); + muladd2(a->d[1], a->d[2]); + extract(l[3]); + muladd2(a->d[1], a->d[3]); + muladd(a->d[2], a->d[2]); + extract(l[4]); + muladd2(a->d[2], a->d[3]); + extract(l[5]); + muladd_fast(a->d[3], a->d[3]); + extract_fast(l[6]); + VERIFY_CHECK(c1 == 0); + l[7] = c0; +#endif +} + #undef sumadd #undef sumadd_fast #undef muladd #undef muladd_fast +#undef muladd2 #undef extract #undef extract_fast @@ -758,6 +918,12 @@ static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { return ret; } +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { + uint64_t l[8]; + secp256k1_scalar_sqr_512(l, a); + secp256k1_scalar_reduce_512(r, l); +} + static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { r1->d[0] = k->d[0]; r1->d[1] = k->d[1]; diff --git a/src/scalar_8x32_impl.h b/src/scalar_8x32_impl.h index acd5ef7de..6086f1ec2 100644 --- a/src/scalar_8x32_impl.h +++ b/src/scalar_8x32_impl.h @@ -306,6 +306,28 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { VERIFY_CHECK(c1 >= th); \ } +/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd2(a,b) { \ + uint32_t tl, th, th2, tl2; \ + { \ + uint64_t t = (uint64_t)a * b; \ + th = t >> 32; /* at most 0xFFFFFFFE */ \ + tl = t; \ + } \ + th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \ + c2 += (th2 < th); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ + tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \ + th2 += (tl2 < tl); /* at most 0xFFFFFFFF */ \ + c0 += tl2; /* overflow is handled on the next line */ \ + th2 += (c0 < tl2); /* second overflow is handled on the next line */ \ + c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ + c1 += th2; /* overflow is handled on the next line */ \ + c2 += (c1 < th2); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ +} + /** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ #define sumadd(a) { \ unsigned int over; \ @@ -569,10 +591,71 @@ static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, con l[15] = c0; } +static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar *a) { + /* 96 bit accumulator. */ + uint32_t c0 = 0, c1 = 0, c2 = 0; + + /* l[0..15] = a[0..7]^2. */ + muladd_fast(a->d[0], a->d[0]); + extract_fast(l[0]); + muladd2(a->d[0], a->d[1]); + extract(l[1]); + muladd2(a->d[0], a->d[2]); + muladd(a->d[1], a->d[1]); + extract(l[2]); + muladd2(a->d[0], a->d[3]); + muladd2(a->d[1], a->d[2]); + extract(l[3]); + muladd2(a->d[0], a->d[4]); + muladd2(a->d[1], a->d[3]); + muladd(a->d[2], a->d[2]); + extract(l[4]); + muladd2(a->d[0], a->d[5]); + muladd2(a->d[1], a->d[4]); + muladd2(a->d[2], a->d[3]); + extract(l[5]); + muladd2(a->d[0], a->d[6]); + muladd2(a->d[1], a->d[5]); + muladd2(a->d[2], a->d[4]); + muladd(a->d[3], a->d[3]); + extract(l[6]); + muladd2(a->d[0], a->d[7]); + muladd2(a->d[1], a->d[6]); + muladd2(a->d[2], a->d[5]); + muladd2(a->d[3], a->d[4]); + extract(l[7]); + muladd2(a->d[1], a->d[7]); + muladd2(a->d[2], a->d[6]); + muladd2(a->d[3], a->d[5]); + muladd(a->d[4], a->d[4]); + extract(l[8]); + muladd2(a->d[2], a->d[7]); + muladd2(a->d[3], a->d[6]); + muladd2(a->d[4], a->d[5]); + extract(l[9]); + muladd2(a->d[3], a->d[7]); + muladd2(a->d[4], a->d[6]); + muladd(a->d[5], a->d[5]); + extract(l[10]); + muladd2(a->d[4], a->d[7]); + muladd2(a->d[5], a->d[6]); + extract(l[11]); + muladd2(a->d[5], a->d[7]); + muladd(a->d[6], a->d[6]); + extract(l[12]); + muladd2(a->d[6], a->d[7]); + extract(l[13]); + muladd_fast(a->d[7], a->d[7]); + extract_fast(l[14]); + VERIFY_CHECK(c1 == 0); + l[15] = c0; +} + #undef sumadd #undef sumadd_fast #undef muladd #undef muladd_fast +#undef muladd2 #undef extract #undef extract_fast @@ -598,6 +681,12 @@ static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { return ret; } +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { + uint32_t l[16]; + secp256k1_scalar_sqr_512(l, a); + secp256k1_scalar_reduce_512(r, l); +} + static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { r1->d[0] = k->d[0]; r1->d[1] = k->d[1]; diff --git a/src/scalar_low_impl.h b/src/scalar_low_impl.h index 47001fccb..aa75f8b0f 100644 --- a/src/scalar_low_impl.h +++ b/src/scalar_low_impl.h @@ -105,6 +105,10 @@ static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { return ret; } +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { + *r = (*a * *a) % EXHAUSTIVE_TEST_ORDER; +} + static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { *r1 = *a; *r2 = 0; diff --git a/src/tests.c b/src/tests.c index ca1ded47b..89f474322 100644 --- a/src/tests.c +++ b/src/tests.c @@ -1898,6 +1898,14 @@ void scalar_test(void) { CHECK(secp256k1_scalar_eq(&r1, &r2)); } + { + /* Test square. */ + secp256k1_scalar r1, r2; + secp256k1_scalar_sqr(&r1, &s1); + secp256k1_scalar_mul(&r2, &s1, &s1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + { /* Test multiplicative identity. */ secp256k1_scalar r1, v1; @@ -2653,6 +2661,12 @@ void run_scalar_tests(void) { CHECK(!secp256k1_scalar_check_overflow(&zz)); CHECK(secp256k1_scalar_eq(&one, &zz)); } + secp256k1_scalar_mul(&z, &x, &x); + CHECK(!secp256k1_scalar_check_overflow(&z)); + secp256k1_scalar_sqr(&zz, &x); + CHECK(!secp256k1_scalar_check_overflow(&zz)); + CHECK(secp256k1_scalar_eq(&zz, &z)); + CHECK(secp256k1_scalar_eq(&r2, &zz)); } } } From 6162d577fec175c620f759675eb09ffa10368de1 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Tue, 12 Jul 2022 18:56:44 +0000 Subject: [PATCH 03/18] generator: cleanups in Pedersen/generator code Silence a compiler warning about an unitialized use of a scalar in case the user tries to provide a 0-length list of commitments. Also ensures that commitments have normalized field elements when they are loaded into ges. --- src/modules/generator/main_impl.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/generator/main_impl.h b/src/modules/generator/main_impl.h index c9f6ec8b0..e60ecdc20 100644 --- a/src/modules/generator/main_impl.h +++ b/src/modules/generator/main_impl.h @@ -391,6 +391,7 @@ int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, c } secp256k1_scalar_set_int(&sum, 0); + secp256k1_scalar_set_int(&tmp, 0); /* Here, n_total > 0. Thus the loop runs at least once. Thus we may use a do-while loop, which checks the loop From 048f9f8642297578a4e7975fa1e9837a58fc1c66 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 27 Aug 2022 15:02:44 +0000 Subject: [PATCH 04/18] bulletproofs: add new empty module --- .gitignore | 5 ++- Makefile.am | 4 +++ ci/cirrus.sh | 1 + configure.ac | 15 ++++++++ include/secp256k1_bulletproofs.h | 18 ++++++++++ src/bench_bulletproofs.c | 38 ++++++++++++++++++++ src/modules/bulletproofs/Makefile.am.include | 10 ++++++ src/modules/bulletproofs/main_impl.h | 12 +++++++ src/modules/bulletproofs/tests_impl.h | 14 ++++++++ src/secp256k1.c | 4 +++ src/tests.c | 8 +++++ 11 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 include/secp256k1_bulletproofs.h create mode 100644 src/bench_bulletproofs.c create mode 100644 src/modules/bulletproofs/Makefile.am.include create mode 100644 src/modules/bulletproofs/main_impl.h create mode 100644 src/modules/bulletproofs/tests_impl.h diff --git a/.gitignore b/.gitignore index 1ec887ded..3c0494d55 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,12 @@ bench +bench_bulletproofs bench_ecmult bench_generator bench_rangeproof bench_internal +bench_whitelist tests +example_musig exhaustive_tests precompute_ecmult_gen precompute_ecmult @@ -66,4 +69,4 @@ src/stamp-h1 libsecp256k1.pc contrib/gh-pr-create.sh -musig_example \ No newline at end of file +musig_example diff --git a/Makefile.am b/Makefile.am index 0b50f7a8b..722dfac3a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -226,6 +226,10 @@ clean-precomp: EXTRA_DIST = autogen.sh SECURITY.md +if ENABLE_MODULE_BULLETPROOFS +include src/modules/bulletproofs/Makefile.am.include +endif + if ENABLE_MODULE_ECDH include src/modules/ecdh/Makefile.am.include endif diff --git a/ci/cirrus.sh b/ci/cirrus.sh index 431d35e46..74e8ab5ba 100755 --- a/ci/cirrus.sh +++ b/ci/cirrus.sh @@ -19,6 +19,7 @@ valgrind --version || true --with-ecmult-gen-precision="$ECMULTGENPRECISION" \ --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \ --enable-module-ecdsa-s2c="$ECDSA_S2C" \ + --enable-module-bulletproofs="$BULLETPROOFS" \ --enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \ --enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \ --enable-module-schnorrsig="$SCHNORRSIG" \ diff --git a/configure.ac b/configure.ac index 3ab35ed8c..0b0a9d78e 100644 --- a/configure.ac +++ b/configure.ac @@ -140,6 +140,11 @@ AC_ARG_ENABLE(examples, AS_HELP_STRING([--enable-examples],[compile the examples [default=no]]), [], [SECP_SET_DEFAULT([enable_examples], [no], [yes])]) +AC_ARG_ENABLE(module_bulletproofs, + AS_HELP_STRING([--enable-module-bulletproofs],[enable Bulletproofs module (experimental)]), + [], + [SECP_SET_DEFAULT([enable_module_bulletproofs], [no], [yes])]) + AC_ARG_ENABLE(module_ecdh, AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=no]]), [], [SECP_SET_DEFAULT([enable_module_ecdh], [no], [yes])]) @@ -417,6 +422,11 @@ if test x"$enable_module_rangeproof" = x"yes"; then AC_DEFINE(ENABLE_MODULE_RANGEPROOF, 1, [Define this symbol to enable the Pedersen / zero knowledge range proof module]) fi +if test x"$enable_module_bulletproofs" = x"yes"; then + enable_module_generator=yes + AC_DEFINE(ENABLE_MODULE_BULLETPROOFS, 1, [Define this symbol to enable the Bulletproofs module]) +fi + if test x"$enable_module_generator" = x"yes"; then AC_DEFINE(ENABLE_MODULE_GENERATOR, 1, [Define this symbol to enable the NUMS generator module]) fi @@ -460,6 +470,9 @@ else # module (which automatically enables the module dependencies) we want to # print an error for the dependent module, not the module dependency. Hence, # we first test dependent modules. + if test x"$enable_module_bulletproofs" = x"yes"; then + AC_MSG_ERROR([Bulletproofs module is experimental. Use --enable-experimental to allow.]) + fi if test x"$enable_module_whitelist" = x"yes"; then AC_MSG_ERROR([Key whitelisting module is experimental. Use --enable-experimental to allow.]) fi @@ -502,6 +515,7 @@ AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"]) AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"]) AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"]) AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_BULLETPROOFS], [test x"$enable_module_bulletproofs" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) @@ -541,6 +555,7 @@ echo " module whitelist = $enable_module_whitelist" echo " module musig = $enable_module_musig" echo " module ecdsa-s2c = $enable_module_ecdsa_s2c" echo " module ecdsa-adaptor = $enable_module_ecdsa_adaptor" +echo " module bulletproofs = $enable_module_bulletproofs" echo echo " asm = $set_asm" echo " ecmult window size = $set_ecmult_window" diff --git a/include/secp256k1_bulletproofs.h b/include/secp256k1_bulletproofs.h new file mode 100644 index 000000000..889d790b2 --- /dev/null +++ b/include/secp256k1_bulletproofs.h @@ -0,0 +1,18 @@ +#ifndef _SECP256K1_BULLETPROOFS_ +# define _SECP256K1_BULLETPROOFS_ + +# include "secp256k1.h" + +# ifdef __cplusplus +extern "C" { +# endif + +#include + +/* TODO */ + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/bench_bulletproofs.c b/src/bench_bulletproofs.c new file mode 100644 index 000000000..f113791c4 --- /dev/null +++ b/src/bench_bulletproofs.c @@ -0,0 +1,38 @@ +/********************************************************************** + * Copyright (c) 2020 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include + +#include "include/secp256k1_bulletproofs.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_context* ctx; +} bench_bulletproofs_data; + +static void bench_bulletproofs_setup(void* arg) { + (void) arg; +} + +static void bench_bulletproofs(void* arg, int iters) { + bench_bulletproofs_data *data = (bench_bulletproofs_data*)arg; + + (void) data; + (void) iters; +} + +int main(void) { + bench_bulletproofs_data data; + int iters = get_iters(32); + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + run_benchmark("bulletproofs_verify_bit", bench_bulletproofs, bench_bulletproofs_setup, NULL, &data, 10, iters); + + secp256k1_context_destroy(data.ctx); + return 0; +} diff --git a/src/modules/bulletproofs/Makefile.am.include b/src/modules/bulletproofs/Makefile.am.include new file mode 100644 index 000000000..6cd9fc3c8 --- /dev/null +++ b/src/modules/bulletproofs/Makefile.am.include @@ -0,0 +1,10 @@ +include_HEADERS += include/secp256k1_bulletproofs.h +noinst_HEADERS += src/modules/bulletproofs/tests_impl.h +noinst_HEADERS += src/modules/bulletproofs/main_impl.h + +if USE_BENCHMARK +noinst_PROGRAMS += bench_bulletproofs +bench_bulletproofs_SOURCES = src/bench_bulletproofs.c +bench_bulletproofs_LDADD = libsecp256k1.la $(SECP_LIBS) +bench_bulletproofs_LDFLAGS = -static +endif diff --git a/src/modules/bulletproofs/main_impl.h b/src/modules/bulletproofs/main_impl.h new file mode 100644 index 000000000..9c61eaf74 --- /dev/null +++ b/src/modules/bulletproofs/main_impl.h @@ -0,0 +1,12 @@ +/********************************************************************** + * Copyright (c) 2020 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_BULLETPROOFS_MAIN_ +#define _SECP256K1_MODULE_BULLETPROOFS_MAIN_ + +/* TODO */ + +#endif diff --git a/src/modules/bulletproofs/tests_impl.h b/src/modules/bulletproofs/tests_impl.h new file mode 100644 index 000000000..0c88fb78c --- /dev/null +++ b/src/modules/bulletproofs/tests_impl.h @@ -0,0 +1,14 @@ +/********************************************************************** + * Copyright (c) 2020 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_BULLETPROOFS_TEST_ +#define _SECP256K1_MODULE_BULLETPROOFS_TEST_ + +void run_bulletproofs_tests(void) { + /* TODO */ +} + +#endif diff --git a/src/secp256k1.c b/src/secp256k1.c index bf6a1c61d..857e9a76e 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -800,6 +800,10 @@ int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32, return 1; } +#ifdef ENABLE_MODULE_BULLETPROOFS +# include "modules/bulletproofs/main_impl.h" +#endif + #ifdef ENABLE_MODULE_ECDH # include "modules/ecdh/main_impl.h" #endif diff --git a/src/tests.c b/src/tests.c index 89f474322..fc84b3cb1 100644 --- a/src/tests.c +++ b/src/tests.c @@ -7132,6 +7132,10 @@ void run_ecdsa_edge_cases(void) { test_ecdsa_edge_cases(); } +#ifdef ENABLE_MODULE_BULLETPROOFS +# include "modules/bulletproofs/tests_impl.h" +#endif + #ifdef ENABLE_MODULE_ECDH # include "modules/ecdh/tests_impl.h" #endif @@ -7452,6 +7456,10 @@ int main(int argc, char **argv) { /* EC key arithmetic test */ run_eckey_negate_test(); +#ifdef ENABLE_MODULE_BULLETPROOFS + run_bulletproofs_tests(); +#endif + #ifdef ENABLE_MODULE_ECDH /* ecdh tests */ run_ecdh_tests(); From 48563c8c791d2d5ed50dabde9de8c0839f43c8f3 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Thu, 12 Nov 2020 03:22:44 +0000 Subject: [PATCH 05/18] bulletproofs: add API functionality to generate a large set of generators --- include/secp256k1_bulletproofs.h | 57 ++++++++++++- src/modules/bulletproofs/main_impl.h | 109 ++++++++++++++++++++++++- src/modules/bulletproofs/tests_impl.h | 110 +++++++++++++++++++++++++- 3 files changed, 273 insertions(+), 3 deletions(-) diff --git a/include/secp256k1_bulletproofs.h b/include/secp256k1_bulletproofs.h index 889d790b2..1ddd96997 100644 --- a/include/secp256k1_bulletproofs.h +++ b/include/secp256k1_bulletproofs.h @@ -9,7 +9,62 @@ extern "C" { #include -/* TODO */ +/** Opaque structure representing a large number of NUMS generators */ +typedef struct secp256k1_bulletproofs_generators secp256k1_bulletproofs_generators; + +/** Allocates and initializes a list of NUMS generators. + * Returns a list of generators, or calls the error callback if the allocation fails. + * Args: ctx: pointer to a context object + * n: number of NUMS generators to produce. + * + * TODO: In a followup range-proof PR, this is would still require 16 + 8 = 24 NUMS + * points. We will later use G = H0(required for compatibility with pedersen_commitment DS) + * in a separate commit to make review easier. + */ +SECP256K1_API secp256k1_bulletproofs_generators *secp256k1_bulletproofs_generators_create( + const secp256k1_context* ctx, + size_t n +) SECP256K1_ARG_NONNULL(1); + +/** Allocates a list of generators from a static array + * Returns a list of generators or NULL in case of failure. + * Args: ctx: pointer to a context object + * In: data: data that came from `secp256k1_bulletproofs_generators_serialize` + * data_len: the length of the `data` buffer + */ +SECP256K1_API secp256k1_bulletproofs_generators* secp256k1_bulletproofs_generators_parse( + const secp256k1_context* ctx, + const unsigned char* data, + size_t data_len +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Serializes a list of generators to an array + * Returns 1 on success, 0 if the provided array was not large enough + * Args: ctx: pointer to a context object + * gen: pointer to the generator set to be serialized + * Out: data: pointer to buffer into which the generators will be serialized + * In/Out: data_len: the length of the `data` buffer. Should be at least + * k = 33 * num_gens. Will be set to k on successful return + * + * TODO: For ease of review, this setting G = H0 is not included in this commit. We will + * add it in the follow-up rangeproof PR. + */ +SECP256K1_API int secp256k1_bulletproofs_generators_serialize( + const secp256k1_context* ctx, + const secp256k1_bulletproofs_generators* gen, + unsigned char* data, + size_t *data_len +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Destroys a list of NUMS generators, freeing allocated memory + * Args: ctx: pointer to a context object + * gen: pointer to the generator set to be destroyed + * (can be NULL, in which case this function is a no-op) + */ +SECP256K1_API void secp256k1_bulletproofs_generators_destroy( + const secp256k1_context* ctx, + secp256k1_bulletproofs_generators* gen +) SECP256K1_ARG_NONNULL(1); # ifdef __cplusplus } diff --git a/src/modules/bulletproofs/main_impl.h b/src/modules/bulletproofs/main_impl.h index 9c61eaf74..ef0ac78cd 100644 --- a/src/modules/bulletproofs/main_impl.h +++ b/src/modules/bulletproofs/main_impl.h @@ -7,6 +7,113 @@ #ifndef _SECP256K1_MODULE_BULLETPROOFS_MAIN_ #define _SECP256K1_MODULE_BULLETPROOFS_MAIN_ -/* TODO */ +#include "include/secp256k1_bulletproofs.h" +#include "include/secp256k1_generator.h" +#include "modules/generator/main_impl.h" /* for generator_{load, save} */ +#include "hash.h" +#include "util.h" + +struct secp256k1_bulletproofs_generators { + size_t n; + /* n total generators; includes both G_i and H_i */ + secp256k1_ge* gens; +}; + +secp256k1_bulletproofs_generators *secp256k1_bulletproofs_generators_create(const secp256k1_context *ctx, size_t n) { + secp256k1_bulletproofs_generators *ret; + secp256k1_rfc6979_hmac_sha256 rng; + unsigned char seed[64]; + size_t i; + + VERIFY_CHECK(ctx != NULL); + + ret = (secp256k1_bulletproofs_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret)); + if (ret == NULL) { + return NULL; + } + ret->gens = (secp256k1_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens)); + if (ret->gens == NULL) { + free(ret); + return NULL; + } + ret->n = n; + + secp256k1_fe_get_b32(&seed[0], &secp256k1_ge_const_g.x); + secp256k1_fe_get_b32(&seed[32], &secp256k1_ge_const_g.y); + + secp256k1_rfc6979_hmac_sha256_initialize(&rng, seed, 64); + for (i = 0; i < n; i++) { + secp256k1_generator gen; + unsigned char tmp[32] = { 0 }; + secp256k1_rfc6979_hmac_sha256_generate(&rng, tmp, 32); + CHECK(secp256k1_generator_generate(ctx, &gen, tmp)); + secp256k1_generator_load(&ret->gens[i], &gen); + } + + return ret; +} + +secp256k1_bulletproofs_generators* secp256k1_bulletproofs_generators_parse(const secp256k1_context* ctx, const unsigned char* data, size_t data_len) { + size_t n = data_len / 33; + secp256k1_bulletproofs_generators* ret; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(data != NULL); + + if (data_len % 33 != 0) { + return NULL; + } + + ret = (secp256k1_bulletproofs_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret)); + if (ret == NULL) { + return NULL; + } + ret->n = n; + ret->gens = (secp256k1_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens)); + if (ret->gens == NULL) { + free(ret); + return NULL; + } + + while (n--) { + secp256k1_generator gen; + if (!secp256k1_generator_parse(ctx, &gen, &data[33 * n])) { + free(ret->gens); + free(ret); + return NULL; + } + secp256k1_generator_load(&ret->gens[n], &gen); + } + return ret; +} + +int secp256k1_bulletproofs_generators_serialize(const secp256k1_context* ctx, const secp256k1_bulletproofs_generators* gens, unsigned char* data, size_t *data_len) { + size_t i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(gens != NULL); + ARG_CHECK(data != NULL); + ARG_CHECK(data_len != NULL); + ARG_CHECK(*data_len >= 33 * gens->n); + + memset(data, 0, *data_len); + for (i = 0; i < gens->n; i++) { + secp256k1_generator gen; + secp256k1_generator_save(&gen, &gens->gens[i]); + secp256k1_generator_serialize(ctx, &data[33 * i], &gen); + } + + *data_len = 33 * gens->n; + return 1; +} + +void secp256k1_bulletproofs_generators_destroy(const secp256k1_context* ctx, secp256k1_bulletproofs_generators *gens) { + VERIFY_CHECK(ctx != NULL); + (void) ctx; + if (gens != NULL) { + free(gens->gens); + free(gens); + } +} #endif diff --git a/src/modules/bulletproofs/tests_impl.h b/src/modules/bulletproofs/tests_impl.h index 0c88fb78c..f75b7294e 100644 --- a/src/modules/bulletproofs/tests_impl.h +++ b/src/modules/bulletproofs/tests_impl.h @@ -7,8 +7,116 @@ #ifndef _SECP256K1_MODULE_BULLETPROOFS_TEST_ #define _SECP256K1_MODULE_BULLETPROOFS_TEST_ +static void test_bulletproofs_generators_api(void) { + /* The BP generator API requires no precomp */ + secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + + secp256k1_bulletproofs_generators *gens; + secp256k1_bulletproofs_generators *gens_orig; + unsigned char gens_ser[330]; + size_t len = sizeof(gens_ser); + + int32_t ecount = 0; + + secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + + /* Create */ + gens = secp256k1_bulletproofs_generators_create(none, 10); + CHECK(gens != NULL && ecount == 0); + gens_orig = gens; /* Preserve for round-trip test */ + + /* Serialize */ + ecount = 0; + CHECK(!secp256k1_bulletproofs_generators_serialize(none, NULL, gens_ser, &len)); + CHECK(ecount == 1); + CHECK(!secp256k1_bulletproofs_generators_serialize(none, gens, NULL, &len)); + CHECK(ecount == 2); + CHECK(!secp256k1_bulletproofs_generators_serialize(none, gens, gens_ser, NULL)); + CHECK(ecount == 3); + len = 0; + CHECK(!secp256k1_bulletproofs_generators_serialize(none, gens, gens_ser, &len)); + CHECK(ecount == 4); + len = sizeof(gens_ser) - 1; + CHECK(!secp256k1_bulletproofs_generators_serialize(none, gens, gens_ser, &len)); + CHECK(ecount == 5); + len = sizeof(gens_ser); + { + /* Output buffer can be greater than minimum needed */ + unsigned char gens_ser_tmp[331]; + size_t len_tmp = sizeof(gens_ser_tmp); + CHECK(secp256k1_bulletproofs_generators_serialize(none, gens, gens_ser_tmp, &len_tmp)); + CHECK(len_tmp == sizeof(gens_ser_tmp) - 1); + CHECK(ecount == 5); + } + + /* Parse */ + CHECK(secp256k1_bulletproofs_generators_serialize(none, gens, gens_ser, &len)); + ecount = 0; + gens = secp256k1_bulletproofs_generators_parse(none, NULL, sizeof(gens_ser)); + CHECK(gens == NULL && ecount == 1); + /* Not a multiple of 33 */ + gens = secp256k1_bulletproofs_generators_parse(none, gens_ser, sizeof(gens_ser) - 1); + CHECK(gens == NULL && ecount == 1); + gens = secp256k1_bulletproofs_generators_parse(none, gens_ser, sizeof(gens_ser)); + CHECK(gens != NULL && ecount == 1); + /* Not valid generators */ + memset(gens_ser, 1, sizeof(gens_ser)); + CHECK(secp256k1_bulletproofs_generators_parse(none, gens_ser, sizeof(gens_ser)) == NULL); + CHECK(ecount == 1); + + /* Check that round-trip succeeded */ + CHECK(gens->n == gens_orig->n); + for (len = 0; len < gens->n; len++) { + ge_equals_ge(&gens->gens[len], &gens_orig->gens[len]); + } + + /* Destroy (we allow destroying a NULL context, it's just a noop. like free().) */ + ecount = 0; + secp256k1_bulletproofs_generators_destroy(none, NULL); + secp256k1_bulletproofs_generators_destroy(none, gens); + secp256k1_bulletproofs_generators_destroy(none, gens_orig); + CHECK(ecount == 0); + + secp256k1_context_destroy(none); +} + +static void test_bulletproofs_generators_fixed(void) { + secp256k1_bulletproofs_generators *gens = secp256k1_bulletproofs_generators_create(ctx, 3); + unsigned char gens_ser[330]; + const unsigned char fixed_first_3[99] = { + 0x0b, + 0xb3, 0x4d, 0x5f, 0xa6, 0xb8, 0xf3, 0xd1, 0x38, + 0x49, 0xce, 0x51, 0x91, 0xb7, 0xf6, 0x76, 0x18, + 0xfe, 0x5b, 0xd1, 0x2a, 0x88, 0xb2, 0x0e, 0xac, + 0x33, 0x89, 0x45, 0x66, 0x7f, 0xb3, 0x30, 0x56, + 0x0a, + 0x62, 0x86, 0x15, 0x16, 0x92, 0x42, 0x10, 0x9e, + 0x9e, 0x64, 0xd4, 0xcb, 0x28, 0x81, 0x60, 0x9c, + 0x24, 0xb9, 0x89, 0x51, 0x2a, 0xd9, 0x01, 0xae, + 0xff, 0x75, 0x64, 0x9c, 0x37, 0x5d, 0xbd, 0x79, + 0x0a, + 0xed, 0xe0, 0x6e, 0x07, 0x5e, 0x79, 0xd0, 0xf7, + 0x7b, 0x03, 0x3e, 0xb9, 0xa9, 0x21, 0xa4, 0x5b, + 0x99, 0xf3, 0x9b, 0xee, 0xfe, 0xa0, 0x37, 0xa2, + 0x1f, 0xe9, 0xd7, 0x4f, 0x95, 0x8b, 0x10, 0xe2, + }; + size_t len; + + len = 99; + CHECK(secp256k1_bulletproofs_generators_serialize(ctx, gens, gens_ser, &len)); + CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0); + + len = sizeof(gens_ser); + CHECK(secp256k1_bulletproofs_generators_serialize(ctx, gens, gens_ser, &len)); + CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0); + + secp256k1_bulletproofs_generators_destroy(ctx, gens); +} + void run_bulletproofs_tests(void) { - /* TODO */ + test_bulletproofs_generators_api(); + test_bulletproofs_generators_fixed(); } #endif From 17417d44f307a44e42468200458c3eb2c407b6b8 Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Mon, 21 Nov 2022 19:31:24 -0800 Subject: [PATCH 06/18] Add utilities from uncompressed Bulletproofs PR Add a transcript module for doing a generic Fiat Shamir --- src/modules/bulletproofs/Makefile.am.include | 4 +- .../bulletproofs_pp_transcript_impl.h | 40 ++++++++++++++++++ src/modules/bulletproofs/bulletproofs_util.h | 42 +++++++++++++++++++ src/modules/bulletproofs/main_impl.h | 13 +++--- src/modules/bulletproofs/tests_impl.h | 17 ++++++++ 5 files changed, 109 insertions(+), 7 deletions(-) create mode 100644 src/modules/bulletproofs/bulletproofs_pp_transcript_impl.h create mode 100644 src/modules/bulletproofs/bulletproofs_util.h diff --git a/src/modules/bulletproofs/Makefile.am.include b/src/modules/bulletproofs/Makefile.am.include index 6cd9fc3c8..6a0773b33 100644 --- a/src/modules/bulletproofs/Makefile.am.include +++ b/src/modules/bulletproofs/Makefile.am.include @@ -1,6 +1,8 @@ include_HEADERS += include/secp256k1_bulletproofs.h -noinst_HEADERS += src/modules/bulletproofs/tests_impl.h +noinst_HEADERS += src/modules/bulletproofs/bulletproofs_util.h noinst_HEADERS += src/modules/bulletproofs/main_impl.h +noinst_HEADERS += src/modules/bulletproofs/bulletproofs_pp_transcript_impl.h +noinst_HEADERS += src/modules/bulletproofs/tests_impl.h if USE_BENCHMARK noinst_PROGRAMS += bench_bulletproofs diff --git a/src/modules/bulletproofs/bulletproofs_pp_transcript_impl.h b/src/modules/bulletproofs/bulletproofs_pp_transcript_impl.h new file mode 100644 index 000000000..e8444e91e --- /dev/null +++ b/src/modules/bulletproofs/bulletproofs_pp_transcript_impl.h @@ -0,0 +1,40 @@ +/********************************************************************** + * Copyright (c) 2022 Sanket Kanjalkar * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ +#ifndef _SECP256K1_MODULE_BULLETPROOFS_PP_TRANSCRIPT_IMPL_ +#define _SECP256K1_MODULE_BULLETPROOFS_PP_TRANSCRIPT_IMPL_ + +#include "group.h" +#include "scalar.h" +#include "bulletproofs_util.h" + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("Bulletproofs_pp/v0/commitment")||SHA256("Bulletproofs_pp/v0/commitment"). + */ +static void secp256k1_bulletproofs_pp_sha256_tagged_commitment_init(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0x52fc8185ul; + sha->s[1] = 0x0e7debf0ul; + sha->s[2] = 0xb0967270ul; + sha->s[3] = 0x6f5abfe1ul; + sha->s[4] = 0x822bdec0ul; + sha->s[5] = 0x36db8beful; + sha->s[6] = 0x03d9e1f1ul; + sha->s[7] = 0x8a5cef6ful; + + sha->bytes = 64; +} + +/* Obtain a challenge scalar from the current transcript.*/ +static void secp256k1_bulletproofs_challenge_scalar(secp256k1_scalar* ch, const secp256k1_sha256 *transcript, uint64_t idx) { + unsigned char buf[32]; + secp256k1_sha256 sha = *transcript; + secp256k1_bulletproofs_le64(buf, idx); + secp256k1_sha256_write(&sha, buf, 8); + secp256k1_sha256_finalize(&sha, buf); + secp256k1_scalar_set_b32(ch, buf, NULL); +} + +#endif diff --git a/src/modules/bulletproofs/bulletproofs_util.h b/src/modules/bulletproofs/bulletproofs_util.h new file mode 100644 index 000000000..20d1c7483 --- /dev/null +++ b/src/modules/bulletproofs/bulletproofs_util.h @@ -0,0 +1,42 @@ +/********************************************************************** + * Copyright (c) 2020 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_BULLETPROOFS_UTIL_ +#define _SECP256K1_MODULE_BULLETPROOFS_UTIL_ + +#include "field.h" +#include "group.h" +#include "hash.h" + +/* Outputs a pair of points, amortizing the parity byte between them + * Assumes both points' coordinates have been normalized. + */ +static void secp256k1_bulletproofs_serialize_points(unsigned char *output, const secp256k1_ge *lpt, const secp256k1_ge *rpt) { + output[0] = (secp256k1_fe_is_odd(&lpt->y) << 1) + secp256k1_fe_is_odd(&rpt->y); + secp256k1_fe_get_b32(&output[1], &lpt->x); + secp256k1_fe_get_b32(&output[33], &rpt->x); +} + +/* Outputs a serialized point in compressed form. Returns 0 at point at infinity. +*/ +static int secp256k1_bulletproofs_serialize_pt(unsigned char *output, secp256k1_ge *lpt) { + size_t size; + return secp256k1_eckey_pubkey_serialize(lpt, output, &size, 1 /*compressed*/); +} + +/* little-endian encodes a uint64 */ +static void secp256k1_bulletproofs_le64(unsigned char *output, const uint64_t n) { + output[0] = n; + output[1] = n >> 8; + output[2] = n >> 16; + output[3] = n >> 24; + output[4] = n >> 32; + output[5] = n >> 40; + output[6] = n >> 48; + output[7] = n >> 56; +} + +#endif diff --git a/src/modules/bulletproofs/main_impl.h b/src/modules/bulletproofs/main_impl.h index ef0ac78cd..047094c70 100644 --- a/src/modules/bulletproofs/main_impl.h +++ b/src/modules/bulletproofs/main_impl.h @@ -7,18 +7,19 @@ #ifndef _SECP256K1_MODULE_BULLETPROOFS_MAIN_ #define _SECP256K1_MODULE_BULLETPROOFS_MAIN_ -#include "include/secp256k1_bulletproofs.h" -#include "include/secp256k1_generator.h" -#include "modules/generator/main_impl.h" /* for generator_{load, save} */ -#include "hash.h" -#include "util.h" - +/* this type must be completed before any of the modules/bulletproofs includes */ struct secp256k1_bulletproofs_generators { size_t n; /* n total generators; includes both G_i and H_i */ secp256k1_ge* gens; }; +#include "include/secp256k1_bulletproofs.h" +#include "include/secp256k1_generator.h" +#include "modules/generator/main_impl.h" /* for generator_{load, save} */ +#include "hash.h" +#include "util.h" + secp256k1_bulletproofs_generators *secp256k1_bulletproofs_generators_create(const secp256k1_context *ctx, size_t n) { secp256k1_bulletproofs_generators *ret; secp256k1_rfc6979_hmac_sha256 rng; diff --git a/src/modules/bulletproofs/tests_impl.h b/src/modules/bulletproofs/tests_impl.h index f75b7294e..930b35af9 100644 --- a/src/modules/bulletproofs/tests_impl.h +++ b/src/modules/bulletproofs/tests_impl.h @@ -7,6 +7,8 @@ #ifndef _SECP256K1_MODULE_BULLETPROOFS_TEST_ #define _SECP256K1_MODULE_BULLETPROOFS_TEST_ +#include "bulletproofs_pp_transcript_impl.h" + static void test_bulletproofs_generators_api(void) { /* The BP generator API requires no precomp */ secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); @@ -114,9 +116,24 @@ static void test_bulletproofs_generators_fixed(void) { secp256k1_bulletproofs_generators_destroy(ctx, gens); } +static void test_bulletproofs_pp_tagged_hash(void) { + unsigned char tag_data[29] = "Bulletproofs_pp/v0/commitment"; + secp256k1_sha256 sha; + secp256k1_sha256 sha_cached; + unsigned char output[32]; + unsigned char output_cached[32]; + + secp256k1_sha256_initialize_tagged(&sha, tag_data, sizeof(tag_data)); + secp256k1_bulletproofs_pp_sha256_tagged_commitment_init(&sha_cached); + secp256k1_sha256_finalize(&sha, output); + secp256k1_sha256_finalize(&sha_cached, output_cached); + CHECK(secp256k1_memcmp_var(output, output_cached, 32) == 0); +} + void run_bulletproofs_tests(void) { test_bulletproofs_generators_api(); test_bulletproofs_generators_fixed(); + test_bulletproofs_pp_tagged_hash(); } #endif From 420353d7da7793513621da3a5ad7479feaf76713 Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Mon, 30 Jan 2023 23:46:03 -0800 Subject: [PATCH 07/18] Add utilities for log2 --- src/modules/bulletproofs/bulletproofs_util.h | 13 +++++++++++++ src/modules/bulletproofs/tests_impl.h | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/modules/bulletproofs/bulletproofs_util.h b/src/modules/bulletproofs/bulletproofs_util.h index 20d1c7483..2bdae23fa 100644 --- a/src/modules/bulletproofs/bulletproofs_util.h +++ b/src/modules/bulletproofs/bulletproofs_util.h @@ -39,4 +39,17 @@ static void secp256k1_bulletproofs_le64(unsigned char *output, const uint64_t n) output[7] = n >> 56; } +/* Check if n is power of two*/ +static int secp256k1_is_power_of_two(size_t n) { + return n > 0 && (n & (n - 1)) == 0; +} + +/* Compute the log2 of n. If n is not a power of two, it returns the largest + * `k` such that 2^k <= n. Assumes n < 2^64. In Bulletproofs, this is bounded + * by len of input vectors which can be safely assumed to be less than 2^64. +*/ +static size_t secp256k1_bulletproofs_pp_log2(size_t n) { + return 64 - 1 - secp256k1_clz64_var((uint64_t)n); +} + #endif diff --git a/src/modules/bulletproofs/tests_impl.h b/src/modules/bulletproofs/tests_impl.h index 930b35af9..bec7c84f8 100644 --- a/src/modules/bulletproofs/tests_impl.h +++ b/src/modules/bulletproofs/tests_impl.h @@ -7,6 +7,10 @@ #ifndef _SECP256K1_MODULE_BULLETPROOFS_TEST_ #define _SECP256K1_MODULE_BULLETPROOFS_TEST_ +#include + +#include "include/secp256k1_bulletproofs.h" +#include "bulletproofs_util.h" #include "bulletproofs_pp_transcript_impl.h" static void test_bulletproofs_generators_api(void) { @@ -130,7 +134,23 @@ static void test_bulletproofs_pp_tagged_hash(void) { CHECK(secp256k1_memcmp_var(output, output_cached, 32) == 0); } +void test_log_exp(void) { + CHECK(secp256k1_is_power_of_two(0) == 0); + CHECK(secp256k1_is_power_of_two(1) == 1); + CHECK(secp256k1_is_power_of_two(2) == 1); + CHECK(secp256k1_is_power_of_two(64) == 1); + CHECK(secp256k1_is_power_of_two(63) == 0); + CHECK(secp256k1_is_power_of_two(256) == 1); + + CHECK(secp256k1_bulletproofs_pp_log2(1) == 0); + CHECK(secp256k1_bulletproofs_pp_log2(2) == 1); + CHECK(secp256k1_bulletproofs_pp_log2(255) == 7); + CHECK(secp256k1_bulletproofs_pp_log2(256) == 8); + CHECK(secp256k1_bulletproofs_pp_log2(257) == 8); +} + void run_bulletproofs_tests(void) { + test_log_exp(); test_bulletproofs_generators_api(); test_bulletproofs_generators_fixed(); test_bulletproofs_pp_tagged_hash(); From 412f8f66a08ef0e60644c7b5b22ee2a3d19ae3e8 Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Tue, 25 Oct 2022 23:29:26 -0700 Subject: [PATCH 08/18] Add utility functions required in norm argument --- src/modules/bulletproofs/Makefile.am.include | 1 + .../bulletproofs_pp_norm_product_impl.h | 81 +++++++++++++++++++ src/modules/bulletproofs/main.h | 13 +++ src/modules/bulletproofs/main_impl.h | 9 +-- src/modules/bulletproofs/tests_impl.h | 39 +++++++++ 5 files changed, 136 insertions(+), 7 deletions(-) create mode 100644 src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h create mode 100644 src/modules/bulletproofs/main.h diff --git a/src/modules/bulletproofs/Makefile.am.include b/src/modules/bulletproofs/Makefile.am.include index 6a0773b33..cfd0916d2 100644 --- a/src/modules/bulletproofs/Makefile.am.include +++ b/src/modules/bulletproofs/Makefile.am.include @@ -2,6 +2,7 @@ include_HEADERS += include/secp256k1_bulletproofs.h noinst_HEADERS += src/modules/bulletproofs/bulletproofs_util.h noinst_HEADERS += src/modules/bulletproofs/main_impl.h noinst_HEADERS += src/modules/bulletproofs/bulletproofs_pp_transcript_impl.h +noinst_HEADERS += src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h noinst_HEADERS += src/modules/bulletproofs/tests_impl.h if USE_BENCHMARK diff --git a/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h b/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h new file mode 100644 index 000000000..1e17ed34b --- /dev/null +++ b/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h @@ -0,0 +1,81 @@ +/********************************************************************** + * Copyright (c) 2020 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_BULLETPROOFS_PP_NORM_PRODUCT_ +#define _SECP256K1_MODULE_BULLETPROOFS_PP_NORM_PRODUCT_ + +#include "group.h" +#include "scalar.h" +#include "ecmult.h" +#include "ecmult_gen.h" +#include "hash.h" + +#include "modules/bulletproofs/main.h" +#include "modules/bulletproofs/bulletproofs_util.h" + +/* Computes the inner product of two vectors of scalars + * with elements starting from offset a and offset b + * skipping elements according to specified step. + * Returns: Sum_{i=0..len-1}(a[offset_a + i*step] * b[offset_b + i*step]) */ +static int secp256k1_scalar_inner_product( + secp256k1_scalar* res, + const secp256k1_scalar* a_vec, + const size_t a_offset, + const secp256k1_scalar* b_vec, + const size_t b_offset, + const size_t step, + const size_t len +) { + size_t i; + secp256k1_scalar_set_int(res, 0); + for (i = 0; i < len; i++) { + secp256k1_scalar term; + secp256k1_scalar_mul(&term, &a_vec[a_offset + step*i], &b_vec[b_offset + step*i]); + secp256k1_scalar_add(res, res, &term); + } + return 1; +} + +/* Computes the q-weighted inner product of two vectors of scalars + * for elements starting from offset a and offset b respectively with the + * given step. + * Returns: Sum_{i=0..len-1}(a[offset_a + step*i] * b[offset_b2 + step*i]*q^(i+1)) */ +static int secp256k1_weighted_scalar_inner_product( + secp256k1_scalar* res, + const secp256k1_scalar* a_vec, + const size_t a_offset, + const secp256k1_scalar* b_vec, + const size_t b_offset, + const size_t step, + const size_t len, + const secp256k1_scalar* q +) { + secp256k1_scalar q_pow; + size_t i; + secp256k1_scalar_set_int(res, 0); + q_pow = *q; + for (i = 0; i < len; i++) { + secp256k1_scalar term; + secp256k1_scalar_mul(&term, &a_vec[a_offset + step*i], &b_vec[b_offset + step*i]); + secp256k1_scalar_mul(&term, &term, &q_pow); + secp256k1_scalar_mul(&q_pow, &q_pow, q); + secp256k1_scalar_add(res, res, &term); + } + return 1; +} + +/* Compute the powers of r as r, r^2, r^4 ... r^(2^(n-1)) */ +static void secp256k1_bulletproofs_powers_of_r(secp256k1_scalar *powers, const secp256k1_scalar *r, size_t n) { + size_t i; + if (n == 0) { + return; + } + powers[0] = *r; + for (i = 1; i < n; i++) { + secp256k1_scalar_sqr(&powers[i], &powers[i - 1]); + } +} +#endif diff --git a/src/modules/bulletproofs/main.h b/src/modules/bulletproofs/main.h new file mode 100644 index 000000000..4174102a6 --- /dev/null +++ b/src/modules/bulletproofs/main.h @@ -0,0 +1,13 @@ +#ifndef SECP256K1_MODULE_BULLETPROOFS_MAIN_H +#define SECP256K1_MODULE_BULLETPROOFS_MAIN_H + +/* this type must be completed before any of the modules/bulletproofs includes */ +struct secp256k1_bulletproofs_generators { + size_t n; + /* n total generators; includes both G_i and H_i */ + /* For BP++, the generators are G_i from [0..(n - 8)] and the last 8 values + are generators are for H_i */ + secp256k1_ge* gens; +}; + +#endif diff --git a/src/modules/bulletproofs/main_impl.h b/src/modules/bulletproofs/main_impl.h index 047094c70..f87b9876b 100644 --- a/src/modules/bulletproofs/main_impl.h +++ b/src/modules/bulletproofs/main_impl.h @@ -7,18 +7,13 @@ #ifndef _SECP256K1_MODULE_BULLETPROOFS_MAIN_ #define _SECP256K1_MODULE_BULLETPROOFS_MAIN_ -/* this type must be completed before any of the modules/bulletproofs includes */ -struct secp256k1_bulletproofs_generators { - size_t n; - /* n total generators; includes both G_i and H_i */ - secp256k1_ge* gens; -}; - #include "include/secp256k1_bulletproofs.h" #include "include/secp256k1_generator.h" #include "modules/generator/main_impl.h" /* for generator_{load, save} */ #include "hash.h" #include "util.h" +#include "modules/bulletproofs/main.h" +#include "modules/bulletproofs/bulletproofs_pp_norm_product_impl.h" secp256k1_bulletproofs_generators *secp256k1_bulletproofs_generators_create(const secp256k1_context *ctx, size_t n) { secp256k1_bulletproofs_generators *ret; diff --git a/src/modules/bulletproofs/tests_impl.h b/src/modules/bulletproofs/tests_impl.h index bec7c84f8..e3daead44 100644 --- a/src/modules/bulletproofs/tests_impl.h +++ b/src/modules/bulletproofs/tests_impl.h @@ -10,6 +10,7 @@ #include #include "include/secp256k1_bulletproofs.h" +#include "bulletproofs_pp_norm_product_impl.h" #include "bulletproofs_util.h" #include "bulletproofs_pp_transcript_impl.h" @@ -149,8 +150,46 @@ void test_log_exp(void) { CHECK(secp256k1_bulletproofs_pp_log2(257) == 8); } +void test_norm_util_helpers(void) { + secp256k1_scalar a_vec[4], b_vec[4], r_pows[4], res, res2, q, r; + int i; + /* a = {1, 2, 3, 4} b = {5, 6, 7, 8}, q = 4, r = 2 */ + for (i = 0; i < 4; i++) { + secp256k1_scalar_set_int(&a_vec[i], i + 1); + secp256k1_scalar_set_int(&b_vec[i], i + 5); + } + secp256k1_scalar_set_int(&q, 4); + secp256k1_scalar_set_int(&r, 2); + secp256k1_scalar_inner_product(&res, a_vec, 0, b_vec, 0, 1, 4); + secp256k1_scalar_set_int(&res2, 70); + CHECK(secp256k1_scalar_eq(&res2, &res) == 1); + + secp256k1_scalar_inner_product(&res, a_vec, 0, b_vec, 1, 2, 2); + secp256k1_scalar_set_int(&res2, 30); + CHECK(secp256k1_scalar_eq(&res2, &res) == 1); + + secp256k1_scalar_inner_product(&res, a_vec, 1, b_vec, 0, 2, 2); + secp256k1_scalar_set_int(&res2, 38); + CHECK(secp256k1_scalar_eq(&res2, &res) == 1); + + secp256k1_scalar_inner_product(&res, a_vec, 1, b_vec, 1, 2, 2); + secp256k1_scalar_set_int(&res2, 44); + CHECK(secp256k1_scalar_eq(&res2, &res) == 1); + + secp256k1_weighted_scalar_inner_product(&res, a_vec, 0, a_vec, 0, 1, 4, &q); + secp256k1_scalar_set_int(&res2, 4740); /*i*i*4^(i+1) */ + CHECK(secp256k1_scalar_eq(&res2, &res) == 1); + + secp256k1_bulletproofs_powers_of_r(r_pows, &r, 4); + secp256k1_scalar_set_int(&res, 2); CHECK(secp256k1_scalar_eq(&res, &r_pows[0])); + secp256k1_scalar_set_int(&res, 4); CHECK(secp256k1_scalar_eq(&res, &r_pows[1])); + secp256k1_scalar_set_int(&res, 16); CHECK(secp256k1_scalar_eq(&res, &r_pows[2])); + secp256k1_scalar_set_int(&res, 256); CHECK(secp256k1_scalar_eq(&res, &r_pows[3])); +} + void run_bulletproofs_tests(void) { test_log_exp(); + test_norm_util_helpers(); test_bulletproofs_generators_api(); test_bulletproofs_generators_fixed(); test_bulletproofs_pp_tagged_hash(); From 8638f0e0cecad113e11b826a41bed1fe7a8d3b85 Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Wed, 26 Oct 2022 00:08:35 -0700 Subject: [PATCH 09/18] Add internal BP++ commit API --- .../bulletproofs_pp_norm_product_impl.h | 66 +++++++++++++++++++ src/modules/bulletproofs/bulletproofs_util.h | 1 + 2 files changed, 67 insertions(+) diff --git a/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h b/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h index 1e17ed34b..f366fea29 100644 --- a/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h +++ b/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h @@ -78,4 +78,70 @@ static void secp256k1_bulletproofs_powers_of_r(secp256k1_scalar *powers, const s secp256k1_scalar_sqr(&powers[i], &powers[i - 1]); } } + +typedef struct ecmult_bp_commit_cb_data { + const secp256k1_scalar *n; + const secp256k1_ge *g; + const secp256k1_scalar *l; + size_t g_len; +} ecmult_bp_commit_cb_data; + +static int ecmult_bp_commit_cb(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + ecmult_bp_commit_cb_data *data = (ecmult_bp_commit_cb_data*) cbdata; + *pt = data->g[idx]; + if (idx < data->g_len) { + *sc = data->n[idx]; + } else { + *sc = data->l[idx - data->g_len]; + } + return 1; +} + +/* Create a commitment `commit` = vG + n_vec*G_vec + l_vec*H_vec where + v = |n_vec*n_vec|_q + . |w|_q denotes q-weighted norm of w and + denotes inner product of l and r. +*/ +static int secp256k1_bulletproofs_commit( + const secp256k1_context* ctx, + secp256k1_scratch_space* scratch, + secp256k1_ge* commit, + const secp256k1_bulletproofs_generators* g_vec, + const secp256k1_scalar* n_vec, + size_t n_vec_len, + const secp256k1_scalar* l_vec, + size_t l_vec_len, + const secp256k1_scalar* c_vec, + size_t c_vec_len, + const secp256k1_scalar* q +) { + secp256k1_scalar v, l_c; + /* First n_vec_len generators are Gs, rest are Hs*/ + VERIFY_CHECK(g_vec->n == (n_vec_len + l_vec_len)); + VERIFY_CHECK(l_vec_len == c_vec_len); + + /* It is possible to extend to support n_vec and c_vec to not be power of + two. For the initial iterations of the code, we stick to powers of two for simplicity.*/ + VERIFY_CHECK(secp256k1_is_power_of_two(n_vec_len)); + VERIFY_CHECK(secp256k1_is_power_of_two(c_vec_len)); + + /* Compute v = n_vec*n_vec*q + l_vec*c_vec */ + secp256k1_weighted_scalar_inner_product(&v, n_vec, 0 /*a offset */, n_vec, 0 /*b offset*/, 1 /*step*/, n_vec_len, q); + secp256k1_scalar_inner_product(&l_c, l_vec, 0 /*a offset */, c_vec, 0 /*b offset*/, 1 /*step*/, l_vec_len); + secp256k1_scalar_add(&v, &v, &l_c); + + { + ecmult_bp_commit_cb_data data; + secp256k1_gej commitj; + data.g = g_vec->gens; + data.n = n_vec; + data.l = l_vec; + data.g_len = n_vec_len; + + if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &commitj, &v, ecmult_bp_commit_cb, (void*) &data, n_vec_len + l_vec_len)) { + return 0; + } + secp256k1_ge_set_gej_var(commit, &commitj); + } + return 1; +} #endif diff --git a/src/modules/bulletproofs/bulletproofs_util.h b/src/modules/bulletproofs/bulletproofs_util.h index 2bdae23fa..07f6fc62b 100644 --- a/src/modules/bulletproofs/bulletproofs_util.h +++ b/src/modules/bulletproofs/bulletproofs_util.h @@ -10,6 +10,7 @@ #include "field.h" #include "group.h" #include "hash.h" +#include "eckey.h" /* Outputs a pair of points, amortizing the parity byte between them * Assumes both points' coordinates have been normalized. From d9145455bb741c9f363c2a085abd0109e63c961f Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Wed, 26 Oct 2022 00:48:27 -0700 Subject: [PATCH 10/18] Add bulletproofs++ norm argument prove API --- .../bulletproofs_pp_norm_product_impl.h | 215 ++++++++++++++++++ 1 file changed, 215 insertions(+) diff --git a/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h b/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h index f366fea29..1f7b16f1c 100644 --- a/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h +++ b/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h @@ -15,6 +15,7 @@ #include "modules/bulletproofs/main.h" #include "modules/bulletproofs/bulletproofs_util.h" +#include "modules/bulletproofs/bulletproofs_pp_transcript_impl.h" /* Computes the inner product of two vectors of scalars * with elements starting from offset a and offset b @@ -144,4 +145,218 @@ static int secp256k1_bulletproofs_commit( } return 1; } + +typedef struct ecmult_x_cb_data { + const secp256k1_scalar *n; + const secp256k1_ge *g; + const secp256k1_scalar *l; + const secp256k1_scalar *r; + const secp256k1_scalar *r_inv; + size_t G_GENS_LEN; /* Figure out initialization syntax so that this can also be const */ + size_t n_len; +} ecmult_x_cb_data; + +static int ecmult_x_cb(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + ecmult_x_cb_data *data = (ecmult_x_cb_data*) cbdata; + if (idx < data->n_len) { + if (idx % 2 == 0) { + secp256k1_scalar_mul(sc, &data->n[idx + 1], data->r); + *pt = data->g[idx]; + } else { + secp256k1_scalar_mul(sc, &data->n[idx - 1], data->r_inv); + *pt = data->g[idx]; + } + } else { + idx -= data->n_len; + if (idx % 2 == 0) { + *sc = data->l[idx + 1]; + *pt = data->g[data->G_GENS_LEN + idx]; + } else { + *sc = data->l[idx - 1]; + *pt = data->g[data->G_GENS_LEN + idx]; + } + } + return 1; +} + +typedef struct ecmult_r_cb_data { + const secp256k1_scalar *n1; + const secp256k1_ge *g1; + const secp256k1_scalar *l1; + size_t G_GENS_LEN; + size_t n_len; +} ecmult_r_cb_data; + +static int ecmult_r_cb(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + ecmult_r_cb_data *data = (ecmult_r_cb_data*) cbdata; + if (idx < data->n_len) { + *sc = data->n1[2*idx + 1]; + *pt = data->g1[2*idx + 1]; + } else { + idx -= data->n_len; + *sc = data->l1[2*idx + 1]; + *pt = data->g1[data->G_GENS_LEN + 2*idx + 1]; + } + return 1; +} + +/* Recursively compute the norm argument proof satisfying the relation + * _q + = v for some commitment + * C = v*G + + . _q is the weighted inner + * product of x with itself, where the weights are the first n powers of q. + * _q = q*x_1^2 + q^2*x_2^2 + q^3*x_3^2 + ... + q^n*x_n^2. + * The API computes q as square of the r challenge (`r^2`). + * + * The norm argument is not zero knowledge and does not operate on any secret data. + * Thus the following code uses variable time operations while computing the proof. + * This function also modifies the values of n_vec, l_vec, c_vec and g_vec. The caller + * is expected to copy these values if they need to be preserved. + * + * Assumptions: This function is intended to be used in conjunction with the + * some parent protocol. To use this norm protocol in a standalone manner, the user + * should add the commitment, generators and initial public data to the transcript hash. +*/ +static int secp256k1_bulletproofs_pp_rangeproof_norm_product_prove( + const secp256k1_context* ctx, + secp256k1_scratch_space* scratch, + unsigned char* proof, + size_t *proof_len, + secp256k1_sha256* transcript, /* Transcript hash of the parent protocol */ + const secp256k1_scalar* r, + secp256k1_ge* g_vec, + size_t g_vec_len, + secp256k1_scalar* n_vec, + size_t n_vec_len, + secp256k1_scalar* l_vec, + size_t l_vec_len, + secp256k1_scalar* c_vec, + size_t c_vec_len +) { + secp256k1_scalar q_f, r_f = *r; + size_t proof_idx = 0; + ecmult_x_cb_data x_cb_data; + ecmult_r_cb_data r_cb_data; + size_t g_len = n_vec_len, h_len = l_vec_len; + const size_t G_GENS_LEN = g_len; + size_t log_g_len = secp256k1_bulletproofs_pp_log2(g_len), log_h_len = secp256k1_bulletproofs_pp_log2(h_len); + size_t num_rounds = log_g_len > log_h_len ? log_g_len : log_h_len; + + /* Check proof sizes.*/ + VERIFY_CHECK(*proof_len >= 65 * num_rounds + 64); + VERIFY_CHECK(g_vec_len == (n_vec_len + l_vec_len) && l_vec_len == c_vec_len); + VERIFY_CHECK(secp256k1_is_power_of_two(n_vec_len) && secp256k1_is_power_of_two(c_vec_len)); + + x_cb_data.n = n_vec; + x_cb_data.g = g_vec; + x_cb_data.l = l_vec; + x_cb_data.G_GENS_LEN = G_GENS_LEN; + + r_cb_data.n1 = n_vec; + r_cb_data.g1 = g_vec; + r_cb_data.l1 = l_vec; + r_cb_data.G_GENS_LEN = G_GENS_LEN; + secp256k1_scalar_sqr(&q_f, &r_f); + + + while (g_len > 1 || h_len > 1) { + size_t i, num_points; + secp256k1_scalar q_sq, r_inv, c0_l1, c1_l0, x_v, c1_l1, r_v; + secp256k1_gej rj, xj; + secp256k1_ge r_ge, x_ge; + secp256k1_scalar e; + + secp256k1_scalar_inverse_var(&r_inv, &r_f); + secp256k1_scalar_sqr(&q_sq, &q_f); + + /* Compute the X commitment X = WIP(r_inv*n0,n1)_q2 * g + r + */ + secp256k1_scalar_inner_product(&c0_l1, c_vec, 0, l_vec, 1, 2, h_len/2); + secp256k1_scalar_inner_product(&c1_l0, c_vec, 1, l_vec, 0, 2, h_len/2); + secp256k1_weighted_scalar_inner_product(&x_v, n_vec, 0, n_vec, 1, 2, g_len/2, &q_sq); + secp256k1_scalar_mul(&x_v, &x_v, &r_inv); + secp256k1_scalar_add(&x_v, &x_v, &x_v); + secp256k1_scalar_add(&x_v, &x_v, &c0_l1); + secp256k1_scalar_add(&x_v, &x_v, &c1_l0); + + x_cb_data.r = &r_f; + x_cb_data.r_inv = &r_inv; + x_cb_data.n_len = g_len >= 2 ? g_len : 0; + num_points = x_cb_data.n_len + (h_len >= 2 ? h_len : 0); + + if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &xj, &x_v, ecmult_x_cb, (void*)&x_cb_data, num_points)) { + return 0; + } + + secp256k1_weighted_scalar_inner_product(&r_v, n_vec, 1, n_vec, 1, 2, g_len/2, &q_sq); + secp256k1_scalar_inner_product(&c1_l1, c_vec, 1, l_vec, 1, 2, h_len/2); + secp256k1_scalar_add(&r_v, &r_v, &c1_l1); + + r_cb_data.n_len = g_len/2; + num_points = r_cb_data.n_len + h_len/2; + if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &rj, &r_v, ecmult_r_cb, (void*)&r_cb_data, num_points)) { + return 0; + } + + /* We only fail here because we cannot serialize points at infinity. */ + if (secp256k1_gej_is_infinity(&xj) || secp256k1_gej_is_infinity(&rj)) { + return 0; + } + + secp256k1_ge_set_gej_var(&x_ge, &xj); + secp256k1_fe_normalize_var(&x_ge.x); + secp256k1_fe_normalize_var(&x_ge.y); + secp256k1_ge_set_gej_var(&r_ge, &rj); + secp256k1_fe_normalize_var(&r_ge.x); + secp256k1_fe_normalize_var(&r_ge.y); + secp256k1_bulletproofs_serialize_points(&proof[proof_idx], &x_ge, &r_ge); + proof_idx += 65; + + /* Obtain challenge e for the the next round */ + secp256k1_sha256_write(transcript, &proof[proof_idx - 65], 65); + secp256k1_bulletproofs_challenge_scalar(&e, transcript, 0); + + if (g_len > 1) { + for (i = 0; i < g_len; i = i + 2) { + secp256k1_scalar nl, nr; + secp256k1_gej gl, gr; + secp256k1_scalar_mul(&nl, &n_vec[i], &r_inv); + secp256k1_scalar_mul(&nr, &n_vec[i + 1], &e); + secp256k1_scalar_add(&n_vec[i/2], &nl, &nr); + + secp256k1_gej_set_ge(&gl, &g_vec[i]); + secp256k1_ecmult(&gl, &gl, &r_f, NULL); + secp256k1_gej_set_ge(&gr, &g_vec[i + 1]); + secp256k1_ecmult(&gr, &gr, &e, NULL); + secp256k1_gej_add_var(&gl, &gl, &gr, NULL); + secp256k1_ge_set_gej_var(&g_vec[i/2], &gl); + } + } + + if (h_len > 1) { + for (i = 0; i < h_len; i = i + 2) { + secp256k1_scalar temp1; + secp256k1_gej grj; + secp256k1_scalar_mul(&temp1, &c_vec[i + 1], &e); + secp256k1_scalar_add(&c_vec[i/2], &c_vec[i], &temp1); + + secp256k1_scalar_mul(&temp1, &l_vec[i + 1], &e); + secp256k1_scalar_add(&l_vec[i/2], &l_vec[i], &temp1); + + secp256k1_gej_set_ge(&grj, &g_vec[G_GENS_LEN + i + 1]); + secp256k1_ecmult(&grj, &grj, &e, NULL); + secp256k1_gej_add_ge_var(&grj, &grj, &g_vec[G_GENS_LEN + i], NULL); + secp256k1_ge_set_gej_var(&g_vec[G_GENS_LEN + i/2], &grj); + } + } + g_len = g_len / 2; + h_len = h_len / 2; + r_f = q_f; + q_f = q_sq; + } + + secp256k1_scalar_get_b32(&proof[proof_idx], &n_vec[0]); + secp256k1_scalar_get_b32(&proof[proof_idx + 32], &l_vec[0]); + proof_idx += 64; + *proof_len = proof_idx; + return 1; +} #endif From 46c7391154a7325133f97f9ec816ccf98ba76ede Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Wed, 26 Oct 2022 00:18:14 -0700 Subject: [PATCH 11/18] Add norm argument verify API --- .../bulletproofs_pp_norm_product_impl.h | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h b/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h index 1f7b16f1c..c380bba19 100644 --- a/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h +++ b/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h @@ -359,4 +359,190 @@ static int secp256k1_bulletproofs_pp_rangeproof_norm_product_prove( *proof_len = proof_idx; return 1; } + +typedef struct ec_mult_verify_cb_data1 { + const unsigned char *proof; + const secp256k1_ge *commit; + const secp256k1_scalar *challenges; +} ec_mult_verify_cb_data1; + +static int ec_mult_verify_cb1(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + ec_mult_verify_cb_data1 *data = (ec_mult_verify_cb_data1*) cbdata; + if (idx == 0) { + *pt = *data->commit; + secp256k1_scalar_set_int(sc, 1); + return 1; + } + idx -= 1; + if (idx % 2 == 0) { + unsigned char pk_buf[33]; + idx /= 2; + *sc = data->challenges[idx]; + pk_buf[0] = 2 | (data->proof[65*idx] >> 1); + memcpy(&pk_buf[1], &data->proof[65*idx + 1], 32); + if (!secp256k1_eckey_pubkey_parse(pt, pk_buf, sizeof(pk_buf))) { + return 0; + } + } else { + unsigned char pk_buf[33]; + secp256k1_scalar neg_one; + idx /= 2; + secp256k1_scalar_set_int(&neg_one, 1); + secp256k1_scalar_negate(&neg_one, &neg_one); + *sc = data->challenges[idx]; + secp256k1_scalar_sqr(sc, sc); + secp256k1_scalar_add(sc, sc, &neg_one); + pk_buf[0] = 2 | data->proof[65*idx]; + memcpy(&pk_buf[1], &data->proof[65*idx + 33], 32); + if (!secp256k1_eckey_pubkey_parse(pt, pk_buf, sizeof(pk_buf))) { + return 0; + } + } + return 1; +} + +typedef struct ec_mult_verify_cb_data2 { + const secp256k1_scalar *s_g; + const secp256k1_scalar *s_h; + const secp256k1_ge *g_vec; + size_t g_vec_len; +} ec_mult_verify_cb_data2; + +static int ec_mult_verify_cb2(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + ec_mult_verify_cb_data2 *data = (ec_mult_verify_cb_data2*) cbdata; + if (idx < data->g_vec_len) { + *sc = data->s_g[idx]; + } else { + *sc = data->s_h[idx - data->g_vec_len]; + } + *pt = data->g_vec[idx]; + return 1; +} + +/* Verify the proof. This function modifies the generators, c_vec and the challenge r. The + caller should make sure to back them up if they need to be reused. +*/ +static int secp256k1_bulletproofs_pp_rangeproof_norm_product_verify( + const secp256k1_context* ctx, + secp256k1_scratch_space* scratch, + const unsigned char* proof, + size_t proof_len, + secp256k1_sha256* transcript, + const secp256k1_scalar* r, + const secp256k1_bulletproofs_generators* g_vec, + size_t g_len, + const secp256k1_scalar* c_vec, + size_t c_vec_len, + const secp256k1_ge* commit +) { + secp256k1_scalar r_f, q_f, v, n, l, r_inv, h_c; + secp256k1_scalar *es, *s_g, *s_h, *r_inv_pows; + secp256k1_gej res1, res2; + size_t i = 0, scratch_checkpoint; + int overflow; + size_t log_g_len = secp256k1_bulletproofs_pp_log2(g_len), log_h_len = secp256k1_bulletproofs_pp_log2(c_vec_len); + size_t n_rounds = log_g_len > log_h_len ? log_g_len : log_h_len; + size_t h_len = c_vec_len; + + if (g_vec->n != (h_len + g_len) || (proof_len != 65 * n_rounds + 64)) { + return 0; + } + + if (!secp256k1_is_power_of_two(g_len) || !secp256k1_is_power_of_two(h_len)) { + return 0; + } + + secp256k1_scalar_set_b32(&n, &proof[n_rounds*65], &overflow); /* n */ + if (overflow) return 0; + secp256k1_scalar_set_b32(&l, &proof[n_rounds*65 + 32], &overflow); /* l */ + if (overflow) return 0; + if (secp256k1_scalar_is_zero(r)) return 0; + + /* Collect the challenges in a new vector */ + scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch); + es = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, n_rounds * sizeof(secp256k1_scalar)); + s_g = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, g_len * sizeof(secp256k1_scalar)); + s_h = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar)); + r_inv_pows = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, log_g_len * sizeof(secp256k1_scalar)); + if (es == NULL || s_g == NULL || s_h == NULL || r_inv_pows == NULL) { + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); + return 0; + } + + /* Compute powers of r_inv. Later used in g_factor computations*/ + secp256k1_scalar_inverse_var(&r_inv, r); + secp256k1_bulletproofs_powers_of_r(r_inv_pows, &r_inv, log_g_len); + + /* Compute r_f = r^(2^log_g_len) */ + r_f = *r; + for (i = 0; i < log_g_len; i++) { + secp256k1_scalar_sqr(&r_f, &r_f); + } + + for (i = 0; i < n_rounds; i++) { + secp256k1_scalar e; + secp256k1_sha256_write(transcript, &proof[i * 65], 65); + secp256k1_bulletproofs_challenge_scalar(&e, transcript, 0); + es[i] = e; + } + /* s_g[0] = n * \prod_{j=0}^{log_g_len - 1} r^(2^j) + * = n * r^(2^log_g_len - 1) + * = n * r_f * r_inv */ + secp256k1_scalar_mul(&s_g[0], &n, &r_f); + secp256k1_scalar_mul(&s_g[0], &s_g[0], &r_inv); + for (i = 1; i < g_len; i++) { + size_t log_i = secp256k1_bulletproofs_pp_log2(i); + size_t nearest_pow_of_two = (size_t)1 << log_i; + /* This combines the two multiplications of challenges and r_invs in a + * single loop. + * s_g[i] = s_g[i - nearest_pow_of_two] + * * e[log_i] * r_inv^(2^log_i) */ + secp256k1_scalar_mul(&s_g[i], &s_g[i - nearest_pow_of_two], &es[log_i]); + secp256k1_scalar_mul(&s_g[i], &s_g[i], &r_inv_pows[log_i]); + } + s_h[0] = l; + secp256k1_scalar_set_int(&h_c, 0); + for (i = 1; i < h_len; i++) { + size_t log_i = secp256k1_bulletproofs_pp_log2(i); + size_t nearest_pow_of_two = (size_t)1 << log_i; + secp256k1_scalar_mul(&s_h[i], &s_h[i - nearest_pow_of_two], &es[log_i]); + } + secp256k1_scalar_inner_product(&h_c, c_vec, 0 /* a_offset */ , s_h, 0 /* b_offset */, 1 /* step */, h_len); + /* Compute v = n*n*q_f + l*h_c where q_f = r_f^2 */ + secp256k1_scalar_sqr(&q_f, &r_f); + secp256k1_scalar_mul(&v, &n, &n); + secp256k1_scalar_mul(&v, &v, &q_f); + secp256k1_scalar_add(&v, &v, &h_c); + + { + ec_mult_verify_cb_data1 data; + data.proof = proof; + data.commit = commit; + data.challenges = es; + + if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &res1, NULL, ec_mult_verify_cb1, &data, 2*n_rounds + 1)) { + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); + return 0; + } + } + { + ec_mult_verify_cb_data2 data; + data.g_vec = g_vec->gens; + data.g_vec_len = g_len; + data.s_g = s_g; + data.s_h = s_h; + + if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &res2, &v, ec_mult_verify_cb2, &data, g_len + h_len)) { + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); + return 0; + } + } + + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); + + /* res1 and res2 should be equal. Could not find a simpler way to compare them */ + secp256k1_gej_neg(&res1, &res1); + secp256k1_gej_add_var(&res1, &res1, &res2, NULL); + return secp256k1_gej_is_infinity(&res1); +} #endif From 25745164835669d71e86863d1de747f26480ec08 Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Wed, 26 Oct 2022 00:20:08 -0700 Subject: [PATCH 12/18] Add testcases for bulletproofs++ norm arugment --- src/modules/bulletproofs/tests_impl.h | 187 ++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) diff --git a/src/modules/bulletproofs/tests_impl.h b/src/modules/bulletproofs/tests_impl.h index e3daead44..ff7519f25 100644 --- a/src/modules/bulletproofs/tests_impl.h +++ b/src/modules/bulletproofs/tests_impl.h @@ -187,12 +187,199 @@ void test_norm_util_helpers(void) { secp256k1_scalar_set_int(&res, 256); CHECK(secp256k1_scalar_eq(&res, &r_pows[3])); } +static void secp256k1_norm_arg_commit_initial_data( + secp256k1_sha256* transcript, + const secp256k1_scalar* r, + const secp256k1_bulletproofs_generators* gens_vec, + size_t g_len, /* Same as n_vec_len, g_len + c_vec_len = gens->n */ + const secp256k1_scalar* c_vec, + size_t c_vec_len, + const secp256k1_ge* commit +) { + /* Commit to the initial public values */ + unsigned char ser_commit[33], ser_scalar[32], ser_le64[8]; + size_t i; + secp256k1_ge comm = *commit; + secp256k1_bulletproofs_pp_sha256_tagged_commitment_init(transcript); + secp256k1_fe_normalize(&comm.x); + secp256k1_fe_normalize(&comm.y); + CHECK(secp256k1_bulletproofs_serialize_pt(&ser_commit[0], &comm)); + secp256k1_sha256_write(transcript, ser_commit, 33); + secp256k1_scalar_get_b32(ser_scalar, r); + secp256k1_sha256_write(transcript, ser_scalar, 32); + secp256k1_bulletproofs_le64(ser_le64, g_len); + secp256k1_sha256_write(transcript, ser_le64, 8); + secp256k1_bulletproofs_le64(ser_le64, gens_vec->n); + secp256k1_sha256_write(transcript, ser_le64, 8); + for (i = 0; i < gens_vec->n; i++) { + secp256k1_fe_normalize(&gens_vec->gens[i].x); + secp256k1_fe_normalize(&gens_vec->gens[i].y); + CHECK(secp256k1_bulletproofs_serialize_pt(&ser_commit[0], &gens_vec->gens[i])); + secp256k1_sha256_write(transcript, ser_commit, 33); + } + secp256k1_bulletproofs_le64(ser_le64, c_vec_len); + secp256k1_sha256_write(transcript, ser_le64, 8); + for (i = 0; i < c_vec_len; i++) { + secp256k1_scalar_get_b32(ser_scalar, &c_vec[i]); + secp256k1_sha256_write(transcript, ser_scalar, 32); + } +} + +/* A complete norm argument. In contrast to secp256k1_bulletproofs_pp_rangeproof_norm_product_prove, this is meant + to be used as a standalone norm argument. + This is a simple wrapper around secp256k1_bulletproofs_pp_rangeproof_norm_product_prove + that also commits to the initial public values used in the protocol. In this case, these public + values are commitment. +*/ +static int secp256k1_norm_arg_prove( + secp256k1_scratch_space* scratch, + unsigned char* proof, + size_t *proof_len, + const secp256k1_scalar* r, + const secp256k1_bulletproofs_generators* gens_vec, + const secp256k1_scalar* n_vec, + size_t n_vec_len, + const secp256k1_scalar* l_vec, + size_t l_vec_len, + const secp256k1_scalar* c_vec, + size_t c_vec_len, + const secp256k1_ge* commit +) { + secp256k1_scalar *ns, *ls, *cs; + secp256k1_ge *gs, comm = *commit; + size_t scratch_checkpoint; + size_t g_len = n_vec_len, h_len = l_vec_len; + int res; + secp256k1_sha256 transcript; + + scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch); + ns = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, g_len * sizeof(secp256k1_scalar)); + ls = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar)); + cs = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar)); + gs = (secp256k1_ge*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, (g_len + h_len) * sizeof(secp256k1_ge)); + if (ns == NULL || ls == NULL || cs == NULL || gs == NULL) { + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); + return 0; + } + memcpy(ns, n_vec, g_len * sizeof(secp256k1_scalar)); + memcpy(ls, l_vec, h_len * sizeof(secp256k1_scalar)); + memcpy(cs, c_vec, h_len * sizeof(secp256k1_scalar)); + memcpy(gs, gens_vec->gens, (g_len + h_len) * sizeof(secp256k1_ge)); + + /* Commit to the initial public values */ + secp256k1_norm_arg_commit_initial_data(&transcript, r, gens_vec, g_len, c_vec, c_vec_len, &comm); + + res = secp256k1_bulletproofs_pp_rangeproof_norm_product_prove( + ctx, + scratch, + proof, + proof_len, + &transcript, /* Transcript hash of the parent protocol */ + r, + gs, + gens_vec->n, + ns, + n_vec_len, + ls, + l_vec_len, + cs, + c_vec_len + ); + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); + return res; +} + +/* Verify the proof */ +static int secp256k1_norm_arg_verify( + secp256k1_scratch_space* scratch, + const unsigned char* proof, + size_t proof_len, + const secp256k1_scalar* r, + const secp256k1_bulletproofs_generators* gens_vec, + size_t g_len, + const secp256k1_scalar* c_vec, + size_t c_vec_len, + const secp256k1_ge* commit +) { + secp256k1_ge comm = *commit; + int res; + secp256k1_sha256 transcript; + + /* Commit to the initial public values */ + secp256k1_norm_arg_commit_initial_data(&transcript, r, gens_vec, g_len, c_vec, c_vec_len, &comm); + + res = secp256k1_bulletproofs_pp_rangeproof_norm_product_verify( + ctx, + scratch, + proof, + proof_len, + &transcript, + r, + gens_vec, + g_len, + c_vec, + c_vec_len, + commit + ); + return res; +} + +void norm_arg_test(unsigned int n, unsigned int m) { + secp256k1_scalar n_vec[64], l_vec[64], c_vec[64]; + secp256k1_scalar r, q; + secp256k1_ge commit; + size_t i, plen; + int res; + secp256k1_bulletproofs_generators *gs = secp256k1_bulletproofs_generators_create(ctx, n + m); + secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*1000); /* shouldn't need much */ + unsigned char proof[1000]; + plen = 1000; + random_scalar_order(&r); + secp256k1_scalar_sqr(&q, &r); + + for (i = 0; i < n; i++) { + random_scalar_order(&n_vec[i]); + } + + for (i = 0; i < m; i++) { + random_scalar_order(&l_vec[i]); + random_scalar_order(&c_vec[i]); + } + + res = secp256k1_bulletproofs_commit(ctx, scratch, &commit, gs, n_vec, n, l_vec, m, c_vec, m, &q); + CHECK(res == 1); + res = secp256k1_norm_arg_prove(scratch, proof, &plen, &r, gs, n_vec, n, l_vec, m, c_vec, m, &commit); + CHECK(res == 1); + + res = secp256k1_norm_arg_verify(scratch, proof, plen, &r, gs, n, c_vec, m, &commit); + CHECK(res == 1); + + /* Changing any of last two scalars should break the proof */ + proof[plen - 1] ^= 1; + res = secp256k1_norm_arg_verify(scratch, proof, plen, &r, gs, n, c_vec, m, &commit); + CHECK(res == 0); + proof[plen - 1 - 32] ^= 1; + res = secp256k1_norm_arg_verify(scratch, proof, plen, &r, gs, n, c_vec, m, &commit); + CHECK(res == 0); + + secp256k1_scratch_space_destroy(ctx, scratch); + secp256k1_bulletproofs_generators_destroy(ctx, gs); +} + void run_bulletproofs_tests(void) { test_log_exp(); test_norm_util_helpers(); test_bulletproofs_generators_api(); test_bulletproofs_generators_fixed(); test_bulletproofs_pp_tagged_hash(); + + norm_arg_test(1, 1); + norm_arg_test(1, 64); + norm_arg_test(64, 1); + norm_arg_test(32, 32); + norm_arg_test(32, 64); + norm_arg_test(64, 32); + norm_arg_test(64, 64); } #endif From 34c4847a6a72e340dac2c078bbea4d65441e5971 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Fri, 20 Jan 2023 13:41:01 +0000 Subject: [PATCH 13/18] ci: add bulletproofs --- .cirrus.yml | 10 +++++++--- ci/cirrus.sh | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index d9d98d43e..e4ef0e347 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -23,6 +23,7 @@ env: WHITELIST: no MUSIG: no ECDSAADAPTOR: no + BULLETPROOFS: no ### test options SECP256K1_TEST_ITERS: BENCH: yes @@ -72,12 +73,12 @@ task: << : *LINUX_CONTAINER matrix: &ENV_MATRIX - env: {WIDEMUL: int64, RECOVERY: yes} - - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes} + - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BULLETPROOFS: yes} - env: {WIDEMUL: int128} - env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes} - - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes} + - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BULLETPROOFS: yes} - env: {WIDEMUL: int128, ASM: x86_64} - - env: { RECOVERY: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes} + - env: { RECOVERY: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BULLETPROOFS: yes} - env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no} - env: {CPPFLAGS: -DDETERMINISTIC} - env: {CFLAGS: -O0, CTIMETEST: no} @@ -108,6 +109,7 @@ task: GENERATOR: yes MUSIG: yes ECDSAADAPTOR: yes + BULLETPROOFS: yes matrix: - env: CC: i686-linux-gnu-gcc @@ -165,6 +167,7 @@ task: GENERATOR: yes MUSIG: yes ECDSAADAPTOR: yes + BULLETPROOFS: yes CTIMETEST: no << : *MERGE_BASE test_script: @@ -259,6 +262,7 @@ task: GENERATOR: yes MUSIG: yes ECDSAADAPTOR: yes + BULLETPROOFS: yes CTIMETEST: no matrix: - name: "Valgrind (memcheck)" diff --git a/ci/cirrus.sh b/ci/cirrus.sh index 74e8ab5ba..8f2b105d6 100755 --- a/ci/cirrus.sh +++ b/ci/cirrus.sh @@ -52,6 +52,10 @@ then $EXEC ./bench_ecmult $EXEC ./bench_internal $EXEC ./bench + if [ "$BULLETPROOFS" = "yes" ] + then + $EXEC ./bench_bulletproofs + fi } >> bench.log 2>&1 fi From 13ad32e814ece805a5bd2ef7c4b46fa37cedf136 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 26 Jan 2023 22:23:17 +0000 Subject: [PATCH 14/18] norm arg: add tests for zero length and zero vectors --- src/modules/bulletproofs/tests_impl.h | 99 +++++++++++++++++++++++---- 1 file changed, 87 insertions(+), 12 deletions(-) diff --git a/src/modules/bulletproofs/tests_impl.h b/src/modules/bulletproofs/tests_impl.h index ff7519f25..9943fef5c 100644 --- a/src/modules/bulletproofs/tests_impl.h +++ b/src/modules/bulletproofs/tests_impl.h @@ -203,6 +203,7 @@ static void secp256k1_norm_arg_commit_initial_data( secp256k1_bulletproofs_pp_sha256_tagged_commitment_init(transcript); secp256k1_fe_normalize(&comm.x); secp256k1_fe_normalize(&comm.y); + CHECK(secp256k1_ge_is_infinity(&comm) == 0); CHECK(secp256k1_bulletproofs_serialize_pt(&ser_commit[0], &comm)); secp256k1_sha256_write(transcript, ser_commit, 33); secp256k1_scalar_get_b32(ser_scalar, r); @@ -225,6 +226,28 @@ static void secp256k1_norm_arg_commit_initial_data( } } +static void copy_vectors_into_scratch(secp256k1_scratch_space* scratch, + secp256k1_scalar **ns, + secp256k1_scalar **ls, + secp256k1_scalar **cs, + secp256k1_ge **gs, + const secp256k1_scalar *n_vec, + const secp256k1_scalar *l_vec, + const secp256k1_scalar *c_vec, + const secp256k1_ge *gens_vec, + size_t g_len, + size_t h_len) { + *ns = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, g_len * sizeof(secp256k1_scalar)); + *ls = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar)); + *cs = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar)); + *gs = (secp256k1_ge*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, (g_len + h_len) * sizeof(secp256k1_ge)); + CHECK(ns != NULL && ls != NULL && cs != NULL && gs != NULL); + memcpy(*ns, n_vec, g_len * sizeof(secp256k1_scalar)); + memcpy(*ls, l_vec, h_len * sizeof(secp256k1_scalar)); + memcpy(*cs, c_vec, h_len * sizeof(secp256k1_scalar)); + memcpy(*gs, gens_vec, (g_len + h_len) * sizeof(secp256k1_ge)); +} + /* A complete norm argument. In contrast to secp256k1_bulletproofs_pp_rangeproof_norm_product_prove, this is meant to be used as a standalone norm argument. This is a simple wrapper around secp256k1_bulletproofs_pp_rangeproof_norm_product_prove @@ -253,18 +276,8 @@ static int secp256k1_norm_arg_prove( secp256k1_sha256 transcript; scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch); - ns = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, g_len * sizeof(secp256k1_scalar)); - ls = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar)); - cs = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar)); - gs = (secp256k1_ge*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, (g_len + h_len) * sizeof(secp256k1_ge)); - if (ns == NULL || ls == NULL || cs == NULL || gs == NULL) { - secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); - return 0; - } - memcpy(ns, n_vec, g_len * sizeof(secp256k1_scalar)); - memcpy(ls, l_vec, h_len * sizeof(secp256k1_scalar)); - memcpy(cs, c_vec, h_len * sizeof(secp256k1_scalar)); - memcpy(gs, gens_vec->gens, (g_len + h_len) * sizeof(secp256k1_ge)); + + copy_vectors_into_scratch(scratch, &ns, &ls, &cs, &gs, n_vec, l_vec, c_vec, gens_vec->gens, g_len, h_len); /* Commit to the initial public values */ secp256k1_norm_arg_commit_initial_data(&transcript, r, gens_vec, g_len, c_vec, c_vec_len, &comm); @@ -324,6 +337,67 @@ static int secp256k1_norm_arg_verify( return res; } +void norm_arg_zero(void) { + secp256k1_scalar n_vec[64], l_vec[64], c_vec[64]; + secp256k1_scalar r, q; + secp256k1_ge commit; + size_t i; + secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*10); /* shouldn't need much */ + unsigned char proof[1000]; + secp256k1_sha256 transcript; + + random_scalar_order(&r); + secp256k1_scalar_sqr(&q, &r); + + /* l is zero vector and n is zero vectors of length 1 each. */ + { + size_t plen = sizeof(proof); + unsigned int n_vec_len = 1; + unsigned int c_vec_len = 1; + secp256k1_bulletproofs_generators *gens = secp256k1_bulletproofs_generators_create(ctx, n_vec_len + c_vec_len); + + secp256k1_scalar_set_int(&n_vec[0], 0); + secp256k1_scalar_set_int(&l_vec[0], 0); + random_scalar_order(&c_vec[0]); + + secp256k1_sha256_initialize(&transcript); /* No challenges used in n = 1, l = 1, but we set transcript as a good practice*/ + CHECK(secp256k1_bulletproofs_commit(ctx, scratch, &commit, gens, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &q)); + { + secp256k1_scalar *ns, *ls, *cs; + secp256k1_ge *gs; + size_t scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch); + copy_vectors_into_scratch(scratch, &ns, &ls, &cs, &gs, n_vec, l_vec, c_vec, gens->gens, n_vec_len, c_vec_len); + CHECK(secp256k1_bulletproofs_pp_rangeproof_norm_product_prove(ctx, scratch, proof, &plen, &transcript, &r, gs, gens->n, ns, n_vec_len, ls, c_vec_len, cs, c_vec_len)); + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); + } + secp256k1_sha256_initialize(&transcript); + CHECK(secp256k1_bulletproofs_pp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &r, gens, c_vec_len, c_vec, c_vec_len, &commit)); + + secp256k1_bulletproofs_generators_destroy(ctx, gens); + } + + /* l is the zero vector and longer than n. This results in one of the + * internal commitments X or R to be the point at infinity. */ + { + unsigned int n_vec_len = 1; + unsigned int c_vec_len = 2; + secp256k1_bulletproofs_generators *gs = secp256k1_bulletproofs_generators_create(ctx, n_vec_len + c_vec_len); + size_t plen = sizeof(proof); + for (i = 0; i < n_vec_len; i++) { + random_scalar_order(&n_vec[i]); + } + for (i = 0; i < c_vec_len; i++) { + secp256k1_scalar_set_int(&l_vec[i], 0); + random_scalar_order(&c_vec[i]); + } + CHECK(secp256k1_bulletproofs_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &q)); + CHECK(!secp256k1_norm_arg_prove(scratch, proof, &plen, &r, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &commit)); + secp256k1_bulletproofs_generators_destroy(ctx, gs); + } + + secp256k1_scratch_space_destroy(ctx, scratch); +} + void norm_arg_test(unsigned int n, unsigned int m) { secp256k1_scalar n_vec[64], l_vec[64], c_vec[64]; secp256k1_scalar r, q; @@ -373,6 +447,7 @@ void run_bulletproofs_tests(void) { test_bulletproofs_generators_fixed(); test_bulletproofs_pp_tagged_hash(); + norm_arg_zero(); norm_arg_test(1, 1); norm_arg_test(1, 64); norm_arg_test(64, 1); From 73edc75528a9a4d4cf69b77d38f108023a132994 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Tue, 31 Jan 2023 14:05:58 +0000 Subject: [PATCH 15/18] norm arg: add verification vectors norm arg: add verify test vector with vector size > 1 --- .../bulletproofs/test_vectors/verify.h | 65 +++++++++++++++ src/modules/bulletproofs/tests_impl.h | 82 +++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 src/modules/bulletproofs/test_vectors/verify.h diff --git a/src/modules/bulletproofs/test_vectors/verify.h b/src/modules/bulletproofs/test_vectors/verify.h new file mode 100644 index 000000000..5397f67af --- /dev/null +++ b/src/modules/bulletproofs/test_vectors/verify.h @@ -0,0 +1,65 @@ +static const unsigned char verify_vector_gens[264] = { 0x03, 0xAF, 0x2C, 0x40, 0xAD, 0x03, 0xCD, 0xC5, 0x76, 0x8C, 0x07, 0x1E, 0x58, 0xD6, 0x8C, 0x73, 0x45, 0xBA, 0xEB, 0xB5, 0x3F, 0x40, 0xFA, 0x8B, 0xBF, 0x73, 0x6E, 0x7B, 0x4A, 0x54, 0x06, 0xED, 0x32, 0x03, 0xCC, 0x11, 0x19, 0x22, 0x2C, 0xA1, 0x0A, 0x45, 0x23, 0xAF, 0x9B, 0x40, 0x0D, 0xA4, 0x5E, 0x06, 0x24, 0xF4, 0x5F, 0x07, 0x89, 0x88, 0xCD, 0x71, 0xAE, 0x77, 0xC1, 0xF5, 0x87, 0x4E, 0xFC, 0xA5, 0x03, 0xDE, 0x61, 0xB1, 0x8F, 0x2C, 0xAC, 0x18, 0xF5, 0xE4, 0x06, 0x8F, 0x65, 0x55, 0xA1, 0x30, 0x5E, 0xF5, 0xF4, 0x84, 0xED, 0x6B, 0xDD, 0xC2, 0xCC, 0xE8, 0x51, 0x38, 0xB8, 0xA5, 0x4C, 0x43, 0xBD, 0x02, 0xA5, 0xF9, 0x8C, 0x1F, 0x82, 0x2D, 0xC6, 0xF3, 0x0F, 0x53, 0xDB, 0x74, 0x77, 0xC7, 0x91, 0x04, 0xB0, 0xB1, 0xA6, 0x17, 0xB2, 0x91, 0xF4, 0x8B, 0x93, 0x3E, 0xBB, 0x73, 0x15, 0x3E, 0x5A, 0xD1, 0x02, 0x44, 0xF5, 0xC6, 0x4E, 0x77, 0x60, 0x81, 0x83, 0xFF, 0xC2, 0x8E, 0x06, 0xFE, 0x67, 0x0C, 0x9A, 0x4B, 0xF2, 0x34, 0xB9, 0xEA, 0xE9, 0x37, 0xDA, 0x30, 0xE2, 0x32, 0x27, 0xF3, 0x88, 0x5F, 0x2A, 0x02, 0x1D, 0x49, 0x5D, 0x04, 0xED, 0x61, 0x95, 0x37, 0xDD, 0x95, 0xB1, 0x4F, 0x64, 0x0E, 0x1E, 0xFB, 0x47, 0x9F, 0xA7, 0xD7, 0xE0, 0x7A, 0xB1, 0x02, 0x81, 0x95, 0xD1, 0xA5, 0x7E, 0xB2, 0x74, 0x8F, 0x03, 0x26, 0xA5, 0xEC, 0xE9, 0x71, 0x46, 0x37, 0xAC, 0x3D, 0x74, 0x84, 0x26, 0xCB, 0x7C, 0xE8, 0xFE, 0x4E, 0xB0, 0x6D, 0x70, 0x3D, 0x00, 0x10, 0x1A, 0x3A, 0x5B, 0xB8, 0xAA, 0x29, 0x59, 0x93, 0x15, 0x03, 0xE1, 0xA5, 0x39, 0x44, 0x75, 0x16, 0x28, 0x5F, 0xBA, 0x69, 0xA2, 0x4A, 0x2A, 0xC3, 0x5B, 0x63, 0x1F, 0x40, 0x10, 0x36, 0xF9, 0x4C, 0xD2, 0x76, 0x0F, 0xCF, 0x7F, 0x50, 0x30, 0x6E, 0x2B, 0x1D }; +static const unsigned char verify_vector_0_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 }; +static const size_t verify_vector_0_n_vec_len = 1; +static const unsigned char verify_vector_0_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; +static secp256k1_scalar verify_vector_0_c_vec[1]; +static const unsigned char verify_vector_0_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A }; +static const unsigned char verify_vector_0_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E }; +static const int verify_vector_0_result = 1; +static const unsigned char verify_vector_1_commit33[33] = { 0x02, 0x6C, 0x09, 0xD7, 0x06, 0x2D, 0x1C, 0x07, 0x0A, 0x64, 0x34, 0x82, 0xF6, 0x46, 0x03, 0xEB, 0x24, 0x3E, 0x54, 0x0F, 0xDA, 0xAF, 0x3A, 0x69, 0x5F, 0x86, 0xB6, 0xD2, 0xC2, 0x06, 0xE9, 0x49, 0xC7 }; +static const size_t verify_vector_1_n_vec_len = 1; +static const unsigned char verify_vector_1_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; +static secp256k1_scalar verify_vector_1_c_vec[1]; +static const unsigned char verify_vector_1_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A }; +static const unsigned char verify_vector_1_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E }; +static const int verify_vector_1_result = 0; +static const unsigned char verify_vector_2_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 }; +static const size_t verify_vector_2_n_vec_len = 1; +static const unsigned char verify_vector_2_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; +static secp256k1_scalar verify_vector_2_c_vec[1]; +static const unsigned char verify_vector_2_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A }; +static const unsigned char verify_vector_2_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }; +static const int verify_vector_2_result = 0; +static const unsigned char verify_vector_3_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 }; +static const size_t verify_vector_3_n_vec_len = 1; +static const unsigned char verify_vector_3_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; +static secp256k1_scalar verify_vector_3_c_vec[1]; +static const unsigned char verify_vector_3_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A }; +static const unsigned char verify_vector_3_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }; +static const int verify_vector_3_result = 0; +static const unsigned char verify_vector_4_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 }; +static const size_t verify_vector_4_n_vec_len = 1; +static const unsigned char verify_vector_4_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; +static secp256k1_scalar verify_vector_4_c_vec[1]; +static const unsigned char verify_vector_4_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A }; +static const unsigned char verify_vector_4_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41 }; +static const int verify_vector_4_result = 0; +static const unsigned char verify_vector_5_commit33[33] = { 0x03, 0x83, 0x6A, 0xD4, 0x2D, 0xD2, 0x02, 0x49, 0xC8, 0x6E, 0x53, 0x22, 0x53, 0x24, 0xDA, 0x52, 0x08, 0xC0, 0x62, 0x4C, 0xCB, 0xB3, 0x13, 0xD7, 0x14, 0x59, 0x68, 0x47, 0x56, 0x00, 0xC0, 0x8D, 0xBA }; +static const size_t verify_vector_5_n_vec_len = 2; +static const unsigned char verify_vector_5_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; +static secp256k1_scalar verify_vector_5_c_vec[1]; +static const unsigned char verify_vector_5_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x36 }; +static const unsigned char verify_vector_5_proof[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x4C, 0xB9, 0xD4, 0x34, 0xA2, 0xD6, 0xD5, 0x4C, 0x0F, 0x2E, 0x2C, 0xE3, 0x82, 0x17, 0x48, 0x63, 0xE0, 0xAE, 0x6B, 0xD7, 0x64, 0x9D, 0x43, 0x2B, 0x6E, 0x6E, 0x1C, 0x62, 0x55, 0x4B, 0xC5, 0x73, 0x3D, 0x74, 0x7B, 0x78, 0x43, 0xF4, 0x8B, 0x7C, 0x84, 0x10, 0x00, 0x8B, 0x12, 0xAF, 0xA4, 0xF1, 0xF4, 0x01, 0x96, 0x21, 0x8B, 0xE9, 0x05, 0x01, 0xF8, 0x23, 0x7A, 0x8F, 0x66, 0xC9, 0xDE, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E }; +static const int verify_vector_5_result = 0; +static const unsigned char verify_vector_6_commit33[33] = { 0x03, 0xCF, 0x7F, 0x08, 0xF5, 0x8A, 0x06, 0x74, 0x5C, 0xDB, 0xCE, 0xC6, 0x51, 0xF3, 0xE5, 0xE4, 0xDC, 0xAD, 0xF4, 0x40, 0x3C, 0xFA, 0xE6, 0x78, 0xBE, 0x49, 0x2D, 0x90, 0xC8, 0xD0, 0x16, 0x3D, 0x78 }; +static const size_t verify_vector_6_n_vec_len = 2; +static const unsigned char verify_vector_6_c_vec32[4][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x30 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D } }; +static secp256k1_scalar verify_vector_6_c_vec[4]; +static const unsigned char verify_vector_6_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A }; +static const unsigned char verify_vector_6_proof[] = { 0x00, 0xD2, 0xEC, 0xE2, 0x53, 0x97, 0x28, 0x68, 0x22, 0x59, 0x34, 0xEF, 0xE4, 0x7B, 0x87, 0x4D, 0xE9, 0x57, 0xD5, 0xB7, 0xC7, 0x72, 0xF4, 0xC9, 0xEA, 0x66, 0x14, 0x59, 0xE1, 0xA9, 0xD5, 0xB2, 0x10, 0xDF, 0xE2, 0xFF, 0xF5, 0xA4, 0x38, 0x6B, 0xFE, 0x36, 0x89, 0xE4, 0x9D, 0x90, 0x9F, 0x71, 0x19, 0xE6, 0xA3, 0x1E, 0xAA, 0xAA, 0x4E, 0xFE, 0xC2, 0xD3, 0x37, 0xBB, 0xDE, 0xDB, 0x46, 0x43, 0xC2, 0x01, 0x42, 0x5F, 0xFC, 0xC6, 0x25, 0xA0, 0xB4, 0xF0, 0x76, 0x99, 0xF4, 0x7C, 0xE9, 0x83, 0x82, 0xED, 0x7C, 0x95, 0xBA, 0xD0, 0xE6, 0x5B, 0x88, 0xFD, 0x38, 0xEA, 0x23, 0x54, 0xD4, 0xBD, 0xD4, 0x37, 0xB8, 0x2B, 0x49, 0xAF, 0x81, 0xFD, 0xBE, 0x88, 0xB2, 0xE5, 0x3F, 0xF4, 0x30, 0x52, 0x00, 0x63, 0x9D, 0xAE, 0x82, 0x44, 0xE9, 0x62, 0x87, 0x2A, 0x23, 0x89, 0x10, 0xE4, 0x9A, 0x64, 0x9F, 0x71, 0xD9, 0x32, 0x57, 0x3B, 0xCB, 0xAC, 0x30, 0xAE, 0x71, 0x61, 0xE9, 0x50, 0x1F, 0xCB, 0x49, 0x9C, 0x52, 0xBA, 0x0C, 0xC4, 0x00, 0x58, 0x73, 0x63, 0xD3, 0x42, 0xDE, 0x42, 0x5E, 0xC5, 0x97, 0xE5, 0xDA, 0x88, 0x76, 0x49, 0x6C, 0x8B, 0x92, 0x99, 0xEE, 0xD0, 0xA9, 0xEB, 0x6E, 0xCA, 0xE1, 0x93, 0x81, 0x56, 0x2E, 0xCA, 0xF3, 0x8E, 0xF0, 0x04, 0xD2, 0x96, 0xD8, 0xDB, 0xEE, 0xEE, 0x1C, 0x44 }; +static const int verify_vector_6_result = 1; +static const unsigned char verify_vector_7_commit33[33] = { 0x02, 0x7A, 0xAA, 0xB2, 0x7E, 0xA5, 0x5B, 0x77, 0x08, 0xE5, 0x43, 0xB6, 0x22, 0x7F, 0xC9, 0xAC, 0x53, 0x10, 0x32, 0x61, 0x7B, 0x7D, 0xAC, 0xB1, 0xB6, 0xF6, 0xAC, 0xDE, 0x63, 0x79, 0x82, 0x9C, 0x24 }; +static const size_t verify_vector_7_n_vec_len = 4; +static const unsigned char verify_vector_7_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; +static secp256k1_scalar verify_vector_7_c_vec[1]; +static const unsigned char verify_vector_7_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 }; +static const unsigned char verify_vector_7_proof[] = { 0x00, 0xBC, 0x4C, 0x42, 0x67, 0x71, 0x69, 0x52, 0x6A, 0x65, 0xFE, 0xA0, 0xCB, 0x3F, 0x58, 0x8B, 0x48, 0x48, 0x6E, 0x59, 0xFC, 0x55, 0x51, 0x10, 0xB9, 0xBF, 0x6A, 0x7D, 0xBF, 0x32, 0x34, 0x4E, 0x7D, 0xBA, 0xD5, 0xCB, 0xCC, 0x19, 0xED, 0xAA, 0x9F, 0x8D, 0x93, 0x26, 0x5E, 0x3F, 0x3E, 0xAA, 0xDF, 0x0B, 0x1C, 0xB3, 0xDC, 0x37, 0xB6, 0xDB, 0xAE, 0x43, 0x63, 0x92, 0xB5, 0xFF, 0x0D, 0x1C, 0x77, 0x02, 0x7E, 0x2B, 0xB8, 0x87, 0x85, 0x81, 0x13, 0x70, 0x1F, 0x03, 0x65, 0x7D, 0xD8, 0x91, 0x83, 0xE5, 0x7E, 0x8B, 0x9E, 0x6F, 0x1C, 0x08, 0x9C, 0x9C, 0x5F, 0xA4, 0x12, 0x5F, 0xD3, 0xEE, 0xE2, 0x74, 0x7A, 0x2C, 0x58, 0x3A, 0x29, 0x4F, 0x64, 0x10, 0xE7, 0x89, 0xBF, 0xB2, 0xE5, 0xD9, 0xD5, 0xC5, 0x62, 0x83, 0x0C, 0xA8, 0xDD, 0x1E, 0x24, 0x6D, 0xD1, 0x58, 0x8D, 0x80, 0x74, 0xF3, 0xD9, 0x3A, 0x68, 0x7B, 0xF5, 0x12, 0xC6, 0xC2, 0x3F, 0x71, 0x47, 0xDF, 0xCF, 0xC8, 0xE2, 0xC4, 0x59, 0xDF, 0x4F, 0xEC, 0x86, 0xE9, 0xF9, 0x31, 0x94, 0x6A, 0x5F, 0xD9, 0x1E, 0x6B, 0x09, 0xCD, 0xCF, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E }; +static const int verify_vector_7_result = 1; +static const unsigned char verify_vector_8_commit33[33] = { 0x02, 0x2D, 0x4F, 0xF9, 0xB7, 0x15, 0x22, 0xBC, 0xB0, 0x8B, 0xF8, 0xBA, 0x31, 0x0A, 0x80, 0x76, 0x7A, 0xE9, 0xA9, 0x83, 0x00, 0xBC, 0x5A, 0x01, 0xCC, 0xE9, 0x00, 0x83, 0x56, 0xEA, 0x77, 0xEB, 0x75 }; +static const size_t verify_vector_8_n_vec_len = 4; +static const unsigned char verify_vector_8_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; +static secp256k1_scalar verify_vector_8_c_vec[1]; +static const unsigned char verify_vector_8_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 }; +static const unsigned char verify_vector_8_proof[] = { 0x00, 0xBC, 0x4C, 0x42, 0x67, 0x71, 0x69, 0x52, 0x6A, 0x65, 0xFE, 0xA0, 0xCB, 0x3F, 0x58, 0x8B, 0x48, 0x48, 0x6E, 0x59, 0xFC, 0x55, 0x51, 0x10, 0xB9, 0xBF, 0x6A, 0x7D, 0xBF, 0x32, 0x34, 0x4E, 0x7D, 0xBA, 0xD5, 0xCB, 0xCC, 0x19, 0xED, 0xAA, 0x9F, 0x8D, 0x93, 0x26, 0x5E, 0x3F, 0x3E, 0xAA, 0xDF, 0x0B, 0x1C, 0xB3, 0xDC, 0x37, 0xB6, 0xDB, 0xAE, 0x43, 0x63, 0x92, 0xB5, 0xFF, 0x0D, 0x1C, 0x77, 0x02, 0x7E, 0x2B, 0xB8, 0x87, 0x85, 0x81, 0x13, 0x70, 0x1F, 0x03, 0x65, 0x7D, 0xD8, 0x91, 0x83, 0xE5, 0x7E, 0x8B, 0x9E, 0x6F, 0x1C, 0x08, 0x9C, 0x9C, 0x5F, 0xA4, 0x12, 0x5F, 0xD3, 0xEE, 0xE2, 0x74, 0x7A, 0x2C, 0x58, 0x3A, 0x29, 0x4F, 0x64, 0x10, 0xE7, 0x89, 0xBF, 0xB2, 0xE5, 0xD9, 0xD5, 0xC5, 0x62, 0x83, 0x0C, 0xA8, 0xDD, 0x1E, 0x24, 0x6D, 0xD1, 0x58, 0x8D, 0x80, 0x74, 0xF3, 0xD9, 0x3A, 0x68, 0x7B, 0xF5, 0x12, 0xC6, 0xC2, 0x3F, 0x71, 0x47, 0xDF, 0xCF, 0xC8, 0xE2, 0xC4, 0x59, 0xDF, 0x4F, 0xEC, 0x86, 0xE9, 0xF9, 0x31, 0x94, 0x6A, 0x5F, 0xD9, 0x1E, 0x6B, 0x09, 0xCD, 0xCF, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E }; +static const int verify_vector_8_result = 0; + diff --git a/src/modules/bulletproofs/tests_impl.h b/src/modules/bulletproofs/tests_impl.h index 9943fef5c..012afefa9 100644 --- a/src/modules/bulletproofs/tests_impl.h +++ b/src/modules/bulletproofs/tests_impl.h @@ -13,6 +13,7 @@ #include "bulletproofs_pp_norm_product_impl.h" #include "bulletproofs_util.h" #include "bulletproofs_pp_transcript_impl.h" +#include "test_vectors/verify.h" static void test_bulletproofs_generators_api(void) { /* The BP generator API requires no precomp */ @@ -440,6 +441,86 @@ void norm_arg_test(unsigned int n, unsigned int m) { secp256k1_bulletproofs_generators_destroy(ctx, gs); } +/* Parses generators from points compressed as pubkeys */ +secp256k1_bulletproofs_generators* bulletproofs_generators_parse_regular(const unsigned char* data, size_t data_len) { + size_t n = data_len / 33; + secp256k1_bulletproofs_generators* ret; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(data != NULL); + + if (data_len % 33 != 0) { + return NULL; + } + + ret = (secp256k1_bulletproofs_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret)); + if (ret == NULL) { + return NULL; + } + ret->n = n; + ret->gens = (secp256k1_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens)); + if (ret->gens == NULL) { + free(ret); + return NULL; + } + + while (n--) { + if (!secp256k1_eckey_pubkey_parse(&ret->gens[n], &data[33 * n], 33)) { + free(ret->gens); + free(ret); + return NULL; + } + } + return ret; +} + +int norm_arg_verify_vectors_helper(secp256k1_scratch *scratch, const unsigned char *gens, const unsigned char *proof, size_t plen, const unsigned char *r32, size_t n_vec_len, const unsigned char c_vec32[][32], secp256k1_scalar *c_vec, size_t c_vec_len, const unsigned char *commit33) { + secp256k1_sha256 transcript; + secp256k1_bulletproofs_generators *gs = bulletproofs_generators_parse_regular(gens, 33*(n_vec_len + c_vec_len)); + secp256k1_scalar r; + secp256k1_ge commit; + int overflow; + int i; + int ret; + + CHECK(gs != NULL); + secp256k1_sha256_initialize(&transcript); + + secp256k1_scalar_set_b32(&r, r32, &overflow); + CHECK(!overflow); + + for (i = 0; i < (int)c_vec_len; i++) { + secp256k1_scalar_set_b32(&c_vec[i], c_vec32[i], &overflow); + CHECK(!overflow); + } + CHECK(secp256k1_eckey_pubkey_parse(&commit, commit33, 33)); + ret = secp256k1_bulletproofs_pp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &r, gs, n_vec_len, c_vec, c_vec_len, &commit); + + secp256k1_bulletproofs_generators_destroy(ctx, gs); + return ret; +} + +#define IDX_TO_TEST(i) (norm_arg_verify_vectors_helper(scratch, verify_vector_gens, verify_vector_##i##_proof, sizeof(verify_vector_##i##_proof), verify_vector_##i##_r32, verify_vector_##i##_n_vec_len, verify_vector_##i##_c_vec32, verify_vector_##i##_c_vec, sizeof(verify_vector_##i##_c_vec)/sizeof(secp256k1_scalar), verify_vector_##i##_commit33) == verify_vector_##i##_result) + +void norm_arg_verify_vectors(void) { + secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*1000); /* shouldn't need much */ + size_t alloc = scratch->alloc_size; + + CHECK(IDX_TO_TEST(0)); + CHECK(IDX_TO_TEST(1)); + CHECK(IDX_TO_TEST(2)); + CHECK(IDX_TO_TEST(3)); + CHECK(IDX_TO_TEST(4)); + CHECK(IDX_TO_TEST(5)); + CHECK(IDX_TO_TEST(6)); + CHECK(IDX_TO_TEST(7)); + CHECK(IDX_TO_TEST(8)); + + CHECK(alloc == scratch->alloc_size); + secp256k1_scratch_space_destroy(ctx, scratch); +} +#undef IDX_TO_TEST + void run_bulletproofs_tests(void) { test_log_exp(); test_norm_util_helpers(); @@ -455,6 +536,7 @@ void run_bulletproofs_tests(void) { norm_arg_test(32, 64); norm_arg_test(64, 32); norm_arg_test(64, 64); + norm_arg_verify_vectors(); } #endif From c9831868723b06cca72141651f9e27f37c6ca3eb Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Tue, 31 Jan 2023 16:32:32 +0000 Subject: [PATCH 16/18] transcript: add tests --- src/modules/bulletproofs/tests_impl.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/modules/bulletproofs/tests_impl.h b/src/modules/bulletproofs/tests_impl.h index 012afefa9..dd3e4130e 100644 --- a/src/modules/bulletproofs/tests_impl.h +++ b/src/modules/bulletproofs/tests_impl.h @@ -128,12 +128,36 @@ static void test_bulletproofs_pp_tagged_hash(void) { secp256k1_sha256 sha_cached; unsigned char output[32]; unsigned char output_cached[32]; + secp256k1_scalar s; secp256k1_sha256_initialize_tagged(&sha, tag_data, sizeof(tag_data)); secp256k1_bulletproofs_pp_sha256_tagged_commitment_init(&sha_cached); secp256k1_sha256_finalize(&sha, output); secp256k1_sha256_finalize(&sha_cached, output_cached); CHECK(secp256k1_memcmp_var(output, output_cached, 32) == 0); + + { + unsigned char expected[32] = { 0x21, 0x2F, 0xB6, 0x4F, 0x9D, 0x8C, 0x3B, 0xC5, + 0xF6, 0x91, 0x15, 0xEE, 0x74, 0xF5, 0x12, 0x67, + 0x8A, 0x41, 0xC6, 0x85, 0x1A, 0x79, 0x14, 0xFC, + 0x48, 0x15, 0xC7, 0x2D, 0xF8, 0x63, 0x8F, 0x1B }; + secp256k1_bulletproofs_pp_sha256_tagged_commitment_init(&sha); + secp256k1_bulletproofs_challenge_scalar(&s, &sha, 0); + secp256k1_scalar_get_b32(output, &s); + CHECK(memcmp(output, expected, sizeof(output)) == 0); + } + + { + unsigned char tmp[3] = {0, 1, 2}; + unsigned char expected[32] = { 0x8D, 0xAA, 0xB7, 0x7E, 0x3C, 0x6A, 0x9E, 0xEC, + 0x72, 0x7E, 0x3E, 0xB7, 0x10, 0x03, 0xF0, 0xE9, + 0x69, 0x4D, 0xAA, 0x96, 0xCE, 0x98, 0xBB, 0x39, + 0x1C, 0x2F, 0x7C, 0x2E, 0x1C, 0x17, 0x78, 0x6D }; + secp256k1_sha256_write(&sha, tmp, sizeof(tmp)); + secp256k1_bulletproofs_challenge_scalar(&s, &sha, 0); + secp256k1_scalar_get_b32(output, &s); + CHECK(memcmp(output, expected, sizeof(output)) == 0); + } } void test_log_exp(void) { From e5a01d12c63b30d3627cd0114a042a9853b0d233 Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Mon, 6 Feb 2023 13:53:02 -0800 Subject: [PATCH 17/18] Rename buletproof_pp* to bppp* --- .cirrus.yml | 14 +- .gitignore | 2 +- Makefile.am | 4 +- ci/cirrus.sh | 6 +- configure.ac | 18 +-- ...p256k1_bulletproofs.h => secp256k1_bppp.h} | 20 +-- src/{bench_bulletproofs.c => bench_bppp.c} | 14 +- src/modules/bppp/Makefile.am.include | 13 ++ .../bppp_norm_product_impl.h} | 38 ++--- .../bppp_transcript_impl.h} | 12 +- .../bulletproofs_util.h => bppp/bppp_util.h} | 12 +- src/modules/{bulletproofs => bppp}/main.h | 8 +- .../{bulletproofs => bppp}/main_impl.h | 26 +-- .../test_vectors/verify.h | 0 .../{bulletproofs => bppp}/tests_impl.h | 148 +++++++++--------- src/modules/bulletproofs/Makefile.am.include | 13 -- src/secp256k1.c | 4 +- src/tests.c | 8 +- 18 files changed, 180 insertions(+), 180 deletions(-) rename include/{secp256k1_bulletproofs.h => secp256k1_bppp.h} (77%) rename src/{bench_bulletproofs.c => bench_bppp.c} (64%) create mode 100644 src/modules/bppp/Makefile.am.include rename src/modules/{bulletproofs/bulletproofs_pp_norm_product_impl.h => bppp/bppp_norm_product_impl.h} (93%) rename src/modules/{bulletproofs/bulletproofs_pp_transcript_impl.h => bppp/bppp_transcript_impl.h} (73%) rename src/modules/{bulletproofs/bulletproofs_util.h => bppp/bppp_util.h} (78%) rename src/modules/{bulletproofs => bppp}/main.h (50%) rename src/modules/{bulletproofs => bppp}/main_impl.h (70%) rename src/modules/{bulletproofs => bppp}/test_vectors/verify.h (100%) rename src/modules/{bulletproofs => bppp}/tests_impl.h (75%) delete mode 100644 src/modules/bulletproofs/Makefile.am.include diff --git a/.cirrus.yml b/.cirrus.yml index e4ef0e347..48c9be8c0 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -23,7 +23,7 @@ env: WHITELIST: no MUSIG: no ECDSAADAPTOR: no - BULLETPROOFS: no + BPPP: no ### test options SECP256K1_TEST_ITERS: BENCH: yes @@ -73,12 +73,12 @@ task: << : *LINUX_CONTAINER matrix: &ENV_MATRIX - env: {WIDEMUL: int64, RECOVERY: yes} - - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BULLETPROOFS: yes} + - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes} - env: {WIDEMUL: int128} - env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes} - - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BULLETPROOFS: yes} + - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes} - env: {WIDEMUL: int128, ASM: x86_64} - - env: { RECOVERY: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BULLETPROOFS: yes} + - env: { RECOVERY: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes} - env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no} - env: {CPPFLAGS: -DDETERMINISTIC} - env: {CFLAGS: -O0, CTIMETEST: no} @@ -109,7 +109,7 @@ task: GENERATOR: yes MUSIG: yes ECDSAADAPTOR: yes - BULLETPROOFS: yes + BPPP: yes matrix: - env: CC: i686-linux-gnu-gcc @@ -167,7 +167,7 @@ task: GENERATOR: yes MUSIG: yes ECDSAADAPTOR: yes - BULLETPROOFS: yes + BPPP: yes CTIMETEST: no << : *MERGE_BASE test_script: @@ -262,7 +262,7 @@ task: GENERATOR: yes MUSIG: yes ECDSAADAPTOR: yes - BULLETPROOFS: yes + BPPP: yes CTIMETEST: no matrix: - name: "Valgrind (memcheck)" diff --git a/.gitignore b/.gitignore index 3c0494d55..9be37772b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ bench -bench_bulletproofs +bench_bppp bench_ecmult bench_generator bench_rangeproof diff --git a/Makefile.am b/Makefile.am index 722dfac3a..482d870d0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -226,8 +226,8 @@ clean-precomp: EXTRA_DIST = autogen.sh SECURITY.md -if ENABLE_MODULE_BULLETPROOFS -include src/modules/bulletproofs/Makefile.am.include +if ENABLE_MODULE_BPPP +include src/modules/bppp/Makefile.am.include endif if ENABLE_MODULE_ECDH diff --git a/ci/cirrus.sh b/ci/cirrus.sh index 8f2b105d6..14c8dbe9e 100755 --- a/ci/cirrus.sh +++ b/ci/cirrus.sh @@ -19,7 +19,7 @@ valgrind --version || true --with-ecmult-gen-precision="$ECMULTGENPRECISION" \ --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \ --enable-module-ecdsa-s2c="$ECDSA_S2C" \ - --enable-module-bulletproofs="$BULLETPROOFS" \ + --enable-module-bppp="$BPPP" \ --enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \ --enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \ --enable-module-schnorrsig="$SCHNORRSIG" \ @@ -52,9 +52,9 @@ then $EXEC ./bench_ecmult $EXEC ./bench_internal $EXEC ./bench - if [ "$BULLETPROOFS" = "yes" ] + if [ "$BPPP" = "yes" ] then - $EXEC ./bench_bulletproofs + $EXEC ./bench_bppp fi } >> bench.log 2>&1 fi diff --git a/configure.ac b/configure.ac index 0b0a9d78e..c168694cd 100644 --- a/configure.ac +++ b/configure.ac @@ -140,10 +140,10 @@ AC_ARG_ENABLE(examples, AS_HELP_STRING([--enable-examples],[compile the examples [default=no]]), [], [SECP_SET_DEFAULT([enable_examples], [no], [yes])]) -AC_ARG_ENABLE(module_bulletproofs, - AS_HELP_STRING([--enable-module-bulletproofs],[enable Bulletproofs module (experimental)]), +AC_ARG_ENABLE(module_bppp, + AS_HELP_STRING([--enable-module-bppp],[enable Bulletproofs++ module (experimental)]), [], - [SECP_SET_DEFAULT([enable_module_bulletproofs], [no], [yes])]) + [SECP_SET_DEFAULT([enable_module_bppp], [no], [yes])]) AC_ARG_ENABLE(module_ecdh, AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=no]]), [], @@ -422,9 +422,9 @@ if test x"$enable_module_rangeproof" = x"yes"; then AC_DEFINE(ENABLE_MODULE_RANGEPROOF, 1, [Define this symbol to enable the Pedersen / zero knowledge range proof module]) fi -if test x"$enable_module_bulletproofs" = x"yes"; then +if test x"$enable_module_bppp" = x"yes"; then enable_module_generator=yes - AC_DEFINE(ENABLE_MODULE_BULLETPROOFS, 1, [Define this symbol to enable the Bulletproofs module]) + AC_DEFINE(ENABLE_MODULE_BPPP, 1, [Define this symbol to enable the Bulletproofs++ module]) fi if test x"$enable_module_generator" = x"yes"; then @@ -470,8 +470,8 @@ else # module (which automatically enables the module dependencies) we want to # print an error for the dependent module, not the module dependency. Hence, # we first test dependent modules. - if test x"$enable_module_bulletproofs" = x"yes"; then - AC_MSG_ERROR([Bulletproofs module is experimental. Use --enable-experimental to allow.]) + if test x"$enable_module_bppp" = x"yes"; then + AC_MSG_ERROR([Bulletproofs++ module is experimental. Use --enable-experimental to allow.]) fi if test x"$enable_module_whitelist" = x"yes"; then AC_MSG_ERROR([Key whitelisting module is experimental. Use --enable-experimental to allow.]) @@ -515,7 +515,7 @@ AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"]) AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"]) AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"]) AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_BULLETPROOFS], [test x"$enable_module_bulletproofs" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_BPPP], [test x"$enable_module_bppp" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) @@ -555,7 +555,7 @@ echo " module whitelist = $enable_module_whitelist" echo " module musig = $enable_module_musig" echo " module ecdsa-s2c = $enable_module_ecdsa_s2c" echo " module ecdsa-adaptor = $enable_module_ecdsa_adaptor" -echo " module bulletproofs = $enable_module_bulletproofs" +echo " module bppp = $enable_module_bppp" echo echo " asm = $set_asm" echo " ecmult window size = $set_ecmult_window" diff --git a/include/secp256k1_bulletproofs.h b/include/secp256k1_bppp.h similarity index 77% rename from include/secp256k1_bulletproofs.h rename to include/secp256k1_bppp.h index 1ddd96997..c880ee484 100644 --- a/include/secp256k1_bulletproofs.h +++ b/include/secp256k1_bppp.h @@ -1,5 +1,5 @@ -#ifndef _SECP256K1_BULLETPROOFS_ -# define _SECP256K1_BULLETPROOFS_ +#ifndef _SECP256K1_BPPP_ +# define _SECP256K1_BPPP_ # include "secp256k1.h" @@ -10,7 +10,7 @@ extern "C" { #include /** Opaque structure representing a large number of NUMS generators */ -typedef struct secp256k1_bulletproofs_generators secp256k1_bulletproofs_generators; +typedef struct secp256k1_bppp_generators secp256k1_bppp_generators; /** Allocates and initializes a list of NUMS generators. * Returns a list of generators, or calls the error callback if the allocation fails. @@ -21,7 +21,7 @@ typedef struct secp256k1_bulletproofs_generators secp256k1_bulletproofs_generato * points. We will later use G = H0(required for compatibility with pedersen_commitment DS) * in a separate commit to make review easier. */ -SECP256K1_API secp256k1_bulletproofs_generators *secp256k1_bulletproofs_generators_create( +SECP256K1_API secp256k1_bppp_generators *secp256k1_bppp_generators_create( const secp256k1_context* ctx, size_t n ) SECP256K1_ARG_NONNULL(1); @@ -29,10 +29,10 @@ SECP256K1_API secp256k1_bulletproofs_generators *secp256k1_bulletproofs_generato /** Allocates a list of generators from a static array * Returns a list of generators or NULL in case of failure. * Args: ctx: pointer to a context object - * In: data: data that came from `secp256k1_bulletproofs_generators_serialize` + * In: data: data that came from `secp256k1_bppp_generators_serialize` * data_len: the length of the `data` buffer */ -SECP256K1_API secp256k1_bulletproofs_generators* secp256k1_bulletproofs_generators_parse( +SECP256K1_API secp256k1_bppp_generators* secp256k1_bppp_generators_parse( const secp256k1_context* ctx, const unsigned char* data, size_t data_len @@ -49,9 +49,9 @@ SECP256K1_API secp256k1_bulletproofs_generators* secp256k1_bulletproofs_generato * TODO: For ease of review, this setting G = H0 is not included in this commit. We will * add it in the follow-up rangeproof PR. */ -SECP256K1_API int secp256k1_bulletproofs_generators_serialize( +SECP256K1_API int secp256k1_bppp_generators_serialize( const secp256k1_context* ctx, - const secp256k1_bulletproofs_generators* gen, + const secp256k1_bppp_generators* gen, unsigned char* data, size_t *data_len ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); @@ -61,9 +61,9 @@ SECP256K1_API int secp256k1_bulletproofs_generators_serialize( * gen: pointer to the generator set to be destroyed * (can be NULL, in which case this function is a no-op) */ -SECP256K1_API void secp256k1_bulletproofs_generators_destroy( +SECP256K1_API void secp256k1_bppp_generators_destroy( const secp256k1_context* ctx, - secp256k1_bulletproofs_generators* gen + secp256k1_bppp_generators* gen ) SECP256K1_ARG_NONNULL(1); # ifdef __cplusplus diff --git a/src/bench_bulletproofs.c b/src/bench_bppp.c similarity index 64% rename from src/bench_bulletproofs.c rename to src/bench_bppp.c index f113791c4..c2846182d 100644 --- a/src/bench_bulletproofs.c +++ b/src/bench_bppp.c @@ -6,32 +6,32 @@ #include -#include "include/secp256k1_bulletproofs.h" +#include "include/secp256k1_bppp.h" #include "util.h" #include "bench.h" typedef struct { secp256k1_context* ctx; -} bench_bulletproofs_data; +} bench_bppp_data; -static void bench_bulletproofs_setup(void* arg) { +static void bench_bppp_setup(void* arg) { (void) arg; } -static void bench_bulletproofs(void* arg, int iters) { - bench_bulletproofs_data *data = (bench_bulletproofs_data*)arg; +static void bench_bppp(void* arg, int iters) { + bench_bppp_data *data = (bench_bppp_data*)arg; (void) data; (void) iters; } int main(void) { - bench_bulletproofs_data data; + bench_bppp_data data; int iters = get_iters(32); data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - run_benchmark("bulletproofs_verify_bit", bench_bulletproofs, bench_bulletproofs_setup, NULL, &data, 10, iters); + run_benchmark("bppp_verify_bit", bench_bppp, bench_bppp_setup, NULL, &data, 10, iters); secp256k1_context_destroy(data.ctx); return 0; diff --git a/src/modules/bppp/Makefile.am.include b/src/modules/bppp/Makefile.am.include new file mode 100644 index 000000000..13e8ea03d --- /dev/null +++ b/src/modules/bppp/Makefile.am.include @@ -0,0 +1,13 @@ +include_HEADERS += include/secp256k1_bppp.h +noinst_HEADERS += src/modules/bppp/bppp_util.h +noinst_HEADERS += src/modules/bppp/main_impl.h +noinst_HEADERS += src/modules/bppp/bppp_transcript_impl.h +noinst_HEADERS += src/modules/bppp/bppp_norm_product_impl.h +noinst_HEADERS += src/modules/bppp/tests_impl.h + +if USE_BENCHMARK +noinst_PROGRAMS += bench_bppp +bench_bppp_SOURCES = src/bench_bppp.c +bench_bppp_LDADD = libsecp256k1.la $(SECP_LIBS) +bench_bppp_LDFLAGS = -static +endif diff --git a/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h b/src/modules/bppp/bppp_norm_product_impl.h similarity index 93% rename from src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h rename to src/modules/bppp/bppp_norm_product_impl.h index c380bba19..9d61b0d05 100644 --- a/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h +++ b/src/modules/bppp/bppp_norm_product_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_MODULE_BULLETPROOFS_PP_NORM_PRODUCT_ -#define _SECP256K1_MODULE_BULLETPROOFS_PP_NORM_PRODUCT_ +#ifndef _SECP256K1_MODULE_BPPP_PP_NORM_PRODUCT_ +#define _SECP256K1_MODULE_BPPP_PP_NORM_PRODUCT_ #include "group.h" #include "scalar.h" @@ -13,9 +13,9 @@ #include "ecmult_gen.h" #include "hash.h" -#include "modules/bulletproofs/main.h" -#include "modules/bulletproofs/bulletproofs_util.h" -#include "modules/bulletproofs/bulletproofs_pp_transcript_impl.h" +#include "modules/bppp/main.h" +#include "modules/bppp/bppp_util.h" +#include "modules/bppp/bppp_transcript_impl.h" /* Computes the inner product of two vectors of scalars * with elements starting from offset a and offset b @@ -69,7 +69,7 @@ static int secp256k1_weighted_scalar_inner_product( } /* Compute the powers of r as r, r^2, r^4 ... r^(2^(n-1)) */ -static void secp256k1_bulletproofs_powers_of_r(secp256k1_scalar *powers, const secp256k1_scalar *r, size_t n) { +static void secp256k1_bppp_powers_of_r(secp256k1_scalar *powers, const secp256k1_scalar *r, size_t n) { size_t i; if (n == 0) { return; @@ -102,11 +102,11 @@ static int ecmult_bp_commit_cb(secp256k1_scalar *sc, secp256k1_ge *pt, size_t id v = |n_vec*n_vec|_q + . |w|_q denotes q-weighted norm of w and denotes inner product of l and r. */ -static int secp256k1_bulletproofs_commit( +static int secp256k1_bppp_commit( const secp256k1_context* ctx, secp256k1_scratch_space* scratch, secp256k1_ge* commit, - const secp256k1_bulletproofs_generators* g_vec, + const secp256k1_bppp_generators* g_vec, const secp256k1_scalar* n_vec, size_t n_vec_len, const secp256k1_scalar* l_vec, @@ -216,7 +216,7 @@ static int ecmult_r_cb(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void * some parent protocol. To use this norm protocol in a standalone manner, the user * should add the commitment, generators and initial public data to the transcript hash. */ -static int secp256k1_bulletproofs_pp_rangeproof_norm_product_prove( +static int secp256k1_bppp_rangeproof_norm_product_prove( const secp256k1_context* ctx, secp256k1_scratch_space* scratch, unsigned char* proof, @@ -238,7 +238,7 @@ static int secp256k1_bulletproofs_pp_rangeproof_norm_product_prove( ecmult_r_cb_data r_cb_data; size_t g_len = n_vec_len, h_len = l_vec_len; const size_t G_GENS_LEN = g_len; - size_t log_g_len = secp256k1_bulletproofs_pp_log2(g_len), log_h_len = secp256k1_bulletproofs_pp_log2(h_len); + size_t log_g_len = secp256k1_bppp_log2(g_len), log_h_len = secp256k1_bppp_log2(h_len); size_t num_rounds = log_g_len > log_h_len ? log_g_len : log_h_len; /* Check proof sizes.*/ @@ -307,12 +307,12 @@ static int secp256k1_bulletproofs_pp_rangeproof_norm_product_prove( secp256k1_ge_set_gej_var(&r_ge, &rj); secp256k1_fe_normalize_var(&r_ge.x); secp256k1_fe_normalize_var(&r_ge.y); - secp256k1_bulletproofs_serialize_points(&proof[proof_idx], &x_ge, &r_ge); + secp256k1_bppp_serialize_points(&proof[proof_idx], &x_ge, &r_ge); proof_idx += 65; /* Obtain challenge e for the the next round */ secp256k1_sha256_write(transcript, &proof[proof_idx - 65], 65); - secp256k1_bulletproofs_challenge_scalar(&e, transcript, 0); + secp256k1_bppp_challenge_scalar(&e, transcript, 0); if (g_len > 1) { for (i = 0; i < g_len; i = i + 2) { @@ -422,14 +422,14 @@ static int ec_mult_verify_cb2(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx /* Verify the proof. This function modifies the generators, c_vec and the challenge r. The caller should make sure to back them up if they need to be reused. */ -static int secp256k1_bulletproofs_pp_rangeproof_norm_product_verify( +static int secp256k1_bppp_rangeproof_norm_product_verify( const secp256k1_context* ctx, secp256k1_scratch_space* scratch, const unsigned char* proof, size_t proof_len, secp256k1_sha256* transcript, const secp256k1_scalar* r, - const secp256k1_bulletproofs_generators* g_vec, + const secp256k1_bppp_generators* g_vec, size_t g_len, const secp256k1_scalar* c_vec, size_t c_vec_len, @@ -440,7 +440,7 @@ static int secp256k1_bulletproofs_pp_rangeproof_norm_product_verify( secp256k1_gej res1, res2; size_t i = 0, scratch_checkpoint; int overflow; - size_t log_g_len = secp256k1_bulletproofs_pp_log2(g_len), log_h_len = secp256k1_bulletproofs_pp_log2(c_vec_len); + size_t log_g_len = secp256k1_bppp_log2(g_len), log_h_len = secp256k1_bppp_log2(c_vec_len); size_t n_rounds = log_g_len > log_h_len ? log_g_len : log_h_len; size_t h_len = c_vec_len; @@ -471,7 +471,7 @@ static int secp256k1_bulletproofs_pp_rangeproof_norm_product_verify( /* Compute powers of r_inv. Later used in g_factor computations*/ secp256k1_scalar_inverse_var(&r_inv, r); - secp256k1_bulletproofs_powers_of_r(r_inv_pows, &r_inv, log_g_len); + secp256k1_bppp_powers_of_r(r_inv_pows, &r_inv, log_g_len); /* Compute r_f = r^(2^log_g_len) */ r_f = *r; @@ -482,7 +482,7 @@ static int secp256k1_bulletproofs_pp_rangeproof_norm_product_verify( for (i = 0; i < n_rounds; i++) { secp256k1_scalar e; secp256k1_sha256_write(transcript, &proof[i * 65], 65); - secp256k1_bulletproofs_challenge_scalar(&e, transcript, 0); + secp256k1_bppp_challenge_scalar(&e, transcript, 0); es[i] = e; } /* s_g[0] = n * \prod_{j=0}^{log_g_len - 1} r^(2^j) @@ -491,7 +491,7 @@ static int secp256k1_bulletproofs_pp_rangeproof_norm_product_verify( secp256k1_scalar_mul(&s_g[0], &n, &r_f); secp256k1_scalar_mul(&s_g[0], &s_g[0], &r_inv); for (i = 1; i < g_len; i++) { - size_t log_i = secp256k1_bulletproofs_pp_log2(i); + size_t log_i = secp256k1_bppp_log2(i); size_t nearest_pow_of_two = (size_t)1 << log_i; /* This combines the two multiplications of challenges and r_invs in a * single loop. @@ -503,7 +503,7 @@ static int secp256k1_bulletproofs_pp_rangeproof_norm_product_verify( s_h[0] = l; secp256k1_scalar_set_int(&h_c, 0); for (i = 1; i < h_len; i++) { - size_t log_i = secp256k1_bulletproofs_pp_log2(i); + size_t log_i = secp256k1_bppp_log2(i); size_t nearest_pow_of_two = (size_t)1 << log_i; secp256k1_scalar_mul(&s_h[i], &s_h[i - nearest_pow_of_two], &es[log_i]); } diff --git a/src/modules/bulletproofs/bulletproofs_pp_transcript_impl.h b/src/modules/bppp/bppp_transcript_impl.h similarity index 73% rename from src/modules/bulletproofs/bulletproofs_pp_transcript_impl.h rename to src/modules/bppp/bppp_transcript_impl.h index e8444e91e..a734ea2dd 100644 --- a/src/modules/bulletproofs/bulletproofs_pp_transcript_impl.h +++ b/src/modules/bppp/bppp_transcript_impl.h @@ -3,17 +3,17 @@ * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_MODULE_BULLETPROOFS_PP_TRANSCRIPT_IMPL_ -#define _SECP256K1_MODULE_BULLETPROOFS_PP_TRANSCRIPT_IMPL_ +#ifndef _SECP256K1_MODULE_BPPP_PP_TRANSCRIPT_IMPL_ +#define _SECP256K1_MODULE_BPPP_PP_TRANSCRIPT_IMPL_ #include "group.h" #include "scalar.h" -#include "bulletproofs_util.h" +#include "bppp_util.h" /* Initializes SHA256 with fixed midstate. This midstate was computed by applying * SHA256 to SHA256("Bulletproofs_pp/v0/commitment")||SHA256("Bulletproofs_pp/v0/commitment"). */ -static void secp256k1_bulletproofs_pp_sha256_tagged_commitment_init(secp256k1_sha256 *sha) { +static void secp256k1_bppp_sha256_tagged_commitment_init(secp256k1_sha256 *sha) { secp256k1_sha256_initialize(sha); sha->s[0] = 0x52fc8185ul; sha->s[1] = 0x0e7debf0ul; @@ -28,10 +28,10 @@ static void secp256k1_bulletproofs_pp_sha256_tagged_commitment_init(secp256k1_sh } /* Obtain a challenge scalar from the current transcript.*/ -static void secp256k1_bulletproofs_challenge_scalar(secp256k1_scalar* ch, const secp256k1_sha256 *transcript, uint64_t idx) { +static void secp256k1_bppp_challenge_scalar(secp256k1_scalar* ch, const secp256k1_sha256 *transcript, uint64_t idx) { unsigned char buf[32]; secp256k1_sha256 sha = *transcript; - secp256k1_bulletproofs_le64(buf, idx); + secp256k1_bppp_le64(buf, idx); secp256k1_sha256_write(&sha, buf, 8); secp256k1_sha256_finalize(&sha, buf); secp256k1_scalar_set_b32(ch, buf, NULL); diff --git a/src/modules/bulletproofs/bulletproofs_util.h b/src/modules/bppp/bppp_util.h similarity index 78% rename from src/modules/bulletproofs/bulletproofs_util.h rename to src/modules/bppp/bppp_util.h index 07f6fc62b..10c58bb7d 100644 --- a/src/modules/bulletproofs/bulletproofs_util.h +++ b/src/modules/bppp/bppp_util.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_MODULE_BULLETPROOFS_UTIL_ -#define _SECP256K1_MODULE_BULLETPROOFS_UTIL_ +#ifndef _SECP256K1_MODULE_BPPP_UTIL_ +#define _SECP256K1_MODULE_BPPP_UTIL_ #include "field.h" #include "group.h" @@ -15,7 +15,7 @@ /* Outputs a pair of points, amortizing the parity byte between them * Assumes both points' coordinates have been normalized. */ -static void secp256k1_bulletproofs_serialize_points(unsigned char *output, const secp256k1_ge *lpt, const secp256k1_ge *rpt) { +static void secp256k1_bppp_serialize_points(unsigned char *output, const secp256k1_ge *lpt, const secp256k1_ge *rpt) { output[0] = (secp256k1_fe_is_odd(&lpt->y) << 1) + secp256k1_fe_is_odd(&rpt->y); secp256k1_fe_get_b32(&output[1], &lpt->x); secp256k1_fe_get_b32(&output[33], &rpt->x); @@ -23,13 +23,13 @@ static void secp256k1_bulletproofs_serialize_points(unsigned char *output, const /* Outputs a serialized point in compressed form. Returns 0 at point at infinity. */ -static int secp256k1_bulletproofs_serialize_pt(unsigned char *output, secp256k1_ge *lpt) { +static int secp256k1_bppp_serialize_pt(unsigned char *output, secp256k1_ge *lpt) { size_t size; return secp256k1_eckey_pubkey_serialize(lpt, output, &size, 1 /*compressed*/); } /* little-endian encodes a uint64 */ -static void secp256k1_bulletproofs_le64(unsigned char *output, const uint64_t n) { +static void secp256k1_bppp_le64(unsigned char *output, const uint64_t n) { output[0] = n; output[1] = n >> 8; output[2] = n >> 16; @@ -49,7 +49,7 @@ static int secp256k1_is_power_of_two(size_t n) { * `k` such that 2^k <= n. Assumes n < 2^64. In Bulletproofs, this is bounded * by len of input vectors which can be safely assumed to be less than 2^64. */ -static size_t secp256k1_bulletproofs_pp_log2(size_t n) { +static size_t secp256k1_bppp_log2(size_t n) { return 64 - 1 - secp256k1_clz64_var((uint64_t)n); } diff --git a/src/modules/bulletproofs/main.h b/src/modules/bppp/main.h similarity index 50% rename from src/modules/bulletproofs/main.h rename to src/modules/bppp/main.h index 4174102a6..47405f458 100644 --- a/src/modules/bulletproofs/main.h +++ b/src/modules/bppp/main.h @@ -1,8 +1,8 @@ -#ifndef SECP256K1_MODULE_BULLETPROOFS_MAIN_H -#define SECP256K1_MODULE_BULLETPROOFS_MAIN_H +#ifndef SECP256K1_MODULE_BPPP_MAIN_H +#define SECP256K1_MODULE_BPPP_MAIN_H -/* this type must be completed before any of the modules/bulletproofs includes */ -struct secp256k1_bulletproofs_generators { +/* this type must be completed before any of the modules/bppp includes */ +struct secp256k1_bppp_generators { size_t n; /* n total generators; includes both G_i and H_i */ /* For BP++, the generators are G_i from [0..(n - 8)] and the last 8 values diff --git a/src/modules/bulletproofs/main_impl.h b/src/modules/bppp/main_impl.h similarity index 70% rename from src/modules/bulletproofs/main_impl.h rename to src/modules/bppp/main_impl.h index f87b9876b..dfebde10e 100644 --- a/src/modules/bulletproofs/main_impl.h +++ b/src/modules/bppp/main_impl.h @@ -4,26 +4,26 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_MODULE_BULLETPROOFS_MAIN_ -#define _SECP256K1_MODULE_BULLETPROOFS_MAIN_ +#ifndef _SECP256K1_MODULE_BPPP_MAIN_ +#define _SECP256K1_MODULE_BPPP_MAIN_ -#include "include/secp256k1_bulletproofs.h" +#include "include/secp256k1_bppp.h" #include "include/secp256k1_generator.h" #include "modules/generator/main_impl.h" /* for generator_{load, save} */ #include "hash.h" #include "util.h" -#include "modules/bulletproofs/main.h" -#include "modules/bulletproofs/bulletproofs_pp_norm_product_impl.h" +#include "modules/bppp/main.h" +#include "modules/bppp/bppp_norm_product_impl.h" -secp256k1_bulletproofs_generators *secp256k1_bulletproofs_generators_create(const secp256k1_context *ctx, size_t n) { - secp256k1_bulletproofs_generators *ret; +secp256k1_bppp_generators *secp256k1_bppp_generators_create(const secp256k1_context *ctx, size_t n) { + secp256k1_bppp_generators *ret; secp256k1_rfc6979_hmac_sha256 rng; unsigned char seed[64]; size_t i; VERIFY_CHECK(ctx != NULL); - ret = (secp256k1_bulletproofs_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret)); + ret = (secp256k1_bppp_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret)); if (ret == NULL) { return NULL; } @@ -49,9 +49,9 @@ secp256k1_bulletproofs_generators *secp256k1_bulletproofs_generators_create(cons return ret; } -secp256k1_bulletproofs_generators* secp256k1_bulletproofs_generators_parse(const secp256k1_context* ctx, const unsigned char* data, size_t data_len) { +secp256k1_bppp_generators* secp256k1_bppp_generators_parse(const secp256k1_context* ctx, const unsigned char* data, size_t data_len) { size_t n = data_len / 33; - secp256k1_bulletproofs_generators* ret; + secp256k1_bppp_generators* ret; VERIFY_CHECK(ctx != NULL); ARG_CHECK(data != NULL); @@ -60,7 +60,7 @@ secp256k1_bulletproofs_generators* secp256k1_bulletproofs_generators_parse(const return NULL; } - ret = (secp256k1_bulletproofs_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret)); + ret = (secp256k1_bppp_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret)); if (ret == NULL) { return NULL; } @@ -83,7 +83,7 @@ secp256k1_bulletproofs_generators* secp256k1_bulletproofs_generators_parse(const return ret; } -int secp256k1_bulletproofs_generators_serialize(const secp256k1_context* ctx, const secp256k1_bulletproofs_generators* gens, unsigned char* data, size_t *data_len) { +int secp256k1_bppp_generators_serialize(const secp256k1_context* ctx, const secp256k1_bppp_generators* gens, unsigned char* data, size_t *data_len) { size_t i; VERIFY_CHECK(ctx != NULL); @@ -103,7 +103,7 @@ int secp256k1_bulletproofs_generators_serialize(const secp256k1_context* ctx, co return 1; } -void secp256k1_bulletproofs_generators_destroy(const secp256k1_context* ctx, secp256k1_bulletproofs_generators *gens) { +void secp256k1_bppp_generators_destroy(const secp256k1_context* ctx, secp256k1_bppp_generators *gens) { VERIFY_CHECK(ctx != NULL); (void) ctx; if (gens != NULL) { diff --git a/src/modules/bulletproofs/test_vectors/verify.h b/src/modules/bppp/test_vectors/verify.h similarity index 100% rename from src/modules/bulletproofs/test_vectors/verify.h rename to src/modules/bppp/test_vectors/verify.h diff --git a/src/modules/bulletproofs/tests_impl.h b/src/modules/bppp/tests_impl.h similarity index 75% rename from src/modules/bulletproofs/tests_impl.h rename to src/modules/bppp/tests_impl.h index dd3e4130e..ab101facb 100644 --- a/src/modules/bulletproofs/tests_impl.h +++ b/src/modules/bppp/tests_impl.h @@ -4,23 +4,23 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_MODULE_BULLETPROOFS_TEST_ -#define _SECP256K1_MODULE_BULLETPROOFS_TEST_ +#ifndef _SECP256K1_MODULE_BPPP_TEST_ +#define _SECP256K1_MODULE_BPPP_TEST_ #include -#include "include/secp256k1_bulletproofs.h" -#include "bulletproofs_pp_norm_product_impl.h" -#include "bulletproofs_util.h" -#include "bulletproofs_pp_transcript_impl.h" +#include "include/secp256k1_bppp.h" +#include "bppp_norm_product_impl.h" +#include "bppp_util.h" +#include "bppp_transcript_impl.h" #include "test_vectors/verify.h" -static void test_bulletproofs_generators_api(void) { +static void test_bppp_generators_api(void) { /* The BP generator API requires no precomp */ secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - secp256k1_bulletproofs_generators *gens; - secp256k1_bulletproofs_generators *gens_orig; + secp256k1_bppp_generators *gens; + secp256k1_bppp_generators *gens_orig; unsigned char gens_ser[330]; size_t len = sizeof(gens_ser); @@ -30,47 +30,47 @@ static void test_bulletproofs_generators_api(void) { secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); /* Create */ - gens = secp256k1_bulletproofs_generators_create(none, 10); + gens = secp256k1_bppp_generators_create(none, 10); CHECK(gens != NULL && ecount == 0); gens_orig = gens; /* Preserve for round-trip test */ /* Serialize */ ecount = 0; - CHECK(!secp256k1_bulletproofs_generators_serialize(none, NULL, gens_ser, &len)); + CHECK(!secp256k1_bppp_generators_serialize(none, NULL, gens_ser, &len)); CHECK(ecount == 1); - CHECK(!secp256k1_bulletproofs_generators_serialize(none, gens, NULL, &len)); + CHECK(!secp256k1_bppp_generators_serialize(none, gens, NULL, &len)); CHECK(ecount == 2); - CHECK(!secp256k1_bulletproofs_generators_serialize(none, gens, gens_ser, NULL)); + CHECK(!secp256k1_bppp_generators_serialize(none, gens, gens_ser, NULL)); CHECK(ecount == 3); len = 0; - CHECK(!secp256k1_bulletproofs_generators_serialize(none, gens, gens_ser, &len)); + CHECK(!secp256k1_bppp_generators_serialize(none, gens, gens_ser, &len)); CHECK(ecount == 4); len = sizeof(gens_ser) - 1; - CHECK(!secp256k1_bulletproofs_generators_serialize(none, gens, gens_ser, &len)); + CHECK(!secp256k1_bppp_generators_serialize(none, gens, gens_ser, &len)); CHECK(ecount == 5); len = sizeof(gens_ser); { /* Output buffer can be greater than minimum needed */ unsigned char gens_ser_tmp[331]; size_t len_tmp = sizeof(gens_ser_tmp); - CHECK(secp256k1_bulletproofs_generators_serialize(none, gens, gens_ser_tmp, &len_tmp)); + CHECK(secp256k1_bppp_generators_serialize(none, gens, gens_ser_tmp, &len_tmp)); CHECK(len_tmp == sizeof(gens_ser_tmp) - 1); CHECK(ecount == 5); } /* Parse */ - CHECK(secp256k1_bulletproofs_generators_serialize(none, gens, gens_ser, &len)); + CHECK(secp256k1_bppp_generators_serialize(none, gens, gens_ser, &len)); ecount = 0; - gens = secp256k1_bulletproofs_generators_parse(none, NULL, sizeof(gens_ser)); + gens = secp256k1_bppp_generators_parse(none, NULL, sizeof(gens_ser)); CHECK(gens == NULL && ecount == 1); /* Not a multiple of 33 */ - gens = secp256k1_bulletproofs_generators_parse(none, gens_ser, sizeof(gens_ser) - 1); + gens = secp256k1_bppp_generators_parse(none, gens_ser, sizeof(gens_ser) - 1); CHECK(gens == NULL && ecount == 1); - gens = secp256k1_bulletproofs_generators_parse(none, gens_ser, sizeof(gens_ser)); + gens = secp256k1_bppp_generators_parse(none, gens_ser, sizeof(gens_ser)); CHECK(gens != NULL && ecount == 1); /* Not valid generators */ memset(gens_ser, 1, sizeof(gens_ser)); - CHECK(secp256k1_bulletproofs_generators_parse(none, gens_ser, sizeof(gens_ser)) == NULL); + CHECK(secp256k1_bppp_generators_parse(none, gens_ser, sizeof(gens_ser)) == NULL); CHECK(ecount == 1); /* Check that round-trip succeeded */ @@ -81,16 +81,16 @@ static void test_bulletproofs_generators_api(void) { /* Destroy (we allow destroying a NULL context, it's just a noop. like free().) */ ecount = 0; - secp256k1_bulletproofs_generators_destroy(none, NULL); - secp256k1_bulletproofs_generators_destroy(none, gens); - secp256k1_bulletproofs_generators_destroy(none, gens_orig); + secp256k1_bppp_generators_destroy(none, NULL); + secp256k1_bppp_generators_destroy(none, gens); + secp256k1_bppp_generators_destroy(none, gens_orig); CHECK(ecount == 0); secp256k1_context_destroy(none); } -static void test_bulletproofs_generators_fixed(void) { - secp256k1_bulletproofs_generators *gens = secp256k1_bulletproofs_generators_create(ctx, 3); +static void test_bppp_generators_fixed(void) { + secp256k1_bppp_generators *gens = secp256k1_bppp_generators_create(ctx, 3); unsigned char gens_ser[330]; const unsigned char fixed_first_3[99] = { 0x0b, @@ -112,17 +112,17 @@ static void test_bulletproofs_generators_fixed(void) { size_t len; len = 99; - CHECK(secp256k1_bulletproofs_generators_serialize(ctx, gens, gens_ser, &len)); + CHECK(secp256k1_bppp_generators_serialize(ctx, gens, gens_ser, &len)); CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0); len = sizeof(gens_ser); - CHECK(secp256k1_bulletproofs_generators_serialize(ctx, gens, gens_ser, &len)); + CHECK(secp256k1_bppp_generators_serialize(ctx, gens, gens_ser, &len)); CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0); - secp256k1_bulletproofs_generators_destroy(ctx, gens); + secp256k1_bppp_generators_destroy(ctx, gens); } -static void test_bulletproofs_pp_tagged_hash(void) { +static void test_bppp_tagged_hash(void) { unsigned char tag_data[29] = "Bulletproofs_pp/v0/commitment"; secp256k1_sha256 sha; secp256k1_sha256 sha_cached; @@ -131,7 +131,7 @@ static void test_bulletproofs_pp_tagged_hash(void) { secp256k1_scalar s; secp256k1_sha256_initialize_tagged(&sha, tag_data, sizeof(tag_data)); - secp256k1_bulletproofs_pp_sha256_tagged_commitment_init(&sha_cached); + secp256k1_bppp_sha256_tagged_commitment_init(&sha_cached); secp256k1_sha256_finalize(&sha, output); secp256k1_sha256_finalize(&sha_cached, output_cached); CHECK(secp256k1_memcmp_var(output, output_cached, 32) == 0); @@ -141,8 +141,8 @@ static void test_bulletproofs_pp_tagged_hash(void) { 0xF6, 0x91, 0x15, 0xEE, 0x74, 0xF5, 0x12, 0x67, 0x8A, 0x41, 0xC6, 0x85, 0x1A, 0x79, 0x14, 0xFC, 0x48, 0x15, 0xC7, 0x2D, 0xF8, 0x63, 0x8F, 0x1B }; - secp256k1_bulletproofs_pp_sha256_tagged_commitment_init(&sha); - secp256k1_bulletproofs_challenge_scalar(&s, &sha, 0); + secp256k1_bppp_sha256_tagged_commitment_init(&sha); + secp256k1_bppp_challenge_scalar(&s, &sha, 0); secp256k1_scalar_get_b32(output, &s); CHECK(memcmp(output, expected, sizeof(output)) == 0); } @@ -154,7 +154,7 @@ static void test_bulletproofs_pp_tagged_hash(void) { 0x69, 0x4D, 0xAA, 0x96, 0xCE, 0x98, 0xBB, 0x39, 0x1C, 0x2F, 0x7C, 0x2E, 0x1C, 0x17, 0x78, 0x6D }; secp256k1_sha256_write(&sha, tmp, sizeof(tmp)); - secp256k1_bulletproofs_challenge_scalar(&s, &sha, 0); + secp256k1_bppp_challenge_scalar(&s, &sha, 0); secp256k1_scalar_get_b32(output, &s); CHECK(memcmp(output, expected, sizeof(output)) == 0); } @@ -168,11 +168,11 @@ void test_log_exp(void) { CHECK(secp256k1_is_power_of_two(63) == 0); CHECK(secp256k1_is_power_of_two(256) == 1); - CHECK(secp256k1_bulletproofs_pp_log2(1) == 0); - CHECK(secp256k1_bulletproofs_pp_log2(2) == 1); - CHECK(secp256k1_bulletproofs_pp_log2(255) == 7); - CHECK(secp256k1_bulletproofs_pp_log2(256) == 8); - CHECK(secp256k1_bulletproofs_pp_log2(257) == 8); + CHECK(secp256k1_bppp_log2(1) == 0); + CHECK(secp256k1_bppp_log2(2) == 1); + CHECK(secp256k1_bppp_log2(255) == 7); + CHECK(secp256k1_bppp_log2(256) == 8); + CHECK(secp256k1_bppp_log2(257) == 8); } void test_norm_util_helpers(void) { @@ -205,7 +205,7 @@ void test_norm_util_helpers(void) { secp256k1_scalar_set_int(&res2, 4740); /*i*i*4^(i+1) */ CHECK(secp256k1_scalar_eq(&res2, &res) == 1); - secp256k1_bulletproofs_powers_of_r(r_pows, &r, 4); + secp256k1_bppp_powers_of_r(r_pows, &r, 4); secp256k1_scalar_set_int(&res, 2); CHECK(secp256k1_scalar_eq(&res, &r_pows[0])); secp256k1_scalar_set_int(&res, 4); CHECK(secp256k1_scalar_eq(&res, &r_pows[1])); secp256k1_scalar_set_int(&res, 16); CHECK(secp256k1_scalar_eq(&res, &r_pows[2])); @@ -215,7 +215,7 @@ void test_norm_util_helpers(void) { static void secp256k1_norm_arg_commit_initial_data( secp256k1_sha256* transcript, const secp256k1_scalar* r, - const secp256k1_bulletproofs_generators* gens_vec, + const secp256k1_bppp_generators* gens_vec, size_t g_len, /* Same as n_vec_len, g_len + c_vec_len = gens->n */ const secp256k1_scalar* c_vec, size_t c_vec_len, @@ -225,25 +225,25 @@ static void secp256k1_norm_arg_commit_initial_data( unsigned char ser_commit[33], ser_scalar[32], ser_le64[8]; size_t i; secp256k1_ge comm = *commit; - secp256k1_bulletproofs_pp_sha256_tagged_commitment_init(transcript); + secp256k1_bppp_sha256_tagged_commitment_init(transcript); secp256k1_fe_normalize(&comm.x); secp256k1_fe_normalize(&comm.y); CHECK(secp256k1_ge_is_infinity(&comm) == 0); - CHECK(secp256k1_bulletproofs_serialize_pt(&ser_commit[0], &comm)); + CHECK(secp256k1_bppp_serialize_pt(&ser_commit[0], &comm)); secp256k1_sha256_write(transcript, ser_commit, 33); secp256k1_scalar_get_b32(ser_scalar, r); secp256k1_sha256_write(transcript, ser_scalar, 32); - secp256k1_bulletproofs_le64(ser_le64, g_len); + secp256k1_bppp_le64(ser_le64, g_len); secp256k1_sha256_write(transcript, ser_le64, 8); - secp256k1_bulletproofs_le64(ser_le64, gens_vec->n); + secp256k1_bppp_le64(ser_le64, gens_vec->n); secp256k1_sha256_write(transcript, ser_le64, 8); for (i = 0; i < gens_vec->n; i++) { secp256k1_fe_normalize(&gens_vec->gens[i].x); secp256k1_fe_normalize(&gens_vec->gens[i].y); - CHECK(secp256k1_bulletproofs_serialize_pt(&ser_commit[0], &gens_vec->gens[i])); + CHECK(secp256k1_bppp_serialize_pt(&ser_commit[0], &gens_vec->gens[i])); secp256k1_sha256_write(transcript, ser_commit, 33); } - secp256k1_bulletproofs_le64(ser_le64, c_vec_len); + secp256k1_bppp_le64(ser_le64, c_vec_len); secp256k1_sha256_write(transcript, ser_le64, 8); for (i = 0; i < c_vec_len; i++) { secp256k1_scalar_get_b32(ser_scalar, &c_vec[i]); @@ -273,9 +273,9 @@ static void copy_vectors_into_scratch(secp256k1_scratch_space* scratch, memcpy(*gs, gens_vec, (g_len + h_len) * sizeof(secp256k1_ge)); } -/* A complete norm argument. In contrast to secp256k1_bulletproofs_pp_rangeproof_norm_product_prove, this is meant +/* A complete norm argument. In contrast to secp256k1_bppp_rangeproof_norm_product_prove, this is meant to be used as a standalone norm argument. - This is a simple wrapper around secp256k1_bulletproofs_pp_rangeproof_norm_product_prove + This is a simple wrapper around secp256k1_bppp_rangeproof_norm_product_prove that also commits to the initial public values used in the protocol. In this case, these public values are commitment. */ @@ -284,7 +284,7 @@ static int secp256k1_norm_arg_prove( unsigned char* proof, size_t *proof_len, const secp256k1_scalar* r, - const secp256k1_bulletproofs_generators* gens_vec, + const secp256k1_bppp_generators* gens_vec, const secp256k1_scalar* n_vec, size_t n_vec_len, const secp256k1_scalar* l_vec, @@ -307,7 +307,7 @@ static int secp256k1_norm_arg_prove( /* Commit to the initial public values */ secp256k1_norm_arg_commit_initial_data(&transcript, r, gens_vec, g_len, c_vec, c_vec_len, &comm); - res = secp256k1_bulletproofs_pp_rangeproof_norm_product_prove( + res = secp256k1_bppp_rangeproof_norm_product_prove( ctx, scratch, proof, @@ -333,7 +333,7 @@ static int secp256k1_norm_arg_verify( const unsigned char* proof, size_t proof_len, const secp256k1_scalar* r, - const secp256k1_bulletproofs_generators* gens_vec, + const secp256k1_bppp_generators* gens_vec, size_t g_len, const secp256k1_scalar* c_vec, size_t c_vec_len, @@ -346,7 +346,7 @@ static int secp256k1_norm_arg_verify( /* Commit to the initial public values */ secp256k1_norm_arg_commit_initial_data(&transcript, r, gens_vec, g_len, c_vec, c_vec_len, &comm); - res = secp256k1_bulletproofs_pp_rangeproof_norm_product_verify( + res = secp256k1_bppp_rangeproof_norm_product_verify( ctx, scratch, proof, @@ -379,26 +379,26 @@ void norm_arg_zero(void) { size_t plen = sizeof(proof); unsigned int n_vec_len = 1; unsigned int c_vec_len = 1; - secp256k1_bulletproofs_generators *gens = secp256k1_bulletproofs_generators_create(ctx, n_vec_len + c_vec_len); + secp256k1_bppp_generators *gens = secp256k1_bppp_generators_create(ctx, n_vec_len + c_vec_len); secp256k1_scalar_set_int(&n_vec[0], 0); secp256k1_scalar_set_int(&l_vec[0], 0); random_scalar_order(&c_vec[0]); secp256k1_sha256_initialize(&transcript); /* No challenges used in n = 1, l = 1, but we set transcript as a good practice*/ - CHECK(secp256k1_bulletproofs_commit(ctx, scratch, &commit, gens, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &q)); + CHECK(secp256k1_bppp_commit(ctx, scratch, &commit, gens, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &q)); { secp256k1_scalar *ns, *ls, *cs; secp256k1_ge *gs; size_t scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch); copy_vectors_into_scratch(scratch, &ns, &ls, &cs, &gs, n_vec, l_vec, c_vec, gens->gens, n_vec_len, c_vec_len); - CHECK(secp256k1_bulletproofs_pp_rangeproof_norm_product_prove(ctx, scratch, proof, &plen, &transcript, &r, gs, gens->n, ns, n_vec_len, ls, c_vec_len, cs, c_vec_len)); + CHECK(secp256k1_bppp_rangeproof_norm_product_prove(ctx, scratch, proof, &plen, &transcript, &r, gs, gens->n, ns, n_vec_len, ls, c_vec_len, cs, c_vec_len)); secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); } secp256k1_sha256_initialize(&transcript); - CHECK(secp256k1_bulletproofs_pp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &r, gens, c_vec_len, c_vec, c_vec_len, &commit)); + CHECK(secp256k1_bppp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &r, gens, c_vec_len, c_vec, c_vec_len, &commit)); - secp256k1_bulletproofs_generators_destroy(ctx, gens); + secp256k1_bppp_generators_destroy(ctx, gens); } /* l is the zero vector and longer than n. This results in one of the @@ -406,7 +406,7 @@ void norm_arg_zero(void) { { unsigned int n_vec_len = 1; unsigned int c_vec_len = 2; - secp256k1_bulletproofs_generators *gs = secp256k1_bulletproofs_generators_create(ctx, n_vec_len + c_vec_len); + secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(ctx, n_vec_len + c_vec_len); size_t plen = sizeof(proof); for (i = 0; i < n_vec_len; i++) { random_scalar_order(&n_vec[i]); @@ -415,9 +415,9 @@ void norm_arg_zero(void) { secp256k1_scalar_set_int(&l_vec[i], 0); random_scalar_order(&c_vec[i]); } - CHECK(secp256k1_bulletproofs_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &q)); + CHECK(secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &q)); CHECK(!secp256k1_norm_arg_prove(scratch, proof, &plen, &r, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &commit)); - secp256k1_bulletproofs_generators_destroy(ctx, gs); + secp256k1_bppp_generators_destroy(ctx, gs); } secp256k1_scratch_space_destroy(ctx, scratch); @@ -429,7 +429,7 @@ void norm_arg_test(unsigned int n, unsigned int m) { secp256k1_ge commit; size_t i, plen; int res; - secp256k1_bulletproofs_generators *gs = secp256k1_bulletproofs_generators_create(ctx, n + m); + secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(ctx, n + m); secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*1000); /* shouldn't need much */ unsigned char proof[1000]; plen = 1000; @@ -445,7 +445,7 @@ void norm_arg_test(unsigned int n, unsigned int m) { random_scalar_order(&c_vec[i]); } - res = secp256k1_bulletproofs_commit(ctx, scratch, &commit, gs, n_vec, n, l_vec, m, c_vec, m, &q); + res = secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n, l_vec, m, c_vec, m, &q); CHECK(res == 1); res = secp256k1_norm_arg_prove(scratch, proof, &plen, &r, gs, n_vec, n, l_vec, m, c_vec, m, &commit); CHECK(res == 1); @@ -462,13 +462,13 @@ void norm_arg_test(unsigned int n, unsigned int m) { CHECK(res == 0); secp256k1_scratch_space_destroy(ctx, scratch); - secp256k1_bulletproofs_generators_destroy(ctx, gs); + secp256k1_bppp_generators_destroy(ctx, gs); } /* Parses generators from points compressed as pubkeys */ -secp256k1_bulletproofs_generators* bulletproofs_generators_parse_regular(const unsigned char* data, size_t data_len) { +secp256k1_bppp_generators* bppp_generators_parse_regular(const unsigned char* data, size_t data_len) { size_t n = data_len / 33; - secp256k1_bulletproofs_generators* ret; + secp256k1_bppp_generators* ret; VERIFY_CHECK(ctx != NULL); ARG_CHECK(data != NULL); @@ -477,7 +477,7 @@ secp256k1_bulletproofs_generators* bulletproofs_generators_parse_regular(const u return NULL; } - ret = (secp256k1_bulletproofs_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret)); + ret = (secp256k1_bppp_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret)); if (ret == NULL) { return NULL; } @@ -500,7 +500,7 @@ secp256k1_bulletproofs_generators* bulletproofs_generators_parse_regular(const u int norm_arg_verify_vectors_helper(secp256k1_scratch *scratch, const unsigned char *gens, const unsigned char *proof, size_t plen, const unsigned char *r32, size_t n_vec_len, const unsigned char c_vec32[][32], secp256k1_scalar *c_vec, size_t c_vec_len, const unsigned char *commit33) { secp256k1_sha256 transcript; - secp256k1_bulletproofs_generators *gs = bulletproofs_generators_parse_regular(gens, 33*(n_vec_len + c_vec_len)); + secp256k1_bppp_generators *gs = bppp_generators_parse_regular(gens, 33*(n_vec_len + c_vec_len)); secp256k1_scalar r; secp256k1_ge commit; int overflow; @@ -518,9 +518,9 @@ int norm_arg_verify_vectors_helper(secp256k1_scratch *scratch, const unsigned ch CHECK(!overflow); } CHECK(secp256k1_eckey_pubkey_parse(&commit, commit33, 33)); - ret = secp256k1_bulletproofs_pp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &r, gs, n_vec_len, c_vec, c_vec_len, &commit); + ret = secp256k1_bppp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &r, gs, n_vec_len, c_vec, c_vec_len, &commit); - secp256k1_bulletproofs_generators_destroy(ctx, gs); + secp256k1_bppp_generators_destroy(ctx, gs); return ret; } @@ -545,12 +545,12 @@ void norm_arg_verify_vectors(void) { } #undef IDX_TO_TEST -void run_bulletproofs_tests(void) { +void run_bppp_tests(void) { test_log_exp(); test_norm_util_helpers(); - test_bulletproofs_generators_api(); - test_bulletproofs_generators_fixed(); - test_bulletproofs_pp_tagged_hash(); + test_bppp_generators_api(); + test_bppp_generators_fixed(); + test_bppp_tagged_hash(); norm_arg_zero(); norm_arg_test(1, 1); diff --git a/src/modules/bulletproofs/Makefile.am.include b/src/modules/bulletproofs/Makefile.am.include deleted file mode 100644 index cfd0916d2..000000000 --- a/src/modules/bulletproofs/Makefile.am.include +++ /dev/null @@ -1,13 +0,0 @@ -include_HEADERS += include/secp256k1_bulletproofs.h -noinst_HEADERS += src/modules/bulletproofs/bulletproofs_util.h -noinst_HEADERS += src/modules/bulletproofs/main_impl.h -noinst_HEADERS += src/modules/bulletproofs/bulletproofs_pp_transcript_impl.h -noinst_HEADERS += src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h -noinst_HEADERS += src/modules/bulletproofs/tests_impl.h - -if USE_BENCHMARK -noinst_PROGRAMS += bench_bulletproofs -bench_bulletproofs_SOURCES = src/bench_bulletproofs.c -bench_bulletproofs_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_bulletproofs_LDFLAGS = -static -endif diff --git a/src/secp256k1.c b/src/secp256k1.c index 857e9a76e..c147eae5f 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -800,8 +800,8 @@ int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32, return 1; } -#ifdef ENABLE_MODULE_BULLETPROOFS -# include "modules/bulletproofs/main_impl.h" +#ifdef ENABLE_MODULE_BPPP +# include "modules/bppp/main_impl.h" #endif #ifdef ENABLE_MODULE_ECDH diff --git a/src/tests.c b/src/tests.c index fc84b3cb1..9e7efe3ad 100644 --- a/src/tests.c +++ b/src/tests.c @@ -7132,8 +7132,8 @@ void run_ecdsa_edge_cases(void) { test_ecdsa_edge_cases(); } -#ifdef ENABLE_MODULE_BULLETPROOFS -# include "modules/bulletproofs/tests_impl.h" +#ifdef ENABLE_MODULE_BPPP +# include "modules/bppp/tests_impl.h" #endif #ifdef ENABLE_MODULE_ECDH @@ -7456,8 +7456,8 @@ int main(int argc, char **argv) { /* EC key arithmetic test */ run_eckey_negate_test(); -#ifdef ENABLE_MODULE_BULLETPROOFS - run_bulletproofs_tests(); +#ifdef ENABLE_MODULE_BPPP + run_bppp_tests(); #endif #ifdef ENABLE_MODULE_ECDH From d7fb25c8ca5bda0e969ce94ccabedfd7b8432769 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 9 Feb 2023 21:31:43 +0000 Subject: [PATCH 18/18] Make sure that bppp_log2 isn't called with value 0 Author: Jonas Nick Date: Thu Feb 9 21:31:43 2023 +0000 --- src/modules/bppp/bppp_norm_product_impl.h | 19 +++++++++++++++---- src/modules/bppp/bppp_util.h | 7 ++++--- src/modules/bppp/tests_impl.h | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/modules/bppp/bppp_norm_product_impl.h b/src/modules/bppp/bppp_norm_product_impl.h index 9d61b0d05..ecb758c36 100644 --- a/src/modules/bppp/bppp_norm_product_impl.h +++ b/src/modules/bppp/bppp_norm_product_impl.h @@ -238,9 +238,13 @@ static int secp256k1_bppp_rangeproof_norm_product_prove( ecmult_r_cb_data r_cb_data; size_t g_len = n_vec_len, h_len = l_vec_len; const size_t G_GENS_LEN = g_len; - size_t log_g_len = secp256k1_bppp_log2(g_len), log_h_len = secp256k1_bppp_log2(h_len); - size_t num_rounds = log_g_len > log_h_len ? log_g_len : log_h_len; + size_t log_g_len, log_h_len; + size_t num_rounds; + VERIFY_CHECK(g_len > 0 && h_len > 0); + log_g_len = secp256k1_bppp_log2(g_len); + log_h_len = secp256k1_bppp_log2(h_len); + num_rounds = log_g_len > log_h_len ? log_g_len : log_h_len; /* Check proof sizes.*/ VERIFY_CHECK(*proof_len >= 65 * num_rounds + 64); VERIFY_CHECK(g_vec_len == (n_vec_len + l_vec_len) && l_vec_len == c_vec_len); @@ -440,10 +444,17 @@ static int secp256k1_bppp_rangeproof_norm_product_verify( secp256k1_gej res1, res2; size_t i = 0, scratch_checkpoint; int overflow; - size_t log_g_len = secp256k1_bppp_log2(g_len), log_h_len = secp256k1_bppp_log2(c_vec_len); - size_t n_rounds = log_g_len > log_h_len ? log_g_len : log_h_len; + size_t log_g_len, log_h_len; + size_t n_rounds; size_t h_len = c_vec_len; + if (g_len == 0 || c_vec_len == 0) { + return 0; + } + log_g_len = secp256k1_bppp_log2(g_len); + log_h_len = secp256k1_bppp_log2(c_vec_len); + n_rounds = log_g_len > log_h_len ? log_g_len : log_h_len; + if (g_vec->n != (h_len + g_len) || (proof_len != 65 * n_rounds + 64)) { return 0; } diff --git a/src/modules/bppp/bppp_util.h b/src/modules/bppp/bppp_util.h index 10c58bb7d..fd04ae691 100644 --- a/src/modules/bppp/bppp_util.h +++ b/src/modules/bppp/bppp_util.h @@ -45,9 +45,10 @@ static int secp256k1_is_power_of_two(size_t n) { return n > 0 && (n & (n - 1)) == 0; } -/* Compute the log2 of n. If n is not a power of two, it returns the largest - * `k` such that 2^k <= n. Assumes n < 2^64. In Bulletproofs, this is bounded - * by len of input vectors which can be safely assumed to be less than 2^64. +/* Compute the log2 of n. n must NOT be 0. If n is not a power of two, it + * returns the largest `k` such that 2^k <= n. Assumes 0 < n < 2^64. In + * Bulletproofs, this is bounded by len of input vectors which can be safely + * assumed to be less than 2^64. */ static size_t secp256k1_bppp_log2(size_t n) { return 64 - 1 - secp256k1_clz64_var((uint64_t)n); diff --git a/src/modules/bppp/tests_impl.h b/src/modules/bppp/tests_impl.h index ab101facb..e92316566 100644 --- a/src/modules/bppp/tests_impl.h +++ b/src/modules/bppp/tests_impl.h @@ -420,6 +420,24 @@ void norm_arg_zero(void) { secp256k1_bppp_generators_destroy(ctx, gs); } + /* Verify vectors of length 0 */ + { + unsigned int n_vec_len = 1; + unsigned int c_vec_len = 1; + secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(ctx, n_vec_len + c_vec_len); + size_t plen = sizeof(proof); + random_scalar_order(&n_vec[0]); + random_scalar_order(&c_vec[0]); + random_scalar_order(&l_vec[0]); + CHECK(secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &q)); + CHECK(secp256k1_norm_arg_prove(scratch, proof, &plen, &r, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &commit)); + CHECK(secp256k1_norm_arg_verify(scratch, proof, plen, &r, gs, n_vec_len, c_vec, c_vec_len, &commit)); + CHECK(!secp256k1_norm_arg_verify(scratch, proof, plen, &r, gs, 0, c_vec, c_vec_len, &commit)); + CHECK(!secp256k1_norm_arg_verify(scratch, proof, plen, &r, gs, n_vec_len, c_vec, 0, &commit)); + + secp256k1_bppp_generators_destroy(ctx, gs); + } + secp256k1_scratch_space_destroy(ctx, scratch); }