Skip to content

Commit 05e1d6c

Browse files
committed
bulletproofs: implement step 0 of the uncompressed prover
1 parent 107f5e3 commit 05e1d6c

File tree

5 files changed

+240
-7
lines changed

5 files changed

+240
-7
lines changed

include/secp256k1_bulletproofs.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,21 @@ extern "C" {
99

1010
#include <stdint.h>
1111

12+
/** Opaque data structure that holds the current state of an uncompressed
13+
* Bulletproof proof generation. This data is not secret and does not need
14+
* to be handled carefully, but neither does it have any meaning outside
15+
* of the API functions that use it.
16+
*
17+
* Obviously you should not modify it or else you will get invalid proofs.
18+
*
19+
* Typical users do not need this structure. If you have more than a few
20+
* hundred bytes of memory to spare create a proof in one shot with the
21+
* TODO function instead.
22+
*/
23+
typedef struct {
24+
unsigned char data[160];
25+
} secp256k1_bulletproofs_prover_context;
26+
1227
/** Opaque structure representing a large number of NUMS generators */
1328
typedef struct secp256k1_bulletproofs_generators secp256k1_bulletproofs_generators;
1429

src/modules/bulletproofs/Makefile.am.include

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
include_HEADERS += include/secp256k1_bulletproofs.h
2-
noinst_HEADERS += src/modules/bulletproofs/tests_impl.h
2+
noinst_HEADERS += src/modules/bulletproofs/bulletproofs_util.h
33
noinst_HEADERS += src/modules/bulletproofs/main_impl.h
4+
noinst_HEADERS += src/modules/bulletproofs/rangeproof_uncompressed_impl.h
5+
noinst_HEADERS += src/modules/bulletproofs/tests_impl.h
46

57
if USE_BENCHMARK
68
noinst_PROGRAMS += bench_bulletproofs
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**********************************************************************
2+
* Copyright (c) 2020 Andrew Poelstra *
3+
* Distributed under the MIT software license, see the accompanying *
4+
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
5+
**********************************************************************/
6+
7+
#ifndef _SECP256K1_MODULE_BULLETPROOFS_UTIL_
8+
#define _SECP256K1_MODULE_BULLETPROOFS_UTIL_
9+
10+
#include "field.h"
11+
#include "group.h"
12+
#include "hash.h"
13+
14+
/* Outputs a pair of points, amortizing the parity byte between them
15+
* Assumes both points' coordinates have been normalized.
16+
*/
17+
static void secp256k1_bulletproofs_serialize_points(unsigned char *output, const secp256k1_ge *lpt, const secp256k1_ge *rpt) {
18+
output[0] = (secp256k1_fe_is_odd(&lpt->y) << 1) + secp256k1_fe_is_odd(&rpt->y);
19+
secp256k1_fe_get_b32(&output[1], &lpt->x);
20+
secp256k1_fe_get_b32(&output[33], &rpt->x);
21+
}
22+
23+
/* little-endian encodes a uint64 */
24+
static void secp256k1_bulletproofs_le64(unsigned char *output, const uint64_t n) {
25+
output[0] = n;
26+
output[1] = n >> 8;
27+
output[2] = n >> 16;
28+
output[3] = n >> 24;
29+
output[4] = n >> 32;
30+
output[5] = n >> 40;
31+
output[6] = n >> 48;
32+
output[7] = n >> 56;
33+
}
34+
35+
static void secp256k1_bulletproofs_commit_initial_data(
36+
unsigned char* commit,
37+
unsigned char* scratch,
38+
const uint64_t n_bits,
39+
const uint64_t min_value,
40+
const secp256k1_ge* commitp,
41+
const secp256k1_ge* asset_genp,
42+
const unsigned char* extra_commit,
43+
size_t extra_commit_len
44+
) {
45+
secp256k1_sha256 sha256;
46+
secp256k1_sha256_initialize(&sha256);
47+
/* FIXME use tagged hash here */
48+
secp256k1_bulletproofs_le64(scratch, n_bits);
49+
secp256k1_sha256_write(&sha256, scratch, 8);
50+
secp256k1_bulletproofs_le64(scratch, min_value);
51+
secp256k1_sha256_write(&sha256, scratch, 8);
52+
secp256k1_bulletproofs_serialize_points(scratch, commitp, asset_genp);
53+
secp256k1_sha256_write(&sha256, scratch, 65);
54+
if (extra_commit != NULL) {
55+
secp256k1_bulletproofs_le64(scratch, (uint64_t) extra_commit_len);
56+
secp256k1_sha256_write(&sha256, scratch, 8);
57+
secp256k1_sha256_write(&sha256, extra_commit, extra_commit_len);
58+
}
59+
secp256k1_sha256_finalize(&sha256, commit);
60+
}
61+
62+
#endif

src/modules/bulletproofs/main_impl.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,20 @@
77
#ifndef _SECP256K1_MODULE_BULLETPROOFS_MAIN_
88
#define _SECP256K1_MODULE_BULLETPROOFS_MAIN_
99

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-
10+
/* this type must be completed before any of the modules/bulletproofs includes */
1611
struct secp256k1_bulletproofs_generators {
1712
size_t n;
1813
/* n total generators; set n = 2*k to get G_i and H_i values for i in [1..k] */
1914
secp256k1_ge* gens;
2015
};
2116

17+
#include "include/secp256k1_bulletproofs.h"
18+
#include "include/secp256k1_generator.h"
19+
#include "modules/bulletproofs/rangeproof_uncompressed_impl.h"
20+
#include "modules/generator/main_impl.h" /* for generator_{load, save} */
21+
#include "hash.h"
22+
#include "util.h"
23+
2224
secp256k1_bulletproofs_generators *secp256k1_bulletproofs_generators_create(const secp256k1_context *ctx, size_t n) {
2325
secp256k1_bulletproofs_generators *ret;
2426
secp256k1_rfc6979_hmac_sha256 rng;
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/**********************************************************************
2+
* Copyright (c) 2020 Andrew Poelstra *
3+
* Distributed under the MIT software license, see the accompanying *
4+
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
5+
**********************************************************************/
6+
7+
#ifndef _SECP256K1_MODULE_BULLETPROOFS_RP_UNCOMPRESSED_
8+
#define _SECP256K1_MODULE_BULLETPROOFS_RP_UNCOMPRESSED_
9+
10+
#include "group.h"
11+
#include "scalar.h"
12+
13+
#include "modules/bulletproofs/bulletproofs_util.h"
14+
15+
/* Prover context data:
16+
* bytes 0-32: x (hash challenge)
17+
* bytes 32-64: y (hash challenge)
18+
* bytes 64-96: z (hash challenge)
19+
* bytes 96-160: lr_generator data
20+
*/
21+
22+
/* Generators (paper -> implementation):
23+
* g -> asset_gen
24+
* h -> default secp256k1 generator
25+
* *g*, *h* vectors -> gens
26+
*/
27+
28+
/* Step 0 of the proof.
29+
* Uses the value but not the blinding factor. Takes the complete commitment,
30+
* but only to put it into the hash.
31+
* Outputs the points A and S, encoded in 65 bytes (one byte with A's parity
32+
* in the LSB, S's parity in the second-LSB, 32-byte A.x, 32-byte S.x).
33+
* Updates the state to include the hashes y and z.
34+
*/
35+
static int secp256k1_bulletproofs_rangeproof_uncompressed_prove_step0_impl(
36+
const secp256k1_ecmult_gen_context* ecmult_gen_ctx,
37+
secp256k1_bulletproofs_prover_context* prover_ctx,
38+
unsigned char* output,
39+
const size_t n_bits,
40+
const uint64_t value,
41+
const uint64_t min_value,
42+
const secp256k1_ge* commitp,
43+
const secp256k1_ge* asset_genp,
44+
const secp256k1_bulletproofs_generators* gens,
45+
const unsigned char* nonce,
46+
const secp256k1_scalar* enc_data,
47+
const unsigned char* extra_commit,
48+
size_t extra_commit_len
49+
) {
50+
secp256k1_sha256 sha256;
51+
unsigned char commit[32];
52+
secp256k1_scalar alpha, rho;
53+
secp256k1_scalar tmp_l, tmp_r;
54+
secp256k1_gej gej;
55+
secp256k1_ge ge;
56+
size_t i;
57+
int overflow;
58+
59+
memset(prover_ctx->data, 0, sizeof(prover_ctx->data));
60+
memset(output, 0, 65);
61+
62+
/* Sanity checks */
63+
if (n_bits > 64) {
64+
return 0;
65+
}
66+
if (gens->n < n_bits * 2) {
67+
return 0;
68+
}
69+
if (value < min_value) {
70+
return 0;
71+
}
72+
if (n_bits < 64 && (value - min_value) >= (1ull << n_bits)) {
73+
return 0;
74+
}
75+
if (extra_commit_len > 0 && extra_commit == NULL) {
76+
return 0;
77+
}
78+
79+
/* Commit to all input data: min value, pedersen commit, asset generator, extra_commit
80+
* Pass the output in as scratch space since we haven't used it yet. */
81+
secp256k1_bulletproofs_commit_initial_data(commit, output, n_bits, min_value, commitp, asset_genp, extra_commit, extra_commit_len);
82+
83+
/* Compute alpha and rho, adding encrypted data to alpha (effectively adding
84+
* it to mu, which is one of the scalars in the final proof) */
85+
secp256k1_scalar_chacha20(&alpha, &rho, nonce, 0);
86+
secp256k1_scalar_add(&alpha, &alpha, enc_data);
87+
88+
/* Compute and output A */
89+
secp256k1_ecmult_gen(ecmult_gen_ctx, &gej, &alpha);
90+
for (i = 0; i < n_bits; i++) {
91+
secp256k1_ge aterm = gens->gens[2 * i + 1];
92+
size_t al = !!((value - min_value) & (1ull << i));
93+
94+
secp256k1_ge_neg(&aterm, &aterm);
95+
secp256k1_fe_cmov(&aterm.x, &gens->gens[2 * i].x, al);
96+
secp256k1_fe_cmov(&aterm.y, &gens->gens[2 * i].y, al);
97+
secp256k1_gej_add_ge(&gej, &gej, &aterm);
98+
}
99+
secp256k1_ge_set_gej(&ge, &gej);
100+
secp256k1_fe_normalize_var(&ge.x);
101+
secp256k1_fe_normalize_var(&ge.y);
102+
output[0] = secp256k1_fe_is_odd(&ge.y) << 1;
103+
secp256k1_fe_get_b32(&output[1], &ge.x);
104+
105+
/* Compute and output S */
106+
secp256k1_ecmult_gen(ecmult_gen_ctx, &gej, &rho);
107+
for (i = 0; i < n_bits; i++) {
108+
secp256k1_ge sterm;
109+
secp256k1_gej stermj;
110+
111+
secp256k1_scalar_chacha20(&tmp_l, &tmp_r, nonce, i + 2);
112+
113+
secp256k1_ecmult_const(&stermj, &gens->gens[2 * i], &tmp_l, 256);
114+
secp256k1_ge_set_gej(&sterm, &stermj);
115+
secp256k1_gej_add_ge(&gej, &gej, &sterm);
116+
secp256k1_ecmult_const(&stermj, &gens->gens[2 * i + 1], &tmp_r, 256);
117+
secp256k1_ge_set_gej(&sterm, &stermj);
118+
secp256k1_gej_add_ge(&gej, &gej, &sterm);
119+
}
120+
secp256k1_ge_set_gej(&ge, &gej);
121+
secp256k1_fe_normalize_var(&ge.x);
122+
secp256k1_fe_normalize_var(&ge.y);
123+
output[0] |= secp256k1_fe_is_odd(&ge.y);
124+
secp256k1_fe_get_b32(&output[33], &ge.x);
125+
126+
/* get challenges y and z, store them in the prover context */
127+
secp256k1_sha256_initialize(&sha256);
128+
secp256k1_sha256_write(&sha256, commit, 32);
129+
secp256k1_sha256_write(&sha256, output, 65);
130+
secp256k1_sha256_finalize(&sha256, &prover_ctx->data[32]);
131+
secp256k1_scalar_set_b32(&tmp_l, &prover_ctx->data[32], &overflow);
132+
if (overflow || secp256k1_scalar_is_zero(&tmp_l)) {
133+
memset(prover_ctx->data, 0, sizeof(prover_ctx->data));
134+
memset(output, 0, 65);
135+
return 0;
136+
}
137+
138+
secp256k1_sha256_initialize(&sha256);
139+
secp256k1_sha256_write(&sha256, &prover_ctx->data[32], 32);
140+
secp256k1_sha256_finalize(&sha256, &prover_ctx->data[64]);
141+
secp256k1_scalar_set_b32(&tmp_l, &prover_ctx->data[64], &overflow);
142+
if (overflow || secp256k1_scalar_is_zero(&tmp_l)) {
143+
memset(prover_ctx->data, 0, sizeof(prover_ctx->data));
144+
memset(output, 0, 65);
145+
return 0;
146+
}
147+
148+
/* Success */
149+
return 1;
150+
}
151+
152+
#endif

0 commit comments

Comments
 (0)