Skip to content

Commit 14b72a2

Browse files
committed
rangeproof: use rangeproof_header structure for proving
1 parent aa87cc8 commit 14b72a2

File tree

2 files changed

+157
-119
lines changed

2 files changed

+157
-119
lines changed

src/modules/rangeproof/rangeproof.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ typedef struct secp256k1_rangeproof_header {
2828
/** Number of bits used to represent the proven value
2929
*
3030
* Encoded in the header. */
31-
int mantissa;
31+
size_t mantissa;
3232
/** 10 to the power of exp, or 1 for a proof of an exact value.
3333
*
3434
* Implied by `exp`, not encoded. */
@@ -70,6 +70,21 @@ static int secp256k1_rangeproof_header_parse(
7070
size_t plen
7171
);
7272

73+
/** Serializes out a rangeproof header which has at least `exp`, `min_value` and `mantissa` set
74+
*
75+
* Returns: 1 on success, 0 on failure
76+
* Out: proof: the buffer to serialize into
77+
* offset: the number of bytes of `proof` that the header occupies
78+
* In: plen: the length of the proof buffer
79+
* header: the header to serialize
80+
*/
81+
static int secp256k1_rangeproof_header_serialize(
82+
unsigned char* proof,
83+
size_t plen,
84+
size_t* offset,
85+
const secp256k1_rangeproof_header* header
86+
);
87+
7388
static int secp256k1_rangeproof_verify_impl(const secp256k1_ecmult_gen_context* ecmult_gen_ctx,
7489
unsigned char *blindout, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce,
7590
uint64_t *min_value, uint64_t *max_value, const secp256k1_ge *commit, const unsigned char *proof, size_t plen,

src/modules/rangeproof/rangeproof_impl.h

Lines changed: 141 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,105 @@ static int secp256k1_rangeproof_header_parse(
109109
return secp256k1_rangeproof_header_expand(header);
110110
}
111111

112+
static int secp256k1_rangeproof_header_set_for_value(
113+
secp256k1_rangeproof_header* header,
114+
uint64_t* proven_value,
115+
const uint64_t min_value,
116+
const uint64_t min_bits,
117+
const int exp,
118+
const uint64_t value
119+
) {
120+
memset(header, 0, sizeof(*header));
121+
*proven_value = 0;
122+
123+
/* Sanity checks */
124+
if (min_value > value || min_bits > 64 || exp < -1 || exp > 18) {
125+
return 0;
126+
}
127+
128+
/* Start by just using the user's requested values, then adjust them in
129+
* various ways to make them compatible. This is probably not advisable
130+
* from a privacy point-of-view but it's important to be compatible with
131+
* the 2015-era API, and all of these issues will go away when we merge
132+
* Bulletproofs. */
133+
header->exp = exp;
134+
header->min_value = min_value;
135+
header->mantissa = min_bits ? min_bits : 1; /* force mantissa to be nonzero */
136+
137+
/* Special-case single-value proofs */
138+
if (header->exp == -1) {
139+
header->mantissa = 0; /* ignore user's min_bits */
140+
return secp256k1_rangeproof_header_expand(header);
141+
}
142+
143+
/* Deal with extreme values (copied directly from 2015 code) */
144+
if (min_bits > 61 || value > INT64_MAX) {
145+
/* Ten is not a power of two, so dividing by ten and then representing in base-2 times ten
146+
* expands the representable range. The verifier requires the proven range is within 0..2**64.
147+
* For very large numbers (all over 2**63) we must change our exponent to compensate.
148+
* Rather than handling it precisely, this just disables use of the exponent for big values.
149+
*/
150+
header->exp = 0;
151+
}
152+
{
153+
/* If the user has asked for more bits of proof then there is room for in the exponent, reduce the exponent. */
154+
uint64_t max = min_bits ? (UINT64_MAX >> (64 - min_bits)) : 0;
155+
int i;
156+
for (i = 0; i < header->exp && max <= UINT64_MAX / 10; i++) {
157+
max *= 10;
158+
}
159+
header->exp = i;
160+
}
161+
162+
163+
/* Increase the mantissa from min_bits until it actually covers the proven value */
164+
if (!secp256k1_rangeproof_header_expand(header)) {
165+
return 0;
166+
}
167+
*proven_value = (value - header->min_value) / header->scale;
168+
while (header->mantissa < 64 && (*proven_value >> header->mantissa) > 0) {
169+
header->mantissa++;
170+
}
171+
/* Fudge min_value so we don't lose the low-order digits of `value` */
172+
header->min_value = value - (*proven_value * header->scale);
173+
174+
/* Increasing the mantissa will have increased the number of rings etc
175+
* so re-expand the header to recompute the other derived values. */
176+
return secp256k1_rangeproof_header_expand(header);
177+
}
178+
179+
static int secp256k1_rangeproof_header_serialize(
180+
unsigned char* proof,
181+
size_t plen,
182+
size_t* offset,
183+
const secp256k1_rangeproof_header* header
184+
) {
185+
*offset = 0;
186+
if (plen < 65) {
187+
return 0;
188+
}
189+
190+
/* Write control byte */
191+
proof[0] = (header->exp >= 0 ? (64 | header->exp) : 0) | (header->min_value ? 32 : 0);
192+
*offset += 1;
193+
/* Write mantissa, for non-exact-value proofs */
194+
if (header->exp >= 0) {
195+
VERIFY_CHECK(header->mantissa > 0 && header->mantissa <= 64);
196+
proof[1] = header->mantissa - 1;
197+
*offset += 1;
198+
}
199+
/* Write min_value, if present */
200+
if (header->min_value > 0) {
201+
size_t i;
202+
for (i = 0; i < 8; i++) {
203+
proof[*offset + i] = (header->min_value >> ((7-i) * 8)) & 255;
204+
}
205+
*offset += 8;
206+
}
207+
208+
return 1;
209+
}
210+
112211
SECP256K1_INLINE static void secp256k1_rangeproof_pub_expand(secp256k1_gej *pubs,
113212
int exp, size_t *rsizes, size_t rings, const secp256k1_ge* genp) {
114213
secp256k1_gej base;
@@ -202,88 +301,12 @@ SECP256K1_INLINE static int secp256k1_rangeproof_genrand(secp256k1_scalar *sec,
202301
return ret;
203302
}
204303

205-
SECP256K1_INLINE static int secp256k1_range_proveparams(uint64_t *v, size_t *rings, size_t *rsizes, size_t *npub, size_t *secidx, uint64_t *min_value,
206-
int *mantissa, uint64_t *scale, int *exp, int *min_bits, uint64_t value) {
207-
size_t i;
208-
*rings = 1;
209-
rsizes[0] = 1;
210-
secidx[0] = 0;
211-
*scale = 1;
212-
*mantissa = 0;
213-
*npub = 0;
214-
if (*min_value == UINT64_MAX) {
215-
/* If the minimum value is the maximal representable value, then we cannot code a range. */
216-
*exp = -1;
217-
}
218-
if (*exp >= 0) {
219-
int max_bits;
220-
uint64_t v2;
221-
if ((*min_value && value > INT64_MAX) || (value && *min_value >= INT64_MAX)) {
222-
/* If either value or min_value is >= 2^63-1 then the other must by zero to avoid overflowing the proven range. */
223-
return 0;
224-
}
225-
max_bits = *min_value ? secp256k1_clz64_var(*min_value) : 64;
226-
if (*min_bits > max_bits) {
227-
*min_bits = max_bits;
228-
}
229-
if (*min_bits > 61 || value > INT64_MAX) {
230-
/** Ten is not a power of two, so dividing by ten and then representing in base-2 times ten
231-
* expands the representable range. The verifier requires the proven range is within 0..2**64.
232-
* For very large numbers (all over 2**63) we must change our exponent to compensate.
233-
* Rather than handling it precisely, this just disables use of the exponent for big values.
234-
*/
235-
*exp = 0;
236-
}
237-
/* Mask off the least significant digits, as requested. */
238-
*v = value - *min_value;
239-
/* If the user has asked for more bits of proof then there is room for in the exponent, reduce the exponent. */
240-
v2 = *min_bits ? (UINT64_MAX>>(64-*min_bits)) : 0;
241-
for (i = 0; (int) i < *exp && (v2 <= UINT64_MAX / 10); i++) {
242-
*v /= 10;
243-
v2 *= 10;
244-
}
245-
*exp = i;
246-
v2 = *v;
247-
for (i = 0; (int) i < *exp; i++) {
248-
v2 *= 10;
249-
*scale *= 10;
250-
}
251-
/* If the masked number isn't precise, compute the public offset. */
252-
*min_value = value - v2;
253-
/* How many bits do we need to represent our value? */
254-
*mantissa = *v ? 64 - secp256k1_clz64_var(*v) : 1;
255-
if (*min_bits > *mantissa) {
256-
/* If the user asked for more precision, give it to them. */
257-
*mantissa = *min_bits;
258-
}
259-
/* Digits in radix-4, except for the last digit if our mantissa length is odd. */
260-
*rings = (*mantissa + 1) >> 1;
261-
for (i = 0; i < *rings; i++) {
262-
rsizes[i] = ((i < *rings - 1) | (!(*mantissa&1))) ? 4 : 2;
263-
*npub += rsizes[i];
264-
secidx[i] = (*v >> (i*2)) & 3;
265-
}
266-
VERIFY_CHECK(*mantissa>0);
267-
VERIFY_CHECK((*v & ~(UINT64_MAX>>(64-*mantissa))) == 0); /* Did this get all the bits? */
268-
} else {
269-
/* A proof for an exact value. */
270-
*exp = 0;
271-
*min_value = value;
272-
*v = 0;
273-
*npub = 2;
274-
}
275-
VERIFY_CHECK(*v * *scale + *min_value == value);
276-
VERIFY_CHECK(*rings > 0);
277-
VERIFY_CHECK(*rings <= 32);
278-
VERIFY_CHECK(*npub <= 128);
279-
return 1;
280-
}
281-
282304
/* strawman interface, writes proof in proof, a buffer of plen, proves with respect to min_value the range for commit which has the provided blinding factor and value. */
283305
SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmult_gen_context* ecmult_gen_ctx,
284306
unsigned char *proof, size_t *plen, uint64_t min_value,
285307
const secp256k1_ge *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value,
286308
const unsigned char *message, size_t msg_len, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_ge* genp){
309+
secp256k1_rangeproof_header header;
287310
secp256k1_gej pubs[128]; /* Candidate digits for our proof, most inferred. */
288311
secp256k1_scalar s[128]; /* Signatures in our proof, most forged. */
289312
secp256k1_scalar sec[32]; /* Blinding factors for the correct digits. */
@@ -294,44 +317,43 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul
294317
unsigned char tmp[33];
295318
unsigned char *signs; /* Location of sign flags in the proof. */
296319
uint64_t v;
297-
uint64_t scale; /* scale = 10^exp. */
298-
int mantissa; /* Number of bits proven in the blinded value. */
299-
size_t rings; /* How many digits will our proof cover. */
300-
size_t rsizes[32]; /* How many possible values there are for each place. */
301320
size_t secidx[32]; /* Which digit is the correct one. */
302321
size_t len; /* Number of bytes used so far. */
303322
size_t i;
323+
size_t pub_idx;
304324
int overflow;
305-
size_t npub;
306325
len = 0;
307-
if (*plen < 65 || min_value > value || min_bits > 64 || min_bits < 0 || exp < -1 || exp > 18) {
326+
if (*plen < 65) {
308327
return 0;
309328
}
310-
if (!secp256k1_range_proveparams(&v, &rings, rsizes, &npub, secidx, &min_value, &mantissa, &scale, &exp, &min_bits, value)) {
329+
330+
if (!secp256k1_rangeproof_header_set_for_value(&header, &v, min_value, min_bits, exp, value)) {
311331
return 0;
312332
}
313-
proof[len] = (rsizes[0] > 1 ? (64 | exp) : 0) | (min_value ? 32 : 0);
314-
len++;
315-
if (rsizes[0] > 1) {
316-
VERIFY_CHECK(mantissa > 0 && mantissa <= 64);
317-
proof[len] = mantissa - 1;
318-
len++;
319-
}
320-
if (min_value) {
321-
for (i = 0; i < 8; i++) {
322-
proof[len + i] = (min_value >> ((7-i) * 8)) & 255;
333+
if (header.exp >= 0) {
334+
for (i = 0; i < header.n_rings; i++) {
335+
secidx[i] = (v >> (i * 2)) & 3;
323336
}
324-
len += 8;
337+
} else {
338+
secidx[0] = 0;
325339
}
340+
341+
VERIFY_CHECK(v * header.scale + header.min_value == value);
342+
VERIFY_CHECK(header.n_rings > 0);
343+
VERIFY_CHECK(header.n_rings <= 32);
344+
VERIFY_CHECK(header.n_pubs <= 128);
345+
346+
secp256k1_rangeproof_header_serialize (proof, *plen, &len, &header);
347+
326348
/* Do we have enough room in the proof for the message? Each ring gives us 128 bytes, but the
327349
* final ring is used to encode the blinding factor and the value, so we can't use that. (Well,
328350
* technically there are 64 bytes available if we avoided the other data, but this is difficult
329351
* because it's not always in the same place. */
330-
if (msg_len > 0 && msg_len > 128 * (rings - 1)) {
352+
if (msg_len > 0 && msg_len > 128 * (header.n_rings - 1)) {
331353
return 0;
332354
}
333355
/* Do we have enough room for the proof? */
334-
if (*plen - len < 32 * (npub + rings - 1) + 32 + ((rings+6) >> 3)) {
356+
if (*plen - len < 32 * (header.n_pubs + header.n_rings - 1) + 32 + ((header.n_rings + 6) >> 3)) {
335357
return 0;
336358
}
337359
secp256k1_sha256_initialize(&sha256_m);
@@ -346,23 +368,23 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul
346368
memcpy(prep, message, msg_len);
347369
}
348370
/* Note, the data corresponding to the blinding factors must be zero. */
349-
if (rsizes[rings - 1] > 1) {
371+
if (header.rsizes[header.n_rings - 1] > 1) {
350372
size_t idx;
351373
/* Value encoding sidechannel. */
352-
idx = rsizes[rings - 1] - 1;
353-
idx -= secidx[rings - 1] == idx;
354-
idx = ((rings - 1) * 4 + idx) * 32;
374+
idx = header.rsizes[header.n_rings - 1] - 1;
375+
idx -= secidx[header.n_rings - 1] == idx;
376+
idx = ((header.n_rings - 1) * 4 + idx) * 32;
355377
for (i = 0; i < 8; i++) {
356378
prep[8 + i + idx] = prep[16 + i + idx] = prep[24 + i + idx] = (v >> (56 - i * 8)) & 255;
357379
prep[i + idx] = 0;
358380
}
359381
prep[idx] = 128;
360382
}
361-
if (!secp256k1_rangeproof_genrand(sec, s, prep, rsizes, rings, nonce, commit, proof, len, genp)) {
383+
if (!secp256k1_rangeproof_genrand(sec, s, prep, header.rsizes, header.n_rings, nonce, commit, proof, len, genp)) {
362384
return 0;
363385
}
364386
memset(prep, 0, 4096);
365-
for (i = 0; i < rings; i++) {
387+
for (i = 0; i < header.n_rings; i++) {
366388
/* Sign will overwrite the non-forged signature, move that random value into the nonce. */
367389
k[i] = s[i * 4 + secidx[i]];
368390
secp256k1_scalar_clear(&s[i * 4 + secidx[i]]);
@@ -374,50 +396,51 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul
374396
* blinded value for one digit.
375397
*/
376398
secp256k1_scalar_set_b32(&stmp, blind, &overflow);
377-
secp256k1_scalar_add(&sec[rings - 1], &sec[rings - 1], &stmp);
378-
if (overflow || secp256k1_scalar_is_zero(&sec[rings - 1])) {
399+
secp256k1_scalar_add(&sec[header.n_rings - 1], &sec[header.n_rings - 1], &stmp);
400+
if (overflow || secp256k1_scalar_is_zero(&sec[header.n_rings - 1])) {
379401
return 0;
380402
}
381403
signs = &proof[len];
382404
/* We need one sign bit for each blinded value we send. */
383-
for (i = 0; i < (rings + 6) >> 3; i++) {
405+
for (i = 0; i < (header.n_rings + 6) >> 3; i++) {
384406
signs[i] = 0;
385407
len++;
386408
}
387-
npub = 0;
388-
for (i = 0; i < rings; i++) {
409+
pub_idx = 0;
410+
for (i = 0; i < header.n_rings; i++) {
389411
/*OPT: Use the precomputed gen2 basis?*/
390-
secp256k1_pedersen_ecmult(ecmult_gen_ctx, &pubs[npub], &sec[i], ((uint64_t)secidx[i] * scale) << (i*2), genp);
391-
if (secp256k1_gej_is_infinity(&pubs[npub])) {
412+
secp256k1_pedersen_ecmult(ecmult_gen_ctx, &pubs[pub_idx], &sec[i], ((uint64_t)secidx[i] * header.scale) << (i*2), genp);
413+
if (secp256k1_gej_is_infinity(&pubs[pub_idx])) {
392414
return 0;
393415
}
394-
if (i < rings - 1) {
416+
if (i < header.n_rings - 1) {
395417
unsigned char tmpc[33];
396418
secp256k1_ge c;
397419
unsigned char quadness;
398420
/*OPT: split loop and batch invert.*/
399-
/*OPT: do not compute full pubs[npub] in ge form; we only need x */
400-
secp256k1_ge_set_gej_var(&c, &pubs[npub]);
421+
/*OPT: do not compute full pubs[pub_idx] in ge form; we only need x */
422+
secp256k1_ge_set_gej_var(&c, &pubs[pub_idx]);
401423
secp256k1_rangeproof_serialize_point(tmpc, &c);
402424
quadness = tmpc[0];
403425
secp256k1_sha256_write(&sha256_m, tmpc, 33);
404426
signs[i>>3] |= quadness << (i&7);
405427
memcpy(&proof[len], tmpc + 1, 32);
406428
len += 32;
407429
}
408-
npub += rsizes[i];
430+
pub_idx += header.rsizes[i];
409431
}
410-
secp256k1_rangeproof_pub_expand(pubs, exp, rsizes, rings, genp);
432+
VERIFY_CHECK(pub_idx == header.n_pubs);
433+
secp256k1_rangeproof_pub_expand(pubs, header.exp, header.rsizes, header.n_rings, genp);
411434
if (extra_commit != NULL) {
412435
secp256k1_sha256_write(&sha256_m, extra_commit, extra_commit_len);
413436
}
414437
secp256k1_sha256_finalize(&sha256_m, tmp);
415-
if (!secp256k1_borromean_sign(ecmult_gen_ctx, &proof[len], s, pubs, k, sec, rsizes, secidx, rings, tmp, 32)) {
438+
if (!secp256k1_borromean_sign(ecmult_gen_ctx, &proof[len], s, pubs, k, sec, header.rsizes, secidx, header.n_rings, tmp, 32)) {
416439
return 0;
417440
}
418441
len += 32;
419-
for (i = 0; i < npub; i++) {
420-
secp256k1_scalar_get_b32(&proof[len],&s[i]);
442+
for (i = 0; i < pub_idx; i++) {
443+
secp256k1_scalar_get_b32(&proof[len], &s[i]);
421444
len += 32;
422445
}
423446
VERIFY_CHECK(len <= *plen);

0 commit comments

Comments
 (0)