bulletproofs: add API functionality to generate a large set of generators

This commit is contained in:
Andrew Poelstra 2020-11-12 03:22:44 +00:00 committed by sanket1729
parent 048f9f8642
commit 48563c8c79
3 changed files with 273 additions and 3 deletions

View File

@ -9,7 +9,62 @@ extern "C" {
#include <stdint.h>
/* 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
}

View File

@ -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

View File

@ -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