Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bp++: Rangeproof PR #207

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 99 additions & 9 deletions include/secp256k1_bppp.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ extern "C" {

#include <stdint.h>

#include "secp256k1_generator.h"

/** Opaque structure representing a large number of NUMS generators */
typedef struct secp256k1_bppp_generators secp256k1_bppp_generators;

/** Opaque structure representing a prover context used in bulletproofs++ prover */
typedef struct secp256k1_bppp_rangeproof_prover_context secp256k1_bppp_rangeproof_prover_context;

/** 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_bppp_generators *secp256k1_bppp_generators_create(
const secp256k1_context *ctx,
Expand All @@ -43,11 +44,9 @@ SECP256K1_API secp256k1_bppp_generators *secp256k1_bppp_generators_parse(
* 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.
* In/Out: data_len: the length of the `data` buffer. Should be initially set to at
* least 33 times the number of generators plus one(33 * (num_gens - 1)).
* Upon success, data_len will be set to the (33 * (num_gens - 1)).
*/
SECP256K1_API int secp256k1_bppp_generators_serialize(
const secp256k1_context *ctx,
Expand All @@ -66,6 +65,97 @@ SECP256K1_API void secp256k1_bppp_generators_destroy(
secp256k1_bppp_generators *gen
) SECP256K1_ARG_NONNULL(1);

/** Returns the serialized size of an bulletproofs++ proof of a given number
* of bits and the base. Both base and n_bits must be a power of two. The number
* of digits required to represent number of bits in the given base must also be
* a power of two. Specifically, all of n_bits, base and num_digits = (n_bits / log2(base))
* must all be a power of two.
* Args: ctx: pointer to a context object
* Out: len: 0 if the parameters and num_digits (n_bits/log2(base)) are not a power of two
* length of the serialized proof otherwise
* In: n_bits: number of bits to prove (max 64, should usually be 64)
* base: base representation to be used in proof construction (max 256, recommended 16)
*/
SECP256K1_API size_t secp256k1_bppp_rangeproof_proof_length(
const secp256k1_context* ctx,
size_t n_bits,
size_t base
) SECP256K1_ARG_NONNULL(1);

/** Produces a Bulletproofs++ rangeproof. Returns 1 on success, 0 on failure.
* Proof creation can only fail if the arguments are invalid. The documentation
* below specifies the constraints on inputs and arguments under which this API
* can fail.
* Args: ctx: pointer to a context object
* scratch: pointer to a scratch space
* gens: pointer to the generator set to use, which must have exactly
* `n = max(num_digits, base) + 7` generators, where num_digits is the number.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"num_digits is the number." -> "num_digits is floor(log_base(value)) + 1?

* asset_gen: pointer to the asset generator for the Pedersen/CT commitment
* Out: proof: pointer to a byte array to output the proof into
* In/Out: plen: pointer to the size of the above array; will be set to the actual size of
* the serialized proof. To learn this value in advance, to allocate a sufficient
* buffer, call `secp256k1_bppp_rangeproof_proof_length`
* In: n_bits: size of range being proven, in bits. Must be a power of two,
* and at most 64.
* base: base representation to be used in proof construction. Must be a power of two,
* value: value committed in the Pedersen commitment. Must be less
* than 2^n_bits.
* min_value: minimum value of the range being proven. Must be less than value
* commit: the Pedersen commitment being proven
* blind: blinding factor for the Pedersen commitment. Must be a 32 byte
* valid scalar within secp curve order.
* nonce: seed for the RNG used to generate random data during proving
* extra_commit: arbitrary extra data that the proof commits to (may be NULL if extra_commit_len is 0)
* extra_commit_len: length of the arbitrary extra data.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_bppp_rangeproof_prove(
const secp256k1_context* ctx,
secp256k1_scratch_space *scratch,
const secp256k1_bppp_generators* gens,
const secp256k1_generator* asset_gen,
unsigned char* proof,
size_t* plen,
const size_t n_bits,
const size_t base,
const uint64_t value,
const uint64_t min_value,
const secp256k1_pedersen_commitment* commit,
const unsigned char* blind,
const unsigned char* nonce,
const unsigned char* extra_commit,
size_t extra_commit_len
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(11) SECP256K1_ARG_NONNULL(12) SECP256K1_ARG_NONNULL(13);

/** Verifies an Bulletproofs++ rangeproof. Returns 1 on success, 0 on failure.
* Args: ctx: pointer to a context object
* scratch: pointer to a scratch space
* gens: pointer to the generator set to use, which must have at least 2*n_bits generators

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bench_bppp uses 24 generators for both proving/verification; it looks like this should also be updated to reflect floor(log_base(value)) + 1.

* asset_gen: pointer to the asset generator for the CT commitment
* In: proof: pointer to a byte array containing the serialized proof
* plen: length of the serialized proof
* n_bits: size of range being proven, in bits. Must be a power of two,
* and at most 64.
* base: base representation to be used in proof construction. Must be a power of two,
* min_value: minimum value of the range being proven
* commit: the Pedersen commitment being proven
* extra_commit: arbitrary extra data that the proof commits to (may be NULL if extra_commit_len is 0)
* extra_commit_len: length of the arbitrary extra data
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_bppp_rangeproof_verify(
const secp256k1_context* ctx,
secp256k1_scratch_space *scratch,
const secp256k1_bppp_generators* gens,
const secp256k1_generator* asset_gen,
const unsigned char* proof,
const size_t plen,
const uint64_t n_bits,
const uint64_t base,
const uint64_t min_value,
const secp256k1_pedersen_commitment* commit,
const unsigned char* extra_commit,
size_t extra_commit_len
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(10);

# ifdef __cplusplus
}
# endif
Expand Down
65 changes: 59 additions & 6 deletions src/bench_bppp.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,85 @@
#include <stdint.h>

#include "../include/secp256k1_bppp.h"
#include "../include/secp256k1.h"
#include "util.h"
#include "bench.h"

#define MAX_PROOF_SIZE 500

typedef struct {
secp256k1_context* ctx;
secp256k1_bppp_generators* gens;
secp256k1_scratch_space *scratch;
secp256k1_pedersen_commitment commit;
unsigned char *proofs;
unsigned char blind[32];
unsigned char nonce[32];
size_t proof_len;
size_t n_bits;
size_t base;
uint64_t min_value;
uint64_t value;
} bench_bppp_data;

static void bench_bppp_setup(void* arg) {
(void) arg;
bench_bppp_data *data = (bench_bppp_data*)arg;

data->min_value = 0;
data->value = 100;
data->proof_len = MAX_PROOF_SIZE;
memset(data->blind, 0x77, 32);
memset(data->nonce, 0x0, 32);
CHECK(secp256k1_pedersen_commit(data->ctx, &data->commit, data->blind, data->value, secp256k1_generator_h));

CHECK(secp256k1_bppp_rangeproof_prove(data->ctx, data->scratch, data->gens, secp256k1_generator_h, data->proofs, &data->proof_len, data->n_bits, data->base, data->value, 0, &data->commit, data->blind, data->nonce, NULL, 0));
CHECK(secp256k1_bppp_rangeproof_verify(data->ctx, data->scratch, data->gens, secp256k1_generator_h, data->proofs, data->proof_len, data->n_bits, data->base, data->min_value, &data->commit, NULL, 0));
}

static void bench_bppp_prove(void* arg, int iters) {
bench_bppp_data *data = (bench_bppp_data*)arg;
int i;

for (i = 0; i < iters; i++) {
data->nonce[1] = i;
data->nonce[2] = i >> 8;
data->nonce[3] = i >> 16;
data->proof_len = MAX_PROOF_SIZE;
CHECK(secp256k1_bppp_rangeproof_prove(data->ctx, data->scratch, data->gens, secp256k1_generator_h, &data->proofs[i*MAX_PROOF_SIZE], &data->proof_len, data->n_bits, data->base, data->value, 0, &data->commit, data->blind, data->nonce, NULL, 0));
}
}

static void bench_bppp(void* arg, int iters) {
static void bench_bppp_verify(void* arg, int iters) {
bench_bppp_data *data = (bench_bppp_data*)arg;
int i;

(void) data;
(void) iters;
for (i = 0; i < iters; i++) {
CHECK(secp256k1_bppp_rangeproof_verify(data->ctx, data->scratch, data->gens, secp256k1_generator_h, &data->proofs[i*MAX_PROOF_SIZE], data->proof_len, data->n_bits, data->base, data->min_value, &data->commit, NULL, 0));
}
}

int main(void) {
bench_bppp_data data;
int iters = get_iters(32);
int iters = get_iters(64);
char test_name[64];

data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
data.gens = secp256k1_bppp_generators_create(data.ctx, 24);
data.scratch = secp256k1_scratch_space_create(data.ctx, 80 * 1024);
data.proofs = (unsigned char *)malloc(iters * MAX_PROOF_SIZE);

run_benchmark("bppp_verify_bit", bench_bppp, bench_bppp_setup, NULL, &data, 10, iters);
data.n_bits = 1ul << 6;
data.base = 16;
sprintf(test_name, "bppp_prove_64bits_16base");
run_benchmark(test_name, bench_bppp_prove, bench_bppp_setup, NULL, &data, 4, iters);

sprintf(test_name, "bppp_verify_64bits_16base");
run_benchmark(test_name, bench_bppp_verify, bench_bppp_setup, NULL, &data, 20, iters);

secp256k1_scratch_space_destroy(data.ctx, data.scratch);
free(data.proofs);
secp256k1_bppp_generators_destroy(data.ctx, data.gens);
secp256k1_context_destroy(data.ctx);

return 0;
}
1 change: 1 addition & 0 deletions src/modules/bppp/Makefile.am.include
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ noinst_HEADERS += src/modules/bppp/bppp_util.h
noinst_HEADERS += src/modules/bppp/main_impl.h
noinst_HEADERS += src/modules/bppp/bppp_transcript_impl.h
noinst_HEADERS += src/modules/bppp/bppp_norm_product_impl.h
noinst_HEADERS += src/modules/bppp/bppp_rangeproof_impl.h
noinst_HEADERS += src/modules/bppp/tests_impl.h

if USE_BENCHMARK
Expand Down
Loading