Skip to content

Commit 385f602

Browse files
committed
commitment: allow setting the blinding factor generator for Pedersen commitments
We now use ecmult_const rather than ecmult_gen, which will slow down the generation of Pedersen commitments. However as far as I'm aware, this is never the bottleneck in proof generation.
1 parent c8d9341 commit 385f602

File tree

7 files changed

+70
-74
lines changed

7 files changed

+70
-74
lines changed

include/secp256k1_commitment.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,11 @@ void secp256k1_pedersen_context_initialize(secp256k1_context* ctx);
6060
* 0: Error. The blinding factor is larger than the group order
6161
* (probability for random 32 byte number < 2^-127) or results in the
6262
* point at infinity. Retry with a different factor.
63-
* In: ctx: pointer to a context object, initialized for signing and Pedersen commitment (cannot be NULL)
63+
* In: ctx: pointer to a context object (cannot be NULL)
6464
* blind: pointer to a 32-byte blinding factor (cannot be NULL)
6565
* value: unsigned 64-bit integer value to commit to.
66-
* gen: additional generator 'h'
66+
* value_gen: value generator 'h'
67+
* blind_gen: blinding factor generator 'g'
6768
* Out: commit: pointer to the commitment (cannot be NULL)
6869
*
6970
* Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA.
@@ -73,8 +74,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
7374
secp256k1_pedersen_commitment *commit,
7475
const unsigned char *blind,
7576
uint64_t value,
76-
const secp256k1_generator *gen
77-
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
77+
const secp256k1_generator *value_gen,
78+
const secp256k1_generator *blind_gen
79+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
7880

7981
/** Computes the sum of multiple positive and negative blinding factors.
8082
* Returns 1: Sum successfully computed.

src/bench_rangeproof.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ static void bench_rangeproof_setup(void* arg) {
2929

3030
data->v = 0;
3131
for (i = 0; i < 32; i++) data->blind[i] = i + 1;
32-
CHECK(secp256k1_pedersen_commit(data->ctx, &data->commit, data->blind, data->v, &secp256k1_generator_const_h));
32+
CHECK(secp256k1_pedersen_commit(data->ctx, &data->commit, data->blind, data->v, &secp256k1_generator_const_h, &secp256k1_generator_const_g));
3333
data->len = 5134;
3434
CHECK(secp256k1_rangeproof_sign(data->ctx, data->proof, &data->len, 0, &data->commit, data->blind, (const unsigned char*)&data->commit, 0, data->min_bits, data->v, NULL, 0, NULL, 0, &secp256k1_generator_const_h));
3535
CHECK(secp256k1_rangeproof_verify(data->ctx, &minv, &maxv, &data->commit, data->proof, data->len, NULL, 0, &secp256k1_generator_const_h));

src/modules/commitment/main_impl.h

+8-6
Original file line numberDiff line numberDiff line change
@@ -47,22 +47,24 @@ int secp256k1_pedersen_commitment_serialize(const secp256k1_context* ctx, unsign
4747
}
4848

4949
/* Generates a pedersen commitment: *commit = blind * G + value * G2. The blinding factor is 32 bytes.*/
50-
int secp256k1_pedersen_commit(const secp256k1_context* ctx, secp256k1_pedersen_commitment *commit, const unsigned char *blind, uint64_t value, const secp256k1_generator* gen) {
51-
secp256k1_ge genp;
50+
int secp256k1_pedersen_commit(const secp256k1_context* ctx, secp256k1_pedersen_commitment *commit, const unsigned char *blind, uint64_t value, const secp256k1_generator* value_gen, const secp256k1_generator* blind_gen) {
51+
secp256k1_ge value_genp;
52+
secp256k1_ge blind_genp;
5253
secp256k1_gej rj;
5354
secp256k1_ge r;
5455
secp256k1_scalar sec;
5556
int overflow;
5657
int ret = 0;
5758
VERIFY_CHECK(ctx != NULL);
58-
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
5959
ARG_CHECK(commit != NULL);
6060
ARG_CHECK(blind != NULL);
61-
ARG_CHECK(gen != NULL);
62-
secp256k1_generator_load(&genp, gen);
61+
ARG_CHECK(value_gen != NULL);
62+
ARG_CHECK(blind_gen != NULL);
63+
secp256k1_generator_load(&value_genp, value_gen);
64+
secp256k1_generator_load(&blind_genp, blind_gen);
6365
secp256k1_scalar_set_b32(&sec, blind, &overflow);
6466
if (!overflow) {
65-
secp256k1_pedersen_ecmult(&ctx->ecmult_gen_ctx, &rj, &sec, value, &genp);
67+
secp256k1_pedersen_ecmult(&rj, &sec, value, &value_genp, &blind_genp);
6668
if (!secp256k1_gej_is_infinity(&rj)) {
6769
secp256k1_ge_set_gej(&r, &rj);
6870
secp256k1_pedersen_commitment_save(commit, &r);

src/modules/commitment/pedersen_impl.h

+18-31
Original file line numberDiff line numberDiff line change
@@ -9,43 +9,30 @@
99

1010
#include <string.h>
1111

12-
#include "eckey.h"
1312
#include "ecmult_const.h"
14-
#include "ecmult_gen.h"
1513
#include "group.h"
16-
#include "field.h"
1714
#include "scalar.h"
18-
#include "util.h"
1915

20-
static void secp256k1_pedersen_scalar_set_u64(secp256k1_scalar *sec, uint64_t value) {
21-
unsigned char data[32];
22-
int i;
23-
for (i = 0; i < 24; i++) {
24-
data[i] = 0;
25-
}
26-
for (; i < 32; i++) {
27-
data[i] = value >> 56;
28-
value <<= 8;
29-
}
30-
secp256k1_scalar_set_b32(sec, data, NULL);
31-
memset(data, 0, 32);
32-
}
16+
/* sec * G + value * G2. */
17+
SECP256K1_INLINE static void secp256k1_pedersen_ecmult(secp256k1_gej *rj, const secp256k1_scalar *sec, uint64_t value, const secp256k1_ge* value_gen, const secp256k1_ge* blind_gen) {
18+
secp256k1_scalar vs;
19+
secp256k1_gej bj;
20+
secp256k1_ge bp;
3321

34-
static void secp256k1_pedersen_ecmult_small(secp256k1_gej *r, uint64_t gn, const secp256k1_ge* genp) {
35-
secp256k1_scalar s;
36-
secp256k1_pedersen_scalar_set_u64(&s, gn);
37-
secp256k1_ecmult_const(r, genp, &s, 64);
38-
secp256k1_scalar_clear(&s);
39-
}
22+
secp256k1_scalar_set_u64(&vs, value);
23+
secp256k1_ecmult_const(rj, value_gen, &vs, 64);
24+
secp256k1_ecmult_const(&bj, blind_gen, sec, 256);
4025

41-
/* sec * G + value * G2. */
42-
SECP256K1_INLINE static void secp256k1_pedersen_ecmult(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_gej *rj, const secp256k1_scalar *sec, uint64_t value, const secp256k1_ge* genp) {
43-
secp256k1_gej vj;
44-
secp256k1_ecmult_gen(ecmult_gen_ctx, rj, sec);
45-
secp256k1_pedersen_ecmult_small(&vj, value, genp);
46-
/* FIXME: constant time. */
47-
secp256k1_gej_add_var(rj, rj, &vj, NULL);
48-
secp256k1_gej_clear(&vj);
26+
/* zero blinding factor indicates that we are not trying to be zero-knowledge,
27+
* so not being constant-time in this case is OK. */
28+
if (!secp256k1_gej_is_infinity(&bj)) {
29+
secp256k1_ge_set_gej(&bp, &bj);
30+
secp256k1_gej_add_ge(rj, rj, &bp);
31+
}
32+
33+
secp256k1_gej_clear(&bj);
34+
secp256k1_ge_clear(&bp);
35+
secp256k1_scalar_clear(&vs);
4936
}
5037

5138
#endif

src/modules/commitment/tests_impl.h

+26-24
Original file line numberDiff line numberDiff line change
@@ -41,54 +41,56 @@ static void test_commitment_api(void) {
4141
secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
4242

4343
secp256k1_rand256(blind);
44-
CHECK(secp256k1_pedersen_commit(none, &commit, blind, val, &secp256k1_generator_const_h) == 0);
44+
CHECK(secp256k1_pedersen_commit(none, &commit, blind, val, &secp256k1_generator_const_h, &secp256k1_generator_const_g) == 0);
4545
CHECK(ecount == 1);
46-
CHECK(secp256k1_pedersen_commit(vrfy, &commit, blind, val, &secp256k1_generator_const_h) == 0);
46+
CHECK(secp256k1_pedersen_commit(vrfy, &commit, blind, val, &secp256k1_generator_const_h, &secp256k1_generator_const_g) == 0);
4747
CHECK(ecount == 2);
48-
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, &secp256k1_generator_const_h) != 0);
48+
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, &secp256k1_generator_const_h, &secp256k1_generator_const_g) != 0);
4949
CHECK(ecount == 2);
5050

51-
CHECK(secp256k1_pedersen_commit(sign, NULL, blind, val, &secp256k1_generator_const_h) == 0);
51+
CHECK(secp256k1_pedersen_commit(sign, NULL, blind, val, &secp256k1_generator_const_h, &secp256k1_generator_const_g) == 0);
5252
CHECK(ecount == 3);
53-
CHECK(secp256k1_pedersen_commit(sign, &commit, NULL, val, &secp256k1_generator_const_h) == 0);
53+
CHECK(secp256k1_pedersen_commit(sign, &commit, NULL, val, &secp256k1_generator_const_h, &secp256k1_generator_const_g) == 0);
5454
CHECK(ecount == 4);
55-
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, NULL) == 0);
55+
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, NULL, &secp256k1_generator_const_g) == 0);
5656
CHECK(ecount == 5);
57+
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, &secp256k1_generator_const_h, NULL) == 0);
58+
CHECK(ecount == 6);
5759

5860
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 1, 1) != 0);
59-
CHECK(ecount == 5);
60-
CHECK(secp256k1_pedersen_blind_sum(none, NULL, &blind_ptr, 1, 1) == 0);
6161
CHECK(ecount == 6);
62-
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, NULL, 1, 1) == 0);
62+
CHECK(secp256k1_pedersen_blind_sum(none, NULL, &blind_ptr, 1, 1) == 0);
6363
CHECK(ecount == 7);
64-
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 1) == 0);
64+
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, NULL, 1, 1) == 0);
6565
CHECK(ecount == 8);
66+
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 1) == 0);
67+
CHECK(ecount == 9);
6668
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 0) != 0);
67-
CHECK(ecount == 8);
69+
CHECK(ecount == 9);
6870

69-
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, &secp256k1_generator_const_h) != 0);
71+
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, &secp256k1_generator_const_h, &secp256k1_generator_const_g) != 0);
7072
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, &commit_ptr, 1) != 0);
7173
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, &commit_ptr, 1) == 0);
7274
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 0) == 0);
7375
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, NULL, 0) != 0);
74-
CHECK(ecount == 8);
75-
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 1, &commit_ptr, 1) == 0);
7676
CHECK(ecount == 9);
77-
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 1) == 0);
77+
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 1, &commit_ptr, 1) == 0);
7878
CHECK(ecount == 10);
79+
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 1) == 0);
80+
CHECK(ecount == 11);
7981

8082
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 0) != 0);
81-
CHECK(ecount == 10);
82-
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 1) == 0);
8383
CHECK(ecount == 11);
84-
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 0, 0) == 0);
84+
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 1) == 0);
8585
CHECK(ecount == 12);
86-
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, NULL, &blind_ptr, &blind_out_ptr, 1, 0) == 0);
86+
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 0, 0) == 0);
8787
CHECK(ecount == 13);
88-
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, NULL, &blind_out_ptr, 1, 0) == 0);
88+
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, NULL, &blind_ptr, &blind_out_ptr, 1, 0) == 0);
8989
CHECK(ecount == 14);
90-
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, NULL, 1, 0) == 0);
90+
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, NULL, &blind_out_ptr, 1, 0) == 0);
9191
CHECK(ecount == 15);
92+
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, NULL, 1, 0) == 0);
93+
CHECK(ecount == 16);
9294

9395
secp256k1_context_destroy(none);
9496
secp256k1_context_destroy(sign);
@@ -132,7 +134,7 @@ static void test_pedersen(void) {
132134
}
133135
CHECK(secp256k1_pedersen_blind_sum(ctx, &blinds[(total - 1) * 32], bptr, total - 1, inputs));
134136
for (i = 0; i < total; i++) {
135-
CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], &secp256k1_generator_const_h));
137+
CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], &secp256k1_generator_const_h, &secp256k1_generator_const_g));
136138
}
137139
CHECK(secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs));
138140
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[inputs], outputs, cptr, inputs));
@@ -147,7 +149,7 @@ static void test_pedersen(void) {
147149
values[1] = 0;
148150
values[2] = 1;
149151
for (i = 0; i < 3; i++) {
150-
CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], &secp256k1_generator_const_h));
152+
CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], &secp256k1_generator_const_h, &secp256k1_generator_const_g));
151153
}
152154
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1));
153155
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1));
@@ -202,7 +204,7 @@ void test_multiple_generators(void) {
202204
/* Correct for blinding factors and do the commitments */
203205
CHECK(secp256k1_pedersen_blind_generator_blind_sum(ctx, value, (const unsigned char * const *) generator_blind, pedersen_blind, n_generators, n_inputs));
204206
for (i = 0; i < n_generators; i++) {
205-
CHECK(secp256k1_pedersen_commit(ctx, &commit[i], pedersen_blind[i], value[i], &generator[i]));
207+
CHECK(secp256k1_pedersen_commit(ctx, &commit[i], pedersen_blind[i], value[i], &generator[i], &secp256k1_generator_const_h));
206208
}
207209

208210
/* Verify */

src/modules/rangeproof/rangeproof_impl.h

+6-3
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul
296296
npub = 0;
297297
for (i = 0; i < rings; i++) {
298298
/*OPT: Use the precomputed gen2 basis?*/
299-
secp256k1_pedersen_ecmult(ecmult_gen_ctx, &pubs[npub], &sec[i], ((uint64_t)secidx[i] * scale) << (i*2), genp);
299+
secp256k1_pedersen_ecmult(&pubs[npub], &sec[i], ((uint64_t)secidx[i] * scale) << (i*2), genp, &secp256k1_ge_const_g);
300300
if (secp256k1_gej_is_infinity(&pubs[npub])) {
301301
return 0;
302302
}
@@ -604,7 +604,10 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm
604604
npub = 0;
605605
secp256k1_gej_set_infinity(&accj);
606606
if (*min_value) {
607-
secp256k1_pedersen_ecmult_small(&accj, *min_value, genp);
607+
secp256k1_scalar mvs;
608+
secp256k1_scalar_set_u64(&mvs, *min_value);
609+
secp256k1_ecmult_const(&accj, genp, &mvs, 64);
610+
secp256k1_scalar_clear(&mvs);
608611
}
609612
for(i = 0; i < rings - 1; i++) {
610613
secp256k1_fe fe;
@@ -660,7 +663,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm
660663
/* Unwind apparently successful, see if the commitment can be reconstructed. */
661664
/* FIXME: should check vv is in the mantissa's range. */
662665
vv = (vv * scale) + *min_value;
663-
secp256k1_pedersen_ecmult(ecmult_gen_ctx, &accj, &blind, vv, genp);
666+
secp256k1_pedersen_ecmult(&accj, &blind, vv, genp, &secp256k1_ge_const_g);
664667
if (secp256k1_gej_is_infinity(&accj)) {
665668
return 0;
666669
}

src/modules/rangeproof/tests_impl.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ static void test_rangeproof_api(const secp256k1_context *none, const secp256k1_c
3131
size_t ext_commit_len = sizeof(ext_commit);
3232

3333
secp256k1_rand256(blind);
34-
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, val, &secp256k1_generator_const_h));
34+
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, val, &secp256k1_generator_const_h, &secp256k1_generator_const_g));
3535

3636
CHECK(secp256k1_rangeproof_sign(none, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, &secp256k1_generator_const_h) == 0);
3737
CHECK(*ecount == 1);
@@ -293,7 +293,7 @@ static void test_rangeproof(void) {
293293
secp256k1_rand256(blind);
294294
for (i = 0; i < 11; i++) {
295295
v = testvs[i];
296-
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, &secp256k1_generator_const_h));
296+
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, &secp256k1_generator_const_h, &secp256k1_generator_const_g));
297297
for (vmin = 0; vmin < (i<9 && i > 0 ? 2 : 1); vmin++) {
298298
const unsigned char *input_message = NULL;
299299
size_t input_message_len = 0;
@@ -348,7 +348,7 @@ static void test_rangeproof(void) {
348348
}
349349
secp256k1_rand256(blind);
350350
v = INT64_MAX - 1;
351-
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, &secp256k1_generator_const_h));
351+
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, &secp256k1_generator_const_h, &secp256k1_generator_const_g));
352352
for (i = 0; i < 19; i++) {
353353
len = 5134;
354354
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, i, 0, v, NULL, 0, NULL, 0, &secp256k1_generator_const_h));
@@ -363,7 +363,7 @@ static void test_rangeproof(void) {
363363
{
364364
/*Malleability test.*/
365365
v = secp256k1_rands64(0, 255);
366-
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, &secp256k1_generator_const_h));
366+
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, &secp256k1_generator_const_h, &secp256k1_generator_const_g));
367367
len = 5134;
368368
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, 0, 3, v, NULL, 0, NULL, 0, &secp256k1_generator_const_h));
369369
CHECK(len <= 5134);
@@ -389,7 +389,7 @@ static void test_rangeproof(void) {
389389
vmin = secp256k1_rands64(0, v);
390390
}
391391
secp256k1_rand256(blind);
392-
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, &secp256k1_generator_const_h));
392+
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, &secp256k1_generator_const_h, &secp256k1_generator_const_g));
393393
len = 5134;
394394
exp = (int)secp256k1_rands64(0,18)-(int)secp256k1_rands64(0,18);
395395
if (exp < 0) {

0 commit comments

Comments
 (0)