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>
|
#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
|
# ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,113 @@
|
|||||||
#ifndef _SECP256K1_MODULE_BULLETPROOFS_MAIN_
|
#ifndef _SECP256K1_MODULE_BULLETPROOFS_MAIN_
|
||||||
#define _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
|
#endif
|
||||||
|
@ -7,8 +7,116 @@
|
|||||||
#ifndef _SECP256K1_MODULE_BULLETPROOFS_TEST_
|
#ifndef _SECP256K1_MODULE_BULLETPROOFS_TEST_
|
||||||
#define _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) {
|
void run_bulletproofs_tests(void) {
|
||||||
/* TODO */
|
test_bulletproofs_generators_api();
|
||||||
|
test_bulletproofs_generators_fixed();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user