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: initial set of cleanups, minor stack space improvements #150

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ bench_schnorrsig
bench_sign
bench_verify
bench_recover
bench_whitelist
bench_internal
tests
exhaustive_tests
Expand Down
6 changes: 4 additions & 2 deletions src/modules/rangeproof/borromean.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
#include "ecmult.h"
#include "ecmult_gen.h"

#include "modules/rangeproof/borromean_util.h"

int secp256k1_borromean_verify(secp256k1_scalar *evalues, const unsigned char *e0, const secp256k1_scalar *s,
const secp256k1_gej *pubs, const size_t *rsizes, size_t nrings, const unsigned char *m, size_t mlen);

int secp256k1_borromean_sign(const secp256k1_ecmult_gen_context *ecmult_gen_ctx,
unsigned char *e0, secp256k1_scalar *s, const secp256k1_gej *pubs, const secp256k1_scalar *k, const secp256k1_scalar *sec,
const size_t *rsizes, const size_t *secidx, size_t nrings, const unsigned char *m, size_t mlen);
unsigned char *e0, secp256k1_scalar *s, const secp256k1_gej *pubs, const secp256k1_scalar *sec,
const size_t *rsizes, const secp256k1_borromean_sz_closure* secidx_closure, size_t nrings, const unsigned char *m, size_t mlen);

#endif
22 changes: 14 additions & 8 deletions src/modules/rangeproof/borromean_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ int secp256k1_borromean_verify(secp256k1_scalar *evalues, const unsigned char *e
}

int secp256k1_borromean_sign(const secp256k1_ecmult_gen_context *ecmult_gen_ctx,
unsigned char *e0, secp256k1_scalar *s, const secp256k1_gej *pubs, const secp256k1_scalar *k, const secp256k1_scalar *sec,
const size_t *rsizes, const size_t *secidx, size_t nrings, const unsigned char *m, size_t mlen) {
unsigned char *e0, secp256k1_scalar *s, const secp256k1_gej *pubs, const secp256k1_scalar *sec,
const size_t *rsizes, const secp256k1_borromean_sz_closure* secidx_closure, size_t nrings, const unsigned char *m, size_t mlen) {
secp256k1_gej rgej;
secp256k1_ge rge;
secp256k1_scalar ens;
Expand All @@ -125,23 +125,24 @@ int secp256k1_borromean_sign(const secp256k1_ecmult_gen_context *ecmult_gen_ctx,
VERIFY_CHECK(e0 != NULL);
VERIFY_CHECK(s != NULL);
VERIFY_CHECK(pubs != NULL);
VERIFY_CHECK(k != NULL);
VERIFY_CHECK(sec != NULL);
VERIFY_CHECK(rsizes != NULL);
VERIFY_CHECK(secidx != NULL);
VERIFY_CHECK(secidx_closure != NULL);
VERIFY_CHECK(nrings > 0);
VERIFY_CHECK(m != NULL);
secp256k1_sha256_initialize(&sha256_e0);
count = 0;
for (i = 0; i < nrings; i++) {
size_t secidx_i = secidx_closure->call(secidx_closure, i);
VERIFY_CHECK(INT_MAX - count > rsizes[i]);
secp256k1_ecmult_gen(ecmult_gen_ctx, &rgej, &k[i]);
/* We have been provided an s value that we will just overwrite, so use it as a nonce */
secp256k1_ecmult_gen(ecmult_gen_ctx, &rgej, &s[count + secidx_i]);
secp256k1_ge_set_gej(&rge, &rgej);
if (secp256k1_gej_is_infinity(&rgej)) {
return 0;
}
secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1);
for (j = secidx[i] + 1; j < rsizes[i]; j++) {
for (j = secidx_i + 1; j < rsizes[i]; j++) {
secp256k1_borromean_hash(tmp, m, mlen, tmp, 33, i, j);
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
if (overflow || secp256k1_scalar_is_zero(&ens)) {
Expand All @@ -165,13 +166,18 @@ int secp256k1_borromean_sign(const secp256k1_ecmult_gen_context *ecmult_gen_ctx,
secp256k1_sha256_finalize(&sha256_e0, e0);
count = 0;
for (i = 0; i < nrings; i++) {
size_t secidx_i = secidx_closure->call(secidx_closure, i);
/* We have been provided an s value that we will just overwrite, so use it as a nonce */
secp256k1_scalar k = s[count + secidx_i];
secp256k1_scalar_clear(&s[count + secidx_i]);

VERIFY_CHECK(INT_MAX - count > rsizes[i]);
secp256k1_borromean_hash(tmp, m, mlen, e0, 32, i, 0);
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
if (overflow || secp256k1_scalar_is_zero(&ens)) {
return 0;
}
for (j = 0; j < secidx[i]; j++) {
for (j = 0; j < secidx_i; j++) {
secp256k1_ecmult(&rgej, &pubs[count + j], &ens, &s[count + j]);
if (secp256k1_gej_is_infinity(&rgej)) {
return 0;
Expand All @@ -186,7 +192,7 @@ int secp256k1_borromean_sign(const secp256k1_ecmult_gen_context *ecmult_gen_ctx,
}
secp256k1_scalar_mul(&s[count + j], &ens, &sec[i]);
secp256k1_scalar_negate(&s[count + j], &s[count + j]);
secp256k1_scalar_add(&s[count + j], &s[count + j], &k[i]);
secp256k1_scalar_add(&s[count + j], &s[count + j], &k);
if (secp256k1_scalar_is_zero(&s[count + j])) {
return 0;
}
Expand Down
32 changes: 32 additions & 0 deletions src/modules/rangeproof/borromean_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**********************************************************************
* Copyright (c) 2021 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/

#ifndef _SECP256K1_BORROMEAN_UTIL_H_
#define _SECP256K1_BORROMEAN_UTIL_H_

#include <stddef.h> /* for size_t */
#include <stdint.h> /* for uint64_t */

/** A pointer to a function that returns a size_t given a ring index
*
* Used by borromean_sign to look up the size of each ring and the secret
* index, to avoid caching these values which would take excessive stack.
* As it turns out, both these values can be determined from the mantissa (for
* rangeproofs) or are constant (for surjection proofs or ring signatures)
*
* In: input: a single closed-over value
* index: which ring in the borromean ring signature this lookup
* function should look up
*/
typedef struct secp256k1_borromean_sz_closure {
uint64_t input;
size_t (*call)(const struct secp256k1_borromean_sz_closure* self, size_t index);
} secp256k1_borromean_sz_closure;

/** Create a sz_closure that just returns a constant */
secp256k1_borromean_sz_closure secp256k1_borromean_sz_closure_const(uint64_t c);

#endif
26 changes: 26 additions & 0 deletions src/modules/rangeproof/borromean_util_impl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**********************************************************************
* Copyright (c) 2021 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/

#ifndef _SECP256K1_BORROMEAN_UTIL_IMPL_H_
#define _SECP256K1_BORROMEAN_UTIL_IMPL_H_

#include "modules/rangeproof/borromean_util.h"
#include "util.h"

static size_t secp256k1_borromean_sz_closure_const_call(const secp256k1_borromean_sz_closure* self, size_t index) {
(void) index;
return self->input;
}

secp256k1_borromean_sz_closure secp256k1_borromean_sz_closure_const(uint64_t c) {
secp256k1_borromean_sz_closure ret;
VERIFY_CHECK(c < SIZE_MAX);
ret.input = c;
ret.call = secp256k1_borromean_sz_closure_const_call;
return ret;
}

#endif
13 changes: 10 additions & 3 deletions src/modules/rangeproof/main_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "modules/rangeproof/pedersen_impl.h"
#include "modules/rangeproof/borromean_impl.h"
#include "modules/rangeproof/borromean_util_impl.h"
#include "modules/rangeproof/rangeproof_impl.h"

/** Alternative generator for secp256k1.
Expand Down Expand Up @@ -231,17 +232,23 @@ int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, c

int secp256k1_rangeproof_info(const secp256k1_context* ctx, int *exp, int *mantissa,
uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, size_t plen) {
secp256k1_rangeproof_header header;
size_t offset;
uint64_t scale;
ARG_CHECK(exp != NULL);
ARG_CHECK(mantissa != NULL);
ARG_CHECK(min_value != NULL);
ARG_CHECK(max_value != NULL);
ARG_CHECK(proof != NULL);
offset = 0;
scale = 1;
(void)ctx;
return secp256k1_rangeproof_getheader_impl(&offset, exp, mantissa, &scale, min_value, max_value, proof, plen);
if (!secp256k1_rangeproof_header_parse(&header, &offset, proof, plen)) {
return 0;
}
*exp = header.exp;
*mantissa = header.mantissa;
*min_value = header.min_value;
*max_value = header.max_value;
return 1;
}

int secp256k1_rangeproof_rewind(const secp256k1_context* ctx,
Expand Down
73 changes: 73 additions & 0 deletions src/modules/rangeproof/rangeproof.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,79 @@
#include "ecmult.h"
#include "ecmult_gen.h"

/** Structure representing data directly encoded into a rangeproof header
*
* A rangeproof is a proof, associated with a Pedersen commitment, that a
* "proven value" in is the range [0, 2^mantissa]. The committed value is
* related to the proven value by the contents of this header, as
*
* committed = min_value + 10^exp * proven
*/
typedef struct secp256k1_rangeproof_header {
/** Power of ten to multiply the proven value by, or -1 for an exact proof
*
* Encoded in the header. */
int exp;
/** Number of bits used to represent the proven value
*
* Encoded in the header. */
size_t mantissa;
/** 10 to the power of exp, or 1 for a proof of an exact value.
*
* Implied by `exp`, not encoded. */
uint64_t scale;
/** Minimum value for the range (added to the proven value).
*
* Encoded in the header. */
uint64_t min_value;
/** Maximum value for the range (min_value + 10^exp * 2^mantissa).
*
* Implied by `min_value`, `exp`, `mantissa`. Not encoded. */
uint64_t max_value;
/** Number of rings to use in the underlying borromean ring signature
*
* Implied by `mantissa`. Not encoded. */
size_t n_rings;
/** Number of public keys to use in the underlying borromean ring signature
*
* Implied by `mantissa`. Not encoded. */
size_t n_pubs;
/** Number of keys in each ring
*
* Implied by `mantissa`. Not encoded. */
size_t rsizes[32];
} secp256k1_rangeproof_header;

/** Parses out a rangeproof header from a rangeproof and fills in all fields
*
* Returns: 1 on success, 0 on failure
* Out: header: the parsed header
* offset: the number of bytes of `proof` that the header occupied
* In: proof: the proof to parse the header out of
* plen: the length of the proof
*/
static int secp256k1_rangeproof_header_parse(
secp256k1_rangeproof_header* header,
size_t* offset,
const unsigned char* proof,
size_t plen
);

/** Serializes out a rangeproof header which has at least `exp`, `min_value` and `mantissa` set
*
* Returns: 1 on success, 0 on failure
* Out: proof: the buffer to serialize into
* offset: the number of bytes of `proof` that the header occupies
* In: plen: the length of the proof buffer
* header: the header to serialize
*/
static int secp256k1_rangeproof_header_serialize(
unsigned char* proof,
size_t plen,
size_t* offset,
const secp256k1_rangeproof_header* header
);

static int secp256k1_rangeproof_verify_impl(const secp256k1_ecmult_gen_context* ecmult_gen_ctx,
unsigned char *blindout, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce,
uint64_t *min_value, uint64_t *max_value, const secp256k1_ge *commit, const unsigned char *proof, size_t plen,
Expand Down
Loading