bulletproofs: add API functionality to generate a large set of generators
This commit is contained in:
parent
048f9f8642
commit
48563c8c79
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user