Skip to content

Commit 8ec6d11

Browse files
committed
Merge #205: Bulletproofs++: Norm argument
d7fb25c Make sure that bppp_log2 isn't called with value 0 (Jonas Nick) e5a01d1 Rename buletproof_pp* to bppp* (sanket1729) c983186 transcript: add tests (Jonas Nick) 73edc75 norm arg: add verification vectors (Jonas Nick) 13ad32e norm arg: add tests for zero length and zero vectors (Jonas Nick) 34c4847 ci: add bulletproofs (Jonas Nick) 2574516 Add testcases for bulletproofs++ norm arugment (sanket1729) 46c7391 Add norm argument verify API (sanket1729) d914545 Add bulletproofs++ norm argument prove API (sanket1729) 8638f0e Add internal BP++ commit API (sanket1729) 412f8f6 Add utility functions required in norm argument (sanket1729) 420353d Add utilities for log2 (sanket1729) 17417d4 Add utilities from uncompressed Bulletproofs PR (sanket1729) 48563c8 bulletproofs: add API functionality to generate a large set of generators (Andrew Poelstra) 048f9f8 bulletproofs: add new empty module (Andrew Poelstra) 6162d57 generator: cleanups in Pedersen/generator code (Andrew Poelstra) 0a60069 Revert "Remove unused scalar_sqr" (Andrew Poelstra) 87373f5 MOVE ONLY: move Pedersen commitment stuff to generator module from rangeproof module (Andrew Poelstra) Pull request description: ACKs for top commit: Liam-Eagen: ACK d7fb25c jonasnick: ACK d7fb25c Tree-SHA512: 0a51e2b404ab594e4ce6c4a65a35f6bbf870d718e0a3cdf7ddd085ed37a0e0c0db55dabca8fe9d8b8beb3f7e60280aa46a2951408c18942dd6ad1c9a71bab5cd
2 parents b1f1675 + d7fb25c commit 8ec6d11

33 files changed

+2429
-520
lines changed

.cirrus.yml

+7-3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ env:
2323
WHITELIST: no
2424
MUSIG: no
2525
ECDSAADAPTOR: no
26+
BPPP: no
2627
### test options
2728
SECP256K1_TEST_ITERS:
2829
BENCH: yes
@@ -72,12 +73,12 @@ task:
7273
<< : *LINUX_CONTAINER
7374
matrix: &ENV_MATRIX
7475
- env: {WIDEMUL: int64, RECOVERY: yes}
75-
- env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
76+
- env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes}
7677
- env: {WIDEMUL: int128}
7778
- env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes}
78-
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
79+
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes}
7980
- env: {WIDEMUL: int128, ASM: x86_64}
80-
- env: { RECOVERY: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
81+
- env: { RECOVERY: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes}
8182
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no}
8283
- env: {CPPFLAGS: -DDETERMINISTIC}
8384
- env: {CFLAGS: -O0, CTIMETEST: no}
@@ -108,6 +109,7 @@ task:
108109
GENERATOR: yes
109110
MUSIG: yes
110111
ECDSAADAPTOR: yes
112+
BPPP: yes
111113
matrix:
112114
- env:
113115
CC: i686-linux-gnu-gcc
@@ -165,6 +167,7 @@ task:
165167
GENERATOR: yes
166168
MUSIG: yes
167169
ECDSAADAPTOR: yes
170+
BPPP: yes
168171
CTIMETEST: no
169172
<< : *MERGE_BASE
170173
test_script:
@@ -259,6 +262,7 @@ task:
259262
GENERATOR: yes
260263
MUSIG: yes
261264
ECDSAADAPTOR: yes
265+
BPPP: yes
262266
CTIMETEST: no
263267
matrix:
264268
- name: "Valgrind (memcheck)"

.gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
bench
2+
bench_bppp
23
bench_ecmult
34
bench_generator
45
bench_rangeproof
56
bench_internal
7+
bench_whitelist
68
tests
9+
example_musig
710
exhaustive_tests
811
precompute_ecmult_gen
912
precompute_ecmult
@@ -66,4 +69,4 @@ src/stamp-h1
6669
libsecp256k1.pc
6770
contrib/gh-pr-create.sh
6871

69-
musig_example
72+
musig_example

Makefile.am

+4
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@ clean-precomp:
226226

227227
EXTRA_DIST = autogen.sh SECURITY.md
228228

229+
if ENABLE_MODULE_BPPP
230+
include src/modules/bppp/Makefile.am.include
231+
endif
232+
229233
if ENABLE_MODULE_ECDH
230234
include src/modules/ecdh/Makefile.am.include
231235
endif

ci/cirrus.sh

+5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ valgrind --version || true
1919
--with-ecmult-gen-precision="$ECMULTGENPRECISION" \
2020
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
2121
--enable-module-ecdsa-s2c="$ECDSA_S2C" \
22+
--enable-module-bppp="$BPPP" \
2223
--enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \
2324
--enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \
2425
--enable-module-schnorrsig="$SCHNORRSIG" \
@@ -51,6 +52,10 @@ then
5152
$EXEC ./bench_ecmult
5253
$EXEC ./bench_internal
5354
$EXEC ./bench
55+
if [ "$BPPP" = "yes" ]
56+
then
57+
$EXEC ./bench_bppp
58+
fi
5459
} >> bench.log 2>&1
5560
fi
5661

configure.ac

+15
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@ AC_ARG_ENABLE(examples,
140140
AS_HELP_STRING([--enable-examples],[compile the examples [default=no]]), [],
141141
[SECP_SET_DEFAULT([enable_examples], [no], [yes])])
142142

143+
AC_ARG_ENABLE(module_bppp,
144+
AS_HELP_STRING([--enable-module-bppp],[enable Bulletproofs++ module (experimental)]),
145+
[],
146+
[SECP_SET_DEFAULT([enable_module_bppp], [no], [yes])])
147+
143148
AC_ARG_ENABLE(module_ecdh,
144149
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=no]]), [],
145150
[SECP_SET_DEFAULT([enable_module_ecdh], [no], [yes])])
@@ -417,6 +422,11 @@ if test x"$enable_module_rangeproof" = x"yes"; then
417422
AC_DEFINE(ENABLE_MODULE_RANGEPROOF, 1, [Define this symbol to enable the Pedersen / zero knowledge range proof module])
418423
fi
419424

425+
if test x"$enable_module_bppp" = x"yes"; then
426+
enable_module_generator=yes
427+
AC_DEFINE(ENABLE_MODULE_BPPP, 1, [Define this symbol to enable the Bulletproofs++ module])
428+
fi
429+
420430
if test x"$enable_module_generator" = x"yes"; then
421431
AC_DEFINE(ENABLE_MODULE_GENERATOR, 1, [Define this symbol to enable the NUMS generator module])
422432
fi
@@ -460,6 +470,9 @@ else
460470
# module (which automatically enables the module dependencies) we want to
461471
# print an error for the dependent module, not the module dependency. Hence,
462472
# we first test dependent modules.
473+
if test x"$enable_module_bppp" = x"yes"; then
474+
AC_MSG_ERROR([Bulletproofs++ module is experimental. Use --enable-experimental to allow.])
475+
fi
463476
if test x"$enable_module_whitelist" = x"yes"; then
464477
AC_MSG_ERROR([Key whitelisting module is experimental. Use --enable-experimental to allow.])
465478
fi
@@ -502,6 +515,7 @@ AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"])
502515
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"])
503516
AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"])
504517
AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"])
518+
AM_CONDITIONAL([ENABLE_MODULE_BPPP], [test x"$enable_module_bppp" = x"yes"])
505519
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
506520
AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"])
507521
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
@@ -541,6 +555,7 @@ echo " module whitelist = $enable_module_whitelist"
541555
echo " module musig = $enable_module_musig"
542556
echo " module ecdsa-s2c = $enable_module_ecdsa_s2c"
543557
echo " module ecdsa-adaptor = $enable_module_ecdsa_adaptor"
558+
echo " module bppp = $enable_module_bppp"
544559
echo
545560
echo " asm = $set_asm"
546561
echo " ecmult window size = $set_ecmult_window"

include/secp256k1_bppp.h

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#ifndef _SECP256K1_BPPP_
2+
# define _SECP256K1_BPPP_
3+
4+
# include "secp256k1.h"
5+
6+
# ifdef __cplusplus
7+
extern "C" {
8+
# endif
9+
10+
#include <stdint.h>
11+
12+
/** Opaque structure representing a large number of NUMS generators */
13+
typedef struct secp256k1_bppp_generators secp256k1_bppp_generators;
14+
15+
/** Allocates and initializes a list of NUMS generators.
16+
* Returns a list of generators, or calls the error callback if the allocation fails.
17+
* Args: ctx: pointer to a context object
18+
* n: number of NUMS generators to produce.
19+
*
20+
* TODO: In a followup range-proof PR, this is would still require 16 + 8 = 24 NUMS
21+
* points. We will later use G = H0(required for compatibility with pedersen_commitment DS)
22+
* in a separate commit to make review easier.
23+
*/
24+
SECP256K1_API secp256k1_bppp_generators *secp256k1_bppp_generators_create(
25+
const secp256k1_context* ctx,
26+
size_t n
27+
) SECP256K1_ARG_NONNULL(1);
28+
29+
/** Allocates a list of generators from a static array
30+
* Returns a list of generators or NULL in case of failure.
31+
* Args: ctx: pointer to a context object
32+
* In: data: data that came from `secp256k1_bppp_generators_serialize`
33+
* data_len: the length of the `data` buffer
34+
*/
35+
SECP256K1_API secp256k1_bppp_generators* secp256k1_bppp_generators_parse(
36+
const secp256k1_context* ctx,
37+
const unsigned char* data,
38+
size_t data_len
39+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
40+
41+
/** Serializes a list of generators to an array
42+
* Returns 1 on success, 0 if the provided array was not large enough
43+
* Args: ctx: pointer to a context object
44+
* gen: pointer to the generator set to be serialized
45+
* Out: data: pointer to buffer into which the generators will be serialized
46+
* In/Out: data_len: the length of the `data` buffer. Should be at least
47+
* k = 33 * num_gens. Will be set to k on successful return
48+
*
49+
* TODO: For ease of review, this setting G = H0 is not included in this commit. We will
50+
* add it in the follow-up rangeproof PR.
51+
*/
52+
SECP256K1_API int secp256k1_bppp_generators_serialize(
53+
const secp256k1_context* ctx,
54+
const secp256k1_bppp_generators* gen,
55+
unsigned char* data,
56+
size_t *data_len
57+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
58+
59+
/** Destroys a list of NUMS generators, freeing allocated memory
60+
* Args: ctx: pointer to a context object
61+
* gen: pointer to the generator set to be destroyed
62+
* (can be NULL, in which case this function is a no-op)
63+
*/
64+
SECP256K1_API void secp256k1_bppp_generators_destroy(
65+
const secp256k1_context* ctx,
66+
secp256k1_bppp_generators* gen
67+
) SECP256K1_ARG_NONNULL(1);
68+
69+
# ifdef __cplusplus
70+
}
71+
# endif
72+
73+
#endif

include/secp256k1_generator.h

+148
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ typedef struct {
2121
unsigned char data[64];
2222
} secp256k1_generator;
2323

24+
/**
25+
* Static constant generator 'h' maintained for historical reasons.
26+
*/
27+
SECP256K1_API extern const secp256k1_generator *secp256k1_generator_h;
28+
2429
/** Parse a 33-byte generator byte sequence into a generator object.
2530
*
2631
* Returns: 1 if input contains a valid generator.
@@ -86,6 +91,149 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate_blin
8691
const unsigned char *blind32
8792
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
8893

94+
/** Opaque data structure that stores a Pedersen commitment
95+
*
96+
* The exact representation of data inside is implementation defined and not
97+
* guaranteed to be portable between different platforms or versions. It is
98+
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
99+
* If you need to convert to a format suitable for storage, transmission, or
100+
* comparison, use secp256k1_pedersen_commitment_serialize and
101+
* secp256k1_pedersen_commitment_parse.
102+
*/
103+
typedef struct {
104+
unsigned char data[64];
105+
} secp256k1_pedersen_commitment;
106+
107+
/** Parse a 33-byte commitment into a commitment object.
108+
*
109+
* Returns: 1 if input contains a valid commitment.
110+
* Args: ctx: a secp256k1 context object.
111+
* Out: commit: pointer to the output commitment object
112+
* In: input: pointer to a 33-byte serialized commitment key
113+
*/
114+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commitment_parse(
115+
const secp256k1_context* ctx,
116+
secp256k1_pedersen_commitment* commit,
117+
const unsigned char *input
118+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
119+
120+
/** Serialize a commitment object into a serialized byte sequence.
121+
*
122+
* Returns: 1 always.
123+
* Args: ctx: a secp256k1 context object.
124+
* Out: output: a pointer to a 33-byte byte array
125+
* In: commit: a pointer to a secp256k1_pedersen_commitment containing an
126+
* initialized commitment
127+
*/
128+
SECP256K1_API int secp256k1_pedersen_commitment_serialize(
129+
const secp256k1_context* ctx,
130+
unsigned char *output,
131+
const secp256k1_pedersen_commitment* commit
132+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
133+
134+
/** Generate a pedersen commitment.
135+
* Returns 1: Commitment successfully created.
136+
* 0: Error. The blinding factor is larger than the group order
137+
* (probability for random 32 byte number < 2^-127) or results in the
138+
* point at infinity. Retry with a different factor.
139+
* In: ctx: pointer to a context object, initialized for signing and Pedersen commitment (cannot be NULL)
140+
* blind: pointer to a 32-byte blinding factor (cannot be NULL)
141+
* value: unsigned 64-bit integer value to commit to.
142+
* gen: additional generator 'h'
143+
* Out: commit: pointer to the commitment (cannot be NULL)
144+
*
145+
* Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA.
146+
*/
147+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
148+
const secp256k1_context* ctx,
149+
secp256k1_pedersen_commitment *commit,
150+
const unsigned char *blind,
151+
uint64_t value,
152+
const secp256k1_generator *gen
153+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
154+
155+
/** Computes the sum of multiple positive and negative blinding factors.
156+
* Returns 1: Sum successfully computed.
157+
* 0: Error. A blinding factor is larger than the group order
158+
* (probability for random 32 byte number < 2^-127). Retry with
159+
* different factors.
160+
* In: ctx: pointer to a context object (cannot be NULL)
161+
* blinds: pointer to pointers to 32-byte character arrays for blinding factors. (cannot be NULL)
162+
* n: number of factors pointed to by blinds.
163+
* npositive: how many of the initial factors should be treated with a positive sign.
164+
* Out: blind_out: pointer to a 32-byte array for the sum (cannot be NULL)
165+
*/
166+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum(
167+
const secp256k1_context* ctx,
168+
unsigned char *blind_out,
169+
const unsigned char * const *blinds,
170+
size_t n,
171+
size_t npositive
172+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
173+
174+
/** Verify a tally of pedersen commitments
175+
* Returns 1: commitments successfully sum to zero.
176+
* 0: Commitments do not sum to zero or other error.
177+
* In: ctx: pointer to a context object (cannot be NULL)
178+
* commits: pointer to array of pointers to the commitments. (cannot be NULL if pcnt is non-zero)
179+
* pcnt: number of commitments pointed to by commits.
180+
* ncommits: pointer to array of pointers to the negative commitments. (cannot be NULL if ncnt is non-zero)
181+
* ncnt: number of commitments pointed to by ncommits.
182+
*
183+
* This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) == 0.
184+
*
185+
* A pedersen commitment is xG + vA where G and A are generators for the secp256k1 group and x is a blinding factor,
186+
* while v is the committed value. For a collection of commitments to sum to zero, for each distinct generator
187+
* A all blinding factors and all values must sum to zero.
188+
*
189+
*/
190+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
191+
const secp256k1_context* ctx,
192+
const secp256k1_pedersen_commitment * const* commits,
193+
size_t pcnt,
194+
const secp256k1_pedersen_commitment * const* ncommits,
195+
size_t ncnt
196+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
197+
198+
/** Sets the final Pedersen blinding factor correctly when the generators themselves
199+
* have blinding factors.
200+
*
201+
* Consider a generator of the form A' = A + rG, where A is the "real" generator
202+
* but A' is the generator provided to verifiers. Then a Pedersen commitment
203+
* P = vA' + r'G really has the form vA + (vr + r')G. To get all these (vr + r')
204+
* to sum to zero for multiple commitments, we take three arrays consisting of
205+
* the `v`s, `r`s, and `r'`s, respectively called `value`s, `generator_blind`s
206+
* and `blinding_factor`s, and sum them.
207+
*
208+
* The function then subtracts the sum of all (vr + r') from the last element
209+
* of the `blinding_factor` array, setting the total sum to zero.
210+
*
211+
* Returns 1: Blinding factor successfully computed.
212+
* 0: Error. A blinding_factor or generator_blind are larger than the group
213+
* order (probability for random 32 byte number < 2^-127). Retry with
214+
* different values.
215+
*
216+
* In: ctx: pointer to a context object
217+
* value: array of asset values, `v` in the above paragraph.
218+
* May not be NULL unless `n_total` is 0.
219+
* generator_blind: array of asset blinding factors, `r` in the above paragraph
220+
* May not be NULL unless `n_total` is 0.
221+
* n_total: Total size of the above arrays
222+
* n_inputs: How many of the initial array elements represent commitments that
223+
* will be negated in the final sum
224+
* In/Out: blinding_factor: array of commitment blinding factors, `r'` in the above paragraph
225+
* May not be NULL unless `n_total` is 0.
226+
* the last value will be modified to get the total sum to zero.
227+
*/
228+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_generator_blind_sum(
229+
const secp256k1_context* ctx,
230+
const uint64_t *value,
231+
const unsigned char* const* generator_blind,
232+
unsigned char* const* blinding_factor,
233+
size_t n_total,
234+
size_t n_inputs
235+
);
236+
89237
# ifdef __cplusplus
90238
}
91239
# endif

0 commit comments

Comments
 (0)