Skip to content

Commit 107f5e3

Browse files
committed
bulletproofs: add API functionality to generate a large set of generators
1 parent b83c814 commit 107f5e3

File tree

3 files changed

+255
-3
lines changed

3 files changed

+255
-3
lines changed

include/secp256k1_bulletproofs.h

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,57 @@ extern "C" {
99

1010
#include <stdint.h>
1111

12-
/* TODO */
12+
/** Opaque structure representing a large number of NUMS generators */
13+
typedef struct secp256k1_bulletproofs_generators secp256k1_bulletproofs_generators;
14+
15+
/** Allocates and initializes a list of NUMS generators
16+
* Returns a list of generators, or NULL if allocation failed.
17+
* Args: ctx: pointer to a context object
18+
* n: number of NUMS generators to produce. Should be 128 to allow for
19+
* 64-bit rangeproofs
20+
*/
21+
SECP256K1_API secp256k1_bulletproofs_generators *secp256k1_bulletproofs_generators_create(
22+
const secp256k1_context* ctx,
23+
size_t n
24+
) SECP256K1_ARG_NONNULL(1);
25+
26+
/** Allocates a list of generators from a static array
27+
* Returns a list of generators, or NULL if allocation or parsing failed.
28+
* Args: ctx: pointer to a context object
29+
* In: data: data that came from `secp256k1_bulletproofs_generators_serialize`
30+
* data_len: the length of the `data` buffer
31+
*/
32+
SECP256K1_API secp256k1_bulletproofs_generators* secp256k1_bulletproofs_generators_parse(
33+
const secp256k1_context* ctx,
34+
const unsigned char* data,
35+
size_t data_len
36+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
37+
38+
/** Serializes a list of generators to an array
39+
* Returns 1 on success, 0 if the provided array was not large enough
40+
* Args: ctx: pointer to a context object
41+
* gen: pointer to the generator set to be serialized
42+
* In: data: data that came from `secp256k1_bulletproofs_generators_serialize`
43+
* In/Out: data_len: the length of the `data` buffer. Should be initially set to at
44+
* least 33 times the number of generators; will be set to 33 times
45+
* the number of generators on successful return
46+
*/
47+
SECP256K1_API int secp256k1_bulletproofs_generators_serialize(
48+
const secp256k1_context* ctx,
49+
const secp256k1_bulletproofs_generators* gen,
50+
unsigned char* data,
51+
size_t *data_len
52+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
53+
54+
/** Destroys a list of NUMS generators, freeing allocated memory
55+
* Args: ctx: pointer to a context object
56+
* gen: pointer to the generator set to be destroyed
57+
* (can be NULL, in which case this function is a no-op)
58+
*/
59+
SECP256K1_API void secp256k1_bulletproofs_generators_destroy(
60+
const secp256k1_context* ctx,
61+
secp256k1_bulletproofs_generators* gen
62+
) SECP256K1_ARG_NONNULL(1);
1363

1464
# ifdef __cplusplus
1565
}

src/modules/bulletproofs/main_impl.h

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,116 @@
77
#ifndef _SECP256K1_MODULE_BULLETPROOFS_MAIN_
88
#define _SECP256K1_MODULE_BULLETPROOFS_MAIN_
99

10-
/* TODO */
10+
#include "include/secp256k1_bulletproofs.h"
11+
#include "include/secp256k1_generator.h"
12+
#include "modules/generator/main_impl.h" /* for generator_{load, save} */
13+
#include "hash.h"
14+
#include "util.h"
15+
16+
struct secp256k1_bulletproofs_generators {
17+
size_t n;
18+
/* n total generators; set n = 2*k to get G_i and H_i values for i in [1..k] */
19+
secp256k1_ge* gens;
20+
};
21+
22+
secp256k1_bulletproofs_generators *secp256k1_bulletproofs_generators_create(const secp256k1_context *ctx, size_t n) {
23+
secp256k1_bulletproofs_generators *ret;
24+
secp256k1_rfc6979_hmac_sha256 rng;
25+
unsigned char seed[64];
26+
size_t i;
27+
28+
VERIFY_CHECK(ctx != NULL);
29+
30+
ret = (secp256k1_bulletproofs_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret));
31+
if (ret == NULL) {
32+
return NULL;
33+
}
34+
ret->gens = (secp256k1_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens));
35+
if (ret->gens == NULL) {
36+
free(ret);
37+
return NULL;
38+
}
39+
ret->n = n;
40+
41+
secp256k1_fe_get_b32(&seed[0], &secp256k1_ge_const_g.x);
42+
secp256k1_fe_get_b32(&seed[32], &secp256k1_ge_const_g.y);
43+
44+
secp256k1_rfc6979_hmac_sha256_initialize(&rng, seed, 64);
45+
for (i = 0; i < n; i++) {
46+
secp256k1_generator gen;
47+
unsigned char tmp[32] = { 0 };
48+
secp256k1_rfc6979_hmac_sha256_generate(&rng, tmp, 32);
49+
CHECK(secp256k1_generator_generate(ctx, &gen, tmp));
50+
secp256k1_generator_load(&ret->gens[i], &gen);
51+
}
52+
53+
return ret;
54+
}
55+
56+
secp256k1_bulletproofs_generators* secp256k1_bulletproofs_generators_parse(const secp256k1_context* ctx, const unsigned char* data, size_t data_len) {
57+
size_t n = data_len / 33;
58+
secp256k1_bulletproofs_generators* ret;
59+
60+
VERIFY_CHECK(ctx != NULL);
61+
ARG_CHECK(data != NULL);
62+
63+
if (data_len % 33 != 0) {
64+
return NULL;
65+
}
66+
67+
ret = (secp256k1_bulletproofs_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret));
68+
if (ret == NULL) {
69+
return NULL;
70+
}
71+
ret->gens = (secp256k1_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens));
72+
if (ret->gens == NULL) {
73+
free(ret);
74+
return NULL;
75+
}
76+
77+
while (n--) {
78+
secp256k1_generator gen;
79+
if (!secp256k1_generator_parse(ctx, &gen, &data[33 * n])) {
80+
free(ret->gens);
81+
free(ret);
82+
return NULL;
83+
}
84+
secp256k1_generator_load(&ret->gens[n], &gen);
85+
}
86+
return ret;
87+
}
88+
89+
int secp256k1_bulletproofs_generators_serialize(const secp256k1_context* ctx, const secp256k1_bulletproofs_generators* gens, unsigned char* data, size_t *data_len) {
90+
size_t i;
91+
92+
VERIFY_CHECK(ctx != NULL);
93+
ARG_CHECK(gens != NULL);
94+
ARG_CHECK(data != NULL);
95+
ARG_CHECK(data_len != NULL);
96+
97+
memset(data, 0, *data_len);
98+
if (*data_len < 33 * gens->n) {
99+
return 0;
100+
}
101+
for (i = 0; i < gens->n; i++) {
102+
secp256k1_generator gen;
103+
secp256k1_generator_save(&gen, &gens->gens[i]);
104+
if (!secp256k1_generator_serialize(ctx, &data[33 * i], &gen)) {
105+
return 0;
106+
}
107+
}
108+
109+
*data_len = 33 * gens->n;
110+
return 1;
111+
}
112+
113+
void secp256k1_bulletproofs_generators_destroy(const secp256k1_context* ctx, secp256k1_bulletproofs_generators *gens) {
114+
VERIFY_CHECK(ctx != NULL);
115+
(void) ctx;
116+
if (gens != NULL) {
117+
free(gens->gens);
118+
free(gens);
119+
}
120+
}
11121

12122
#endif

src/modules/bulletproofs/tests_impl.h

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,100 @@
77
#ifndef _SECP256K1_MODULE_BULLETPROOFS_TEST_
88
#define _SECP256K1_MODULE_BULLETPROOFS_TEST_
99

10+
static void test_bulletproofs_generators_api(void) {
11+
/* The BP generator API requires no precomp */
12+
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
13+
14+
secp256k1_bulletproofs_generators *gens;
15+
unsigned char gens_ser[330];
16+
size_t len = sizeof(gens_ser);
17+
18+
int32_t ecount = 0;
19+
20+
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
21+
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
22+
23+
/* Create */
24+
gens = secp256k1_bulletproofs_generators_create(none, 10);
25+
CHECK(gens != NULL && ecount == 0);
26+
27+
/* Serialize */
28+
ecount = 0;
29+
CHECK(!secp256k1_bulletproofs_generators_serialize(none, NULL, gens_ser, &len));
30+
CHECK(ecount == 1);
31+
CHECK(!secp256k1_bulletproofs_generators_serialize(none, gens, NULL, &len));
32+
CHECK(ecount == 2);
33+
CHECK(!secp256k1_bulletproofs_generators_serialize(none, gens, gens_ser, NULL));
34+
CHECK(ecount == 3);
35+
len = 0;
36+
CHECK(!secp256k1_bulletproofs_generators_serialize(none, gens, gens_ser, &len));
37+
len = sizeof(gens_ser) - 1;
38+
CHECK(!secp256k1_bulletproofs_generators_serialize(none, gens, gens_ser, &len));
39+
len = sizeof(gens_ser) + 1; /* len can be greater than minimum needed */
40+
CHECK(secp256k1_bulletproofs_generators_serialize(none, gens, gens_ser, &len));
41+
CHECK(len == sizeof(gens_ser));
42+
CHECK(ecount == 3);
43+
44+
/* Parse */
45+
ecount = 0;
46+
secp256k1_bulletproofs_generators_destroy(none, gens); /* avoid leaking memory */
47+
gens = secp256k1_bulletproofs_generators_parse(none, NULL, sizeof(gens_ser));
48+
CHECK(gens == NULL && ecount == 1);
49+
/* Not a multiple of 33 */
50+
gens = secp256k1_bulletproofs_generators_parse(none, gens_ser, sizeof(gens_ser) - 1);
51+
CHECK(gens == NULL && ecount == 1);
52+
gens = secp256k1_bulletproofs_generators_parse(none, gens_ser, sizeof(gens_ser));
53+
CHECK(gens != NULL && ecount == 1);
54+
/* Not valid generators */
55+
memset(gens_ser, 1, sizeof(gens_ser));
56+
gens = secp256k1_bulletproofs_generators_parse(none, gens_ser, sizeof(gens_ser));
57+
CHECK(gens == NULL && ecount == 1);
58+
59+
/* Destroy (we allow destroying a NULL context, it's just a noop. like free().) */
60+
ecount = 0;
61+
secp256k1_bulletproofs_generators_destroy(none, NULL);
62+
secp256k1_bulletproofs_generators_destroy(none, gens);
63+
CHECK(ecount == 0);
64+
65+
secp256k1_context_destroy(none);
66+
}
67+
68+
static void test_bulletproofs_generators_fixed(void) {
69+
secp256k1_bulletproofs_generators *gens = secp256k1_bulletproofs_generators_create(ctx, 3);
70+
unsigned char gens_ser[330];
71+
const unsigned char fixed_first_3[99] = {
72+
0x0b,
73+
0xb3, 0x4d, 0x5f, 0xa6, 0xb8, 0xf3, 0xd1, 0x38,
74+
0x49, 0xce, 0x51, 0x91, 0xb7, 0xf6, 0x76, 0x18,
75+
0xfe, 0x5b, 0xd1, 0x2a, 0x88, 0xb2, 0x0e, 0xac,
76+
0x33, 0x89, 0x45, 0x66, 0x7f, 0xb3, 0x30, 0x56,
77+
0x0a,
78+
0x62, 0x86, 0x15, 0x16, 0x92, 0x42, 0x10, 0x9e,
79+
0x9e, 0x64, 0xd4, 0xcb, 0x28, 0x81, 0x60, 0x9c,
80+
0x24, 0xb9, 0x89, 0x51, 0x2a, 0xd9, 0x01, 0xae,
81+
0xff, 0x75, 0x64, 0x9c, 0x37, 0x5d, 0xbd, 0x79,
82+
0x0a,
83+
0xed, 0xe0, 0x6e, 0x07, 0x5e, 0x79, 0xd0, 0xf7,
84+
0x7b, 0x03, 0x3e, 0xb9, 0xa9, 0x21, 0xa4, 0x5b,
85+
0x99, 0xf3, 0x9b, 0xee, 0xfe, 0xa0, 0x37, 0xa2,
86+
0x1f, 0xe9, 0xd7, 0x4f, 0x95, 0x8b, 0x10, 0xe2,
87+
};
88+
size_t len;
89+
90+
len = 99;
91+
CHECK(secp256k1_bulletproofs_generators_serialize(ctx, gens, gens_ser, &len));
92+
CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0);
93+
94+
len = sizeof(gens_ser);
95+
CHECK(secp256k1_bulletproofs_generators_serialize(ctx, gens, gens_ser, &len));
96+
CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0);
97+
98+
secp256k1_bulletproofs_generators_destroy(ctx, gens);
99+
}
100+
10101
void run_bulletproofs_tests(void) {
11-
/* TODO */
102+
test_bulletproofs_generators_api();
103+
test_bulletproofs_generators_fixed();
12104
}
13105

14106
#endif

0 commit comments

Comments
 (0)