modules, tests: Port bitcoin-core/secp256k1#1777 and bitcoin-core/secp256k1#1824 to zkp-specific code

This commit is contained in:
DarkWindman
2026-04-02 18:03:37 +03:00
parent f7e7e6bb15
commit baac08d207
28 changed files with 259 additions and 224 deletions

View File

@@ -138,7 +138,7 @@ static void secp256k1_surjectionproof_csprng_init(secp256k1_surjectionproof_cspr
csprng->state_i = 0;
}
static size_t secp256k1_surjectionproof_csprng_next(secp256k1_surjectionproof_csprng *csprng, size_t rand_max) {
static size_t secp256k1_surjectionproof_csprng_next(const secp256k1_hash_ctx *hash_ctx, secp256k1_surjectionproof_csprng *csprng, size_t rand_max) {
/* The number of random bytes to read for each random sample */
const size_t increment = rand_max > 256 ? 2 : 1;
/* The maximum value expressable by the number of random bytes we read */
@@ -151,8 +151,8 @@ static size_t secp256k1_surjectionproof_csprng_next(secp256k1_surjectionproof_cs
if (csprng->state_i + increment >= 32) {
secp256k1_sha256 sha;
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, csprng->state, 32);
secp256k1_sha256_finalize(&sha, csprng->state);
secp256k1_sha256_write(hash_ctx, &sha, csprng->state, 32);
secp256k1_sha256_finalize(hash_ctx, &sha, csprng->state);
secp256k1_sha256_clear(&sha);
csprng->state_i = 0;
}
@@ -212,6 +212,7 @@ void secp256k1_surjectionproof_destroy(secp256k1_surjectionproof* proof) {
}
int secp256k1_surjectionproof_initialize(const secp256k1_context* ctx, secp256k1_surjectionproof* proof, size_t *input_index, const secp256k1_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, const secp256k1_fixed_asset_tag* fixed_output_tag, const size_t n_max_iterations, const unsigned char *random_seed32) {
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(ctx);
secp256k1_surjectionproof_csprng csprng;
size_t n_iterations = 0;
@@ -239,7 +240,7 @@ int secp256k1_surjectionproof_initialize(const secp256k1_context* ctx, secp256k1
for (i = 0; i < n_input_tags_to_use; i++) {
while (1) {
size_t next_input_index;
next_input_index = secp256k1_surjectionproof_csprng_next(&csprng, n_input_tags);
next_input_index = secp256k1_surjectionproof_csprng_next(hash_ctx, &csprng, n_input_tags);
if (secp256k1_memcmp_var(&fixed_input_tags[next_input_index], fixed_output_tag, sizeof(*fixed_output_tag)) == 0) {
*input_index = next_input_index;
has_output_tag = 1;
@@ -270,6 +271,7 @@ int secp256k1_surjectionproof_initialize(const secp256k1_context* ctx, secp256k1
}
int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_surjectionproof* proof, const secp256k1_generator* ephemeral_input_tags, size_t n_ephemeral_input_tags, const secp256k1_generator* ephemeral_output_tag, size_t input_index, const unsigned char *input_blinding_key, const unsigned char *output_blinding_key) {
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(ctx);
secp256k1_scalar blinding_key;
secp256k1_scalar tmps;
secp256k1_scalar nonce;
@@ -334,8 +336,8 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s
/* Produce signature */
rsizes[0] = (int) n_used_pubkeys;
indices[0] = (int) ring_input_index;
secp256k1_surjection_genmessage(msg32, ephemeral_input_tags, n_total_pubkeys, ephemeral_output_tag);
if (secp256k1_surjection_genrand(borromean_s, n_used_pubkeys, &blinding_key) == 0) {
secp256k1_surjection_genmessage(hash_ctx, msg32, ephemeral_input_tags, n_total_pubkeys, ephemeral_output_tag);
if (secp256k1_surjection_genrand(hash_ctx, borromean_s, n_used_pubkeys, &blinding_key) == 0) {
return 0;
}
/* Borromean sign will overwrite one of the s values we just generated, so use
@@ -343,7 +345,7 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s
* homage to the rangeproof code which does this very cleverly to encode messages. */
nonce = borromean_s[ring_input_index];
secp256k1_scalar_clear(&borromean_s[ring_input_index]);
if (secp256k1_borromean_sign(&ctx->ecmult_gen_ctx, &proof->data[0], borromean_s, ring_pubkeys, &nonce, &blinding_key, rsizes, indices, 1, msg32, 32) == 0) {
if (secp256k1_borromean_sign(hash_ctx, &ctx->ecmult_gen_ctx, &proof->data[0], borromean_s, ring_pubkeys, &nonce, &blinding_key, rsizes, indices, 1, msg32, 32) == 0) {
return 0;
}
for (i = 0; i < n_used_pubkeys; i++) {
@@ -356,6 +358,7 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s
static
#endif
int secp256k1_surjectionproof_verify(const secp256k1_context* ctx, const secp256k1_surjectionproof* proof, const secp256k1_generator* ephemeral_input_tags, size_t n_ephemeral_input_tags, const secp256k1_generator* ephemeral_output_tag) {
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(ctx);
size_t rsizes[1]; /* array needed for borromean sig API */
size_t i;
size_t n_total_pubkeys;
@@ -394,8 +397,8 @@ int secp256k1_surjectionproof_verify(const secp256k1_context* ctx, const secp256
return 0;
}
}
secp256k1_surjection_genmessage(msg32, ephemeral_input_tags, n_total_pubkeys, ephemeral_output_tag);
return secp256k1_borromean_verify(NULL, &proof->data[0], borromean_s, ring_pubkeys, rsizes, 1, msg32, 32);
secp256k1_surjection_genmessage(hash_ctx, msg32, ephemeral_input_tags, n_total_pubkeys, ephemeral_output_tag);
return secp256k1_borromean_verify(hash_ctx, NULL, &proof->data[0], borromean_s, ring_pubkeys, rsizes, 1, msg32, 32);
}
#endif

View File

@@ -15,7 +15,7 @@
#include "../../scalar.h"
#include "../../hash.h"
SECP256K1_INLINE static void secp256k1_surjection_genmessage(unsigned char *msg32, const secp256k1_generator *ephemeral_input_tags, size_t n_input_tags, const secp256k1_generator *ephemeral_output_tag) {
SECP256K1_INLINE static void secp256k1_surjection_genmessage(const secp256k1_hash_ctx *hash_ctx, unsigned char *msg32, const secp256k1_generator *ephemeral_input_tags, size_t n_input_tags, const secp256k1_generator *ephemeral_output_tag) {
/* compute message */
size_t i;
unsigned char pk_ser[33];
@@ -26,16 +26,16 @@ SECP256K1_INLINE static void secp256k1_surjection_genmessage(unsigned char *msg3
for (i = 0; i < n_input_tags; i++) {
pk_ser[0] = 2 + (ephemeral_input_tags[i].data[63] & 1);
memcpy(&pk_ser[1], &ephemeral_input_tags[i].data[0], 32);
secp256k1_sha256_write(&sha256_en, pk_ser, pk_len);
secp256k1_sha256_write(hash_ctx, &sha256_en, pk_ser, pk_len);
}
pk_ser[0] = 2 + (ephemeral_output_tag->data[63] & 1);
memcpy(&pk_ser[1], &ephemeral_output_tag->data[0], 32);
secp256k1_sha256_write(&sha256_en, pk_ser, pk_len);
secp256k1_sha256_finalize(&sha256_en, msg32);
secp256k1_sha256_write(hash_ctx, &sha256_en, pk_ser, pk_len);
secp256k1_sha256_finalize(hash_ctx, &sha256_en, msg32);
secp256k1_sha256_clear(&sha256_en);
}
SECP256K1_INLINE static int secp256k1_surjection_genrand(secp256k1_scalar *s, size_t ns, const secp256k1_scalar *blinding_key) {
SECP256K1_INLINE static int secp256k1_surjection_genrand(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar *s, size_t ns, const secp256k1_scalar *blinding_key) {
size_t i;
unsigned char sec_input[36];
secp256k1_sha256 sha256_en;
@@ -50,8 +50,8 @@ SECP256K1_INLINE static int secp256k1_surjection_genrand(secp256k1_scalar *s, si
sec_input[3] = i >> 24;
secp256k1_sha256_initialize(&sha256_en);
secp256k1_sha256_write(&sha256_en, sec_input, 36);
secp256k1_sha256_finalize(&sha256_en, sec_input);
secp256k1_sha256_write(hash_ctx, &sha256_en, sec_input, 36);
secp256k1_sha256_finalize(hash_ctx, &sha256_en, sec_input);
secp256k1_sha256_clear(&sha256_en);
secp256k1_scalar_set_b32(&s[i], sec_input, &overflow);
if (overflow == 1) {

View File

@@ -26,7 +26,7 @@ static void test_surjectionproof_api(void) {
size_t serialized_len;
secp256k1_surjectionproof proof;
secp256k1_surjectionproof* proof_on_heap;
size_t n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]);
size_t n_inputs = ARRAY_SIZE(fixed_input_tags);
size_t input_index;
size_t i;
@@ -146,7 +146,7 @@ static void test_input_selection(size_t n_inputs) {
size_t try_count = n_inputs * 100;
secp256k1_surjectionproof proof;
secp256k1_fixed_asset_tag fixed_input_tags[1000];
const size_t max_n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]) - 1;
const size_t max_n_inputs = ARRAY_SIZE(fixed_input_tags) - 1;
CHECK(n_inputs < max_n_inputs);
testrand256(seed);
@@ -313,7 +313,7 @@ static void test_gen_verify(size_t n_inputs, size_t n_used) {
secp256k1_fixed_asset_tag fixed_input_tags[1000];
secp256k1_generator ephemeral_input_tags[1000];
unsigned char *input_blinding_key[1000];
const size_t max_n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]) - 1;
const size_t max_n_inputs = ARRAY_SIZE(fixed_input_tags) - 1;
size_t try_count = n_inputs * 100;
size_t key_index;
size_t input_index;
@@ -395,6 +395,7 @@ static void test_gen_verify(size_t n_inputs, size_t n_used) {
/* check that a proof with empty n_used_inputs is invalid */
static void test_no_used_inputs_verify(void) {
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
secp256k1_surjectionproof proof;
secp256k1_fixed_asset_tag fixed_input_tag;
secp256k1_fixed_asset_tag fixed_output_tag;
@@ -422,10 +423,10 @@ static void test_no_used_inputs_verify(void) {
/* create "borromean signature" which is just a hash of metadata (pubkeys, etc) in this case */
secp256k1_generator_load(&output, &ephemeral_output_tag);
secp256k1_surjection_genmessage(proof.data, ephemeral_input_tags, 1, &ephemeral_output_tag);
secp256k1_surjection_genmessage(hash_ctx, proof.data, ephemeral_input_tags, 1, &ephemeral_output_tag);
secp256k1_sha256_initialize(&sha256_e0);
secp256k1_sha256_write(&sha256_e0, proof.data, 32);
secp256k1_sha256_finalize(&sha256_e0, proof.data);
secp256k1_sha256_write(hash_ctx, &sha256_e0, proof.data, 32);
secp256k1_sha256_finalize(hash_ctx, &sha256_e0, proof.data);
result = secp256k1_surjectionproof_verify(CTX, &proof, ephemeral_input_tags, n_ephemeral_input_tags, &ephemeral_output_tag);
CHECK(result == 0);