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

rangeproof: add a "net blinding factor" API for Elements #204

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 43 additions & 0 deletions include/secp256k1_rangeproof.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,49 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
size_t ncnt
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);

/** Compute the "net blinding factor" for an asset/amount pair of Pedersen commitments
*
* Returns 0 if either input is out of range, otherwise 1
* Args: ctx: a secp256k1 context object.
* Out: output: 32-byte array into which the result will be written
* In: val: the value of the amount commitment
* vbf: the amount commitment's blinding factor
* abf: the asset commitment's blinding factor
*
* This computse val*abf + vbf
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_netbf_compute(
const secp256k1_context* ctx,
unsigned char* output,
uint64_t val,
const unsigned char* vbf,
const unsigned char* abf
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);

/** Accumulate a net blinding factor
*
* Returns 0 if the input is out of range, otherwise 1
* Args: ctx: a secp256k1 context object.
* In/Out: acc: initially set to the current state of the accumulator; updated in place
* In: nbf: the net blinding factor to add to the accumulator
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_netbf_acc(
const secp256k1_context* ctx,
unsigned char* acc,
const unsigned char* nbf
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);

/** Negate a(n accumulated) net blinding factor
*
* Returns 0 if the input is out of range, otherwise 1
* Args: ctx: a secp256k1 context object.
* In/Out: acc: initially set to the bf to negate; changed to the negated version
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_netbf_neg(
const secp256k1_context* ctx,
unsigned char* output
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);

/** Sets the final Pedersen blinding factor correctly when the generators themselves
* have blinding factors.
*
Expand Down
68 changes: 68 additions & 0 deletions src/modules/rangeproof/main_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,74 @@ int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const secp256k
return secp256k1_gej_is_infinity(&accj);
}

int secp256k1_netbf_compute(const secp256k1_context* ctx, unsigned char* output, uint64_t val, const unsigned char* vbf, const unsigned char* abf) {
int overflow = 0;
secp256k1_scalar vbf_s;
secp256k1_scalar abf_s;

VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output != NULL);
ARG_CHECK(vbf != NULL);
ARG_CHECK(abf != NULL);
(void) ctx;

secp256k1_scalar_set_b32(&abf_s, abf, &overflow);
if (overflow == 1) {
return 0;
}
secp256k1_scalar_set_u64(&vbf_s, val);
secp256k1_scalar_mul(&abf_s, &abf_s, &vbf_s);

secp256k1_scalar_set_b32(&vbf_s, vbf, &overflow);
if (overflow == 1) {
return 0;
}
secp256k1_scalar_add(&vbf_s, &vbf_s, &abf_s);

secp256k1_scalar_get_b32(output, &vbf_s);
return 1;
}

int secp256k1_netbf_acc(const secp256k1_context* ctx, unsigned char* acc, const unsigned char* nbf) {
int overflow = 0;
secp256k1_scalar ret_s;
secp256k1_scalar nbf_s;

VERIFY_CHECK(ctx != NULL);
ARG_CHECK(acc != NULL);
ARG_CHECK(nbf != NULL);

secp256k1_scalar_set_b32(&ret_s, acc, &overflow);
if (overflow == 1) {
return 0;
}
secp256k1_scalar_set_b32(&nbf_s, nbf, &overflow);
if (overflow == 1) {
return 0;
}

secp256k1_scalar_add(&ret_s, &ret_s, &nbf_s);
secp256k1_scalar_get_b32(acc, &ret_s);
return 1;
}

int secp256k1_netbf_neg(const secp256k1_context* ctx, unsigned char* acc) {
int overflow = 0;
secp256k1_scalar ret_s;

VERIFY_CHECK(ctx != NULL);
ARG_CHECK(acc != NULL);

secp256k1_scalar_set_b32(&ret_s, acc, &overflow);
if (overflow == 1) {
return 0;
}

secp256k1_scalar_negate(&ret_s, &ret_s);
secp256k1_scalar_get_b32(acc, &ret_s);
return 1;
}

int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, const uint64_t *value, const unsigned char* const* generator_blind, unsigned char* const* blinding_factor, size_t n_total, size_t n_inputs) {
secp256k1_scalar sum;
secp256k1_scalar tmp;
Expand Down
77 changes: 77 additions & 0 deletions src/modules/rangeproof/tests_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,81 @@ static void test_rangeproof_api(const secp256k1_context *none, const secp256k1_c
CHECK(secp256k1_rangeproof_max_size(none, UINT64_MAX, 0) == 5134);
}

#define N_COMMITS 8
static void test_nbf(const secp256k1_context *none, const int32_t *ecount) {
unsigned char abf[N_COMMITS][32];
unsigned char vbf[N_COMMITS][32];
unsigned char nbf[N_COMMITS][32];
uint64_t val[N_COMMITS];

unsigned char acc_p[32];
unsigned char acc_n[32];
secp256k1_scalar target;

size_t i;
VERIFY_CHECK(N_COMMITS >= 2); /* better to trigger this than to trigger UB */

/* Check that zeros are ok; check NULL checks */
memset(abf[0], 0x00, sizeof(abf[0]));
memset(vbf[0], 0x00, sizeof(abf[0]));
val[0] = 0;

CHECK(secp256k1_netbf_compute(none, nbf[0], val[0], vbf[0], abf[0]));
CHECK(secp256k1_memcmp_var(nbf[0], vbf[0], sizeof(nbf[0])) == 0);
CHECK(*ecount == 0);
CHECK(secp256k1_netbf_compute(none, NULL, val[0], vbf[0], abf[0]) == 0);
CHECK(*ecount == 1);
CHECK(secp256k1_netbf_compute(none, nbf[0], val[0], NULL, abf[0]) == 0);
CHECK(*ecount == 2);
CHECK(secp256k1_netbf_compute(none, nbf[0], val[0], vbf[0], NULL) == 0);
CHECK(*ecount == 3);

memset(vbf[1], 0xff, sizeof(vbf[1])); /* out of range */
memset(abf[1], 0xff, sizeof(abf[1])); /* out of range */
CHECK(secp256k1_netbf_compute(none, nbf[0], val[0], vbf[0], abf[1]) == 0);
CHECK(secp256k1_netbf_compute(none, nbf[0], val[0], vbf[1], abf[0]) == 0);
CHECK(secp256k1_netbf_compute(none, nbf[0], val[0], vbf[1], abf[1]) == 0);
CHECK(*ecount == 3); /* not API errors */

memset(acc_p, 0x00, sizeof(acc_p)); /* FIXME should we expose a nbf_clear method for this? */
memset(acc_n, 0x00, sizeof(acc_n));
secp256k1_scalar_clear(&target);
for (i = 0; i < N_COMMITS; i++) {
val[i] = secp256k1_testrand64();
/* nb these theoretically could go out of range but not in this universe's lifetime */
secp256k1_testrand256(abf[i]);
secp256k1_testrand256(vbf[i]);
CHECK(secp256k1_netbf_compute(none, nbf[i], val[i], vbf[i], abf[i]));

if (secp256k1_testrand32() & 1) {
int overflow;
secp256k1_scalar tmps;
/* positive */
CHECK(secp256k1_netbf_acc(none, acc_p, nbf[i]));

secp256k1_scalar_set_b32(&tmps, nbf[i], &overflow);
CHECK(overflow == 0); /* actually unreachable, not just cryptographically */
secp256k1_scalar_add(&target, &target, &tmps);
} else {
int overflow;
secp256k1_scalar tmps;
/* negative */
CHECK(secp256k1_netbf_acc(none, acc_n, nbf[i]));

secp256k1_scalar_set_b32(&tmps, nbf[i], &overflow);
CHECK(overflow == 0); /* actually unreachable, not just cryptographically */
secp256k1_scalar_negate(&tmps, &tmps);
secp256k1_scalar_add(&target, &target, &tmps);
}
}
CHECK(secp256k1_netbf_neg(none, acc_n));
CHECK(secp256k1_netbf_acc(none, acc_p, acc_n));

secp256k1_scalar_get_b32(acc_n, &target);
CHECK(secp256k1_memcmp_var(acc_p, acc_n, sizeof(acc_p)) == 0);
}
#undef N_COMMITS

static void test_api(void) {
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
Expand All @@ -257,6 +332,8 @@ static void test_api(void) {
test_pedersen_api(none, sign, vrfy, sttc, &ecount);
ecount = 0;
test_rangeproof_api(none, sign, vrfy, both, sttc, &ecount);
ecount = 0;
test_nbf(none, &ecount);
}

secp256k1_context_destroy(none);
Expand Down