Skip to content

Commit 3cd525b

Browse files
committed
rangeproof: add method to verify single-value proofs
1 parent 9eea081 commit 3cd525b

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

src/modules/rangeproof/main_impl.h

+94
Original file line numberDiff line numberDiff line change
@@ -304,4 +304,98 @@ int secp256k1_rangeproof_sign(const secp256k1_context* ctx, unsigned char *proof
304304
proof, plen, min_value, &commitp, blind, nonce, exp, min_bits, value, message, msg_len, extra_commit, extra_commit_len, &genp);
305305
}
306306

307+
int secp256k1_rangeproof_verify_value(const secp256k1_context* ctx, const unsigned char* proof, size_t plen, uint64_t value, const secp256k1_pedersen_commitment* commit, const secp256k1_generator* gen) {
308+
secp256k1_ge commitp;
309+
secp256k1_ge genp;
310+
secp256k1_gej tmpj;
311+
secp256k1_gej xj;
312+
secp256k1_ge rp;
313+
secp256k1_scalar es;
314+
secp256k1_scalar ss;
315+
secp256k1_sha256 sha2;
316+
unsigned char tmpch[33];
317+
unsigned char pp_comm[32];
318+
size_t offset;
319+
size_t sz;
320+
int overflow;
321+
322+
VERIFY_CHECK(ctx != NULL);
323+
ARG_CHECK(proof != NULL);
324+
ARG_CHECK(commit != NULL);
325+
ARG_CHECK(gen != NULL);
326+
327+
if (plen != 73 && plen != 65) {
328+
return 0;
329+
}
330+
/* 0x80 must be unset for any rangeproof; 0x40 indicates "has nonzero range"
331+
* so must also be unset for single-value proofs */
332+
if ((proof[0] & 0xC0) != 0x00) {
333+
return 0;
334+
}
335+
336+
secp256k1_pedersen_commitment_load(&commitp, commit);
337+
secp256k1_generator_load(&genp, gen);
338+
/* Verify that value in the header is what we expect; 0x20 is "has nonzero min-value" */
339+
if ((proof[0] & 0x20) == 0x00) {
340+
if (value != 0) {
341+
return 0;
342+
}
343+
offset = 1;
344+
} else {
345+
int i;
346+
uint64_t claimed = 0;
347+
for (i = 0; i < 8; i++) {
348+
claimed = (claimed << 8) | proof[1 + i];
349+
}
350+
if (value != claimed) {
351+
return 0;
352+
}
353+
offset = 9;
354+
}
355+
/* Subtract value from commitment; store modified commitment in xj */
356+
secp256k1_pedersen_ecmult_small(&tmpj, value, &genp);
357+
secp256k1_gej_neg(&tmpj, &tmpj);
358+
secp256k1_gej_add_ge_var(&xj, &tmpj, &commitp, NULL);
359+
360+
/* Now we just have a Schnorr signature in (e, s) form. The verification
361+
* equation is e == H(sG - eX || proof params) */
362+
363+
/* 1. Compute slow/overwrought commitment to proof params */
364+
secp256k1_sha256_initialize(&sha2);
365+
secp256k1_rangeproof_serialize_point(tmpch, &commitp);
366+
secp256k1_sha256_write(&sha2, tmpch, 33);
367+
secp256k1_rangeproof_serialize_point(tmpch, &genp);
368+
secp256k1_sha256_write(&sha2, tmpch, 33);
369+
secp256k1_sha256_write(&sha2, proof, offset); /* lol we commit to one extra byte here */
370+
secp256k1_sha256_finalize(&sha2, pp_comm);
371+
372+
/* ... feed this into our hash */
373+
secp256k1_borromean_hash(tmpch, pp_comm, 32, &proof[offset], 32, 0, 0);
374+
secp256k1_scalar_set_b32(&es, tmpch, &overflow);
375+
if (overflow || secp256k1_scalar_is_zero(&es)) {
376+
return 0;
377+
}
378+
379+
/* 1. Compute R = sG - eX */
380+
secp256k1_scalar_set_b32(&ss, &proof[offset + 32], &overflow);
381+
if (overflow || secp256k1_scalar_is_zero(&ss)) {
382+
return 0;
383+
}
384+
secp256k1_ecmult(&tmpj, &xj, &es, &ss);
385+
if (secp256k1_gej_is_infinity(&tmpj)) {
386+
return 0;
387+
}
388+
secp256k1_ge_set_gej(&rp, &tmpj);
389+
secp256k1_eckey_pubkey_serialize(&rp, tmpch, &sz, 1);
390+
391+
/* 2. Compute e = H(R || proof params) */
392+
secp256k1_sha256_initialize(&sha2);
393+
secp256k1_sha256_write(&sha2, tmpch, sz);
394+
secp256k1_sha256_write(&sha2, pp_comm, sizeof(pp_comm));
395+
secp256k1_sha256_finalize(&sha2, tmpch);
396+
397+
/* 3. Check computed e against original e */
398+
return !memcmp(tmpch, &proof[offset], 32);
399+
}
400+
307401
#endif

src/modules/rangeproof/tests_impl.h

+2
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,8 @@ void test_rangeproof_fixed_vectors(void) {
919919
CHECK(min_value == UINT64_MAX);
920920
CHECK(max_value == UINT64_MAX);
921921
CHECK(m_len == 0);
922+
923+
CHECK(secp256k1_rangeproof_verify_value(ctx, vector_3, sizeof(vector_3), UINT64_MAX, &pc, secp256k1_generator_h));
922924
}
923925
}
924926

0 commit comments

Comments
 (0)