Merge remote-tracking branch 'origin/fix/code-scanning-alerts' into dev

This commit is contained in:
shrec 2026-03-21 14:15:44 +00:00
commit d49453d935
No known key found for this signature in database
5 changed files with 156 additions and 103 deletions

View File

@ -278,7 +278,7 @@ Sponsorship helps sustain development of:
| **Bitcoin Lightning** | `shrec@stacker.news` (any Lightning wallet) |
| **PayPal** | [paypal.me/IChkheidze](https://paypal.me/IChkheidze) |
| **Corporate / Foundation** | [payysoon@gmail.com](mailto:payysoon@gmail.com) |
| **Discord** | [Join our server](https://discord.gg/sUmW7cc5) |
| **Discord** | [Join our server](https://discord.gg/E4BK8SeMYU) |
All sponsors will be acknowledged in the README, release notes, and project documentation.
For corporate partnerships, audit co-funding, or grant applications -- please reach out via email.

View File

@ -298,7 +298,7 @@ static void test_musig2_rogue_key() {
uint8_t pubkeys_dup[64];
std::memcpy(pubkeys_dup, xonly1, 32);
std::memcpy(pubkeys_dup + 32, xonly1, 32);
rc = ufsecp_musig2_key_agg(ctx, pubkeys_dup, 2, keyagg, agg_pub);
(void)ufsecp_musig2_key_agg(ctx, pubkeys_dup, 2, keyagg, agg_pub);
CHECK(true, "key_agg with duplicate keys did not crash");
ufsecp_ctx_destroy(ctx);
@ -354,7 +354,7 @@ static void test_musig2_transcript_mutation() {
rc = ufsecp_musig2_partial_sign(ctx, sn1, priv1, keyagg_bad, session, 0, psig);
if (rc == UFSECP_OK) {
// The partial sig should not verify with the original keyagg
ufsecp_error_t vrc = ufsecp_musig2_partial_verify(ctx, psig, pn1, xonly1,
const ufsecp_error_t vrc = ufsecp_musig2_partial_verify(ctx, psig, pn1, xonly1,
keyagg, session, 0);
CHECK(vrc != UFSECP_OK, "psig from corrupted keyagg must not verify against real keyagg");
} else {
@ -407,11 +407,11 @@ static void test_musig2_signer_ordering() {
// Signer 1 signs with index=1 (should be index=0)
uint8_t psig1_wrong[32];
ufsecp_error_t rc = ufsecp_musig2_partial_sign(ctx, sn1, priv1, keyagg, session, 1, psig1_wrong);
const ufsecp_error_t rc = ufsecp_musig2_partial_sign(ctx, sn1, priv1, keyagg, session, 1, psig1_wrong);
if (rc == UFSECP_OK) {
// Partial verify should catch the index mismatch
ufsecp_error_t vrc = ufsecp_musig2_partial_verify(ctx, psig1_wrong, pn1, xonly1,
const ufsecp_error_t vrc = ufsecp_musig2_partial_verify(ctx, psig1_wrong, pn1, xonly1,
keyagg, session, 0);
CHECK(vrc != UFSECP_OK, "verify catches signer with wrong index");
} else {
@ -464,7 +464,7 @@ static void test_musig2_malicious_aggregator() {
aggnonce_bad[38] ^= 0xFF;
uint8_t session[UFSECP_MUSIG2_SESSION_LEN];
ufsecp_error_t rc = ufsecp_musig2_start_sign_session(ctx, aggnonce_bad, keyagg, msg32, session);
const ufsecp_error_t rc = ufsecp_musig2_start_sign_session(ctx, aggnonce_bad, keyagg, msg32, session);
if (rc == UFSECP_OK) {
uint8_t psig1[32], psig2[32];
@ -478,7 +478,7 @@ static void test_musig2_malicious_aggregator() {
ufsecp_musig2_partial_sig_agg(ctx, psigs, 2, session, final_sig);
// Final sig from tampered aggnonce must NOT verify
ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_sig, agg_pub);
const ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_sig, agg_pub);
CHECK(vrc != UFSECP_OK, "sig from tampered aggnonce must not verify");
} else {
CHECK(true, "start_session correctly rejected tampered aggnonce");
@ -534,7 +534,7 @@ static void test_musig2_abort_restart() {
// Verify secnonce1 was consumed -- reuse must fail
uint8_t psig1_reuse[32];
ufsecp_error_t rc = ufsecp_musig2_partial_sign(ctx, sn1, priv1, keyagg, session, 0, psig1_reuse);
const ufsecp_error_t rc = ufsecp_musig2_partial_sign(ctx, sn1, priv1, keyagg, session, 0, psig1_reuse);
CHECK(rc != UFSECP_OK, "consumed secnonce reuse after abort must fail");
// Session 2: restart with completely fresh nonces -- must succeed
@ -569,7 +569,7 @@ static void test_musig2_abort_restart() {
"restarted session produces valid signature");
// Verify aborted partial sig is invalid under fresh session
ufsecp_error_t vrc = ufsecp_musig2_partial_verify(ctx, psig1_abort, pn1f,
const ufsecp_error_t vrc = ufsecp_musig2_partial_verify(ctx, psig1_abort, pn1f,
xonly1, keyagg, session_f, 0);
CHECK(vrc != UFSECP_OK, "aborted partial sig rejected in fresh session");
@ -663,7 +663,7 @@ static void test_frost_below_threshold() {
ncommit1, 1,
group_pub, msg32, final_sig);
if (arc == UFSECP_OK) {
ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_sig, group_pub + 1);
const ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_sig, group_pub + 1);
CHECK(vrc != UFSECP_OK, "below-threshold sig must not verify");
} else {
CHECK(true, "below-threshold aggregate correctly rejected");
@ -758,7 +758,7 @@ static void test_frost_malformed_commitment() {
ncommits_bad, 2,
group_pub, msg32, final_sig);
if (arc == UFSECP_OK) {
ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_sig, group_pub + 1);
const ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_sig, group_pub + 1);
CHECK(vrc != UFSECP_OK, "sig from corrupted nonce commits must not verify");
} else {
CHECK(true, "aggregate correctly rejected corrupted commits");
@ -847,7 +847,7 @@ static void test_frost_malicious_coordinator() {
uint8_t recv_shares[512]; size_t recv_len = 0;
for (uint32_t j = 0; j < 3; ++j) {
std::memcpy(recv_shares + recv_len,
shares[j] + i * UFSECP_FROST_SHARE_LEN,
shares[j] + static_cast<size_t>(i) * UFSECP_FROST_SHARE_LEN,
UFSECP_FROST_SHARE_LEN);
recv_len += UFSECP_FROST_SHARE_LEN;
}
@ -888,11 +888,11 @@ static void test_frost_malicious_coordinator() {
std::memcpy(psigs_all, psig1, 36);
std::memcpy(psigs_all + 36, psig2, 36);
uint8_t final_sig[64];
ufsecp_error_t arc = ufsecp_frost_aggregate(ctx, psigs_all, 2,
const ufsecp_error_t arc = ufsecp_frost_aggregate(ctx, psigs_all, 2,
ncommits_good, 2,
group_pub, msg32, final_sig);
if (arc == UFSECP_OK) {
ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_sig, group_pub + 1);
const ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_sig, group_pub + 1);
CHECK(vrc != UFSECP_OK, "sig from inconsistent coordinator views must not verify");
} else {
CHECK(true, "aggregate correctly rejected inconsistent partial sigs");
@ -933,7 +933,7 @@ static void test_frost_duplicate_nonce() {
uint8_t recv_shares[512]; size_t recv_len = 0;
for (uint32_t j = 0; j < 3; ++j) {
std::memcpy(recv_shares + recv_len,
shares[j] + i * UFSECP_FROST_SHARE_LEN,
shares[j] + static_cast<size_t>(i) * UFSECP_FROST_SHARE_LEN,
UFSECP_FROST_SHARE_LEN);
recv_len += UFSECP_FROST_SHARE_LEN;
}
@ -958,7 +958,7 @@ static void test_frost_duplicate_nonce() {
std::memcpy(ncommits_dup + UFSECP_FROST_NONCE_COMMIT_LEN, nc1, UFSECP_FROST_NONCE_COMMIT_LEN);
uint8_t psig1[36];
ufsecp_error_t rc = ufsecp_frost_sign(ctx, keypkgs[0], nonce1, msg32,
const ufsecp_error_t rc = ufsecp_frost_sign(ctx, keypkgs[0], nonce1, msg32,
ncommits_dup, 2, psig1);
// Should either reject or produce an invalid result
if (rc == UFSECP_OK) {
@ -966,11 +966,11 @@ static void test_frost_duplicate_nonce() {
std::memcpy(psigs_dup, psig1, 36);
std::memcpy(psigs_dup + 36, psig1, 36);
uint8_t final_sig[64];
ufsecp_error_t arc = ufsecp_frost_aggregate(ctx, psigs_dup, 2,
const ufsecp_error_t arc = ufsecp_frost_aggregate(ctx, psigs_dup, 2,
ncommits_dup, 2,
group_pub, msg32, final_sig);
if (arc == UFSECP_OK) {
ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_sig, group_pub + 1);
const ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_sig, group_pub + 1);
CHECK(vrc != UFSECP_OK, "sig from duplicate nonces must not verify");
} else {
CHECK(true, "aggregate rejected duplicate nonce commits");
@ -1016,7 +1016,7 @@ static void test_frost_participant_identity_mismatch() {
uint8_t recv_shares[512]; size_t recv_len = 0;
for (uint32_t j = 0; j < 3; ++j) {
std::memcpy(recv_shares + recv_len,
shares_buf[j] + i * UFSECP_FROST_SHARE_LEN,
shares_buf[j] + static_cast<size_t>(i) * UFSECP_FROST_SHARE_LEN,
UFSECP_FROST_SHARE_LEN);
recv_len += UFSECP_FROST_SHARE_LEN;
}
@ -1067,11 +1067,11 @@ static void test_frost_participant_identity_mismatch() {
std::memcpy(psigs_sw, psig_s, 36);
std::memcpy(psigs_sw + 36, psig_s2, 36);
uint8_t final_sig[64];
ufsecp_error_t arc = ufsecp_frost_aggregate(ctx, psigs_sw, 2,
const ufsecp_error_t arc = ufsecp_frost_aggregate(ctx, psigs_sw, 2,
ncommits_swapped, 2,
group_pub, msg32, final_sig);
if (arc == UFSECP_OK) {
ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_sig, group_pub + 1);
const ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_sig, group_pub + 1);
CHECK(vrc != UFSECP_OK, "sig from swapped participant IDs must not verify");
} else {
CHECK(true, "aggregate rejected swapped participant IDs");
@ -1127,11 +1127,11 @@ static void test_frost_participant_identity_mismatch() {
std::memcpy(psigs_did, psig_dup_id, 36);
std::memcpy(psigs_did + 36, psig_dup_id2, 36);
uint8_t final_sig[64];
ufsecp_error_t arc = ufsecp_frost_aggregate(ctx, psigs_did, 2,
const ufsecp_error_t arc = ufsecp_frost_aggregate(ctx, psigs_did, 2,
ncommits_dup_id, 2,
group_pub, msg32, final_sig);
if (arc == UFSECP_OK) {
ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_sig, group_pub + 1);
const ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_sig, group_pub + 1);
CHECK(vrc != UFSECP_OK, "sig from duplicate participant IDs must not verify");
} else {
CHECK(true, "aggregate rejected duplicate participant IDs (division by zero)");
@ -1175,7 +1175,7 @@ static void test_frost_stale_commitment_replay() {
uint8_t recv_shares[512]; size_t recv_len = 0;
for (uint32_t j = 0; j < 3; ++j) {
std::memcpy(recv_shares + recv_len,
shares_buf[j] + i * UFSECP_FROST_SHARE_LEN,
shares_buf[j] + static_cast<size_t>(i) * UFSECP_FROST_SHARE_LEN,
UFSECP_FROST_SHARE_LEN);
recv_len += UFSECP_FROST_SHARE_LEN;
}
@ -1233,7 +1233,7 @@ static void test_frost_stale_commitment_replay() {
// Signer 1 signs with fresh nonce but stale commit set -> binding mismatch
uint8_t psig_stale[36];
ufsecp_error_t rc = ufsecp_frost_sign(ctx, keypkgs[0], nonce_r2_1, msg32,
const ufsecp_error_t rc = ufsecp_frost_sign(ctx, keypkgs[0], nonce_r2_1, msg32,
ncommits_stale, 2, psig_stale);
if (rc == UFSECP_OK) {
// Signer 2 signs with fresh nonce and same stale commit set
@ -1243,11 +1243,11 @@ static void test_frost_stale_commitment_replay() {
std::memcpy(psigs_stale, psig_stale, 36);
std::memcpy(psigs_stale + 36, psig_r2_2, 36);
uint8_t final_stale[64];
ufsecp_error_t arc = ufsecp_frost_aggregate(ctx, psigs_stale, 2,
const ufsecp_error_t arc = ufsecp_frost_aggregate(ctx, psigs_stale, 2,
ncommits_stale, 2,
group_pub, msg32, final_stale);
if (arc == UFSECP_OK) {
ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_stale, group_pub + 1);
const ufsecp_error_t vrc = ufsecp_schnorr_verify(ctx, msg32, final_stale, group_pub + 1);
CHECK(vrc != UFSECP_OK,
"sig with stale commitment replay must not verify");
} else {
@ -1622,7 +1622,7 @@ static void test_ecdsa_adaptor_transcript_mismatch() {
"adaptor sign on msg1");
// Verify with DIFFERENT message
ufsecp_error_t rc = ufsecp_ecdsa_adaptor_verify(ctx, pre_sig, pub33, msg2, adaptor_point);
const ufsecp_error_t rc = ufsecp_ecdsa_adaptor_verify(ctx, pre_sig, pub33, msg2, adaptor_point);
CHECK(rc != UFSECP_OK, "adaptor verify must reject wrong message");
ufsecp_ctx_destroy(ctx);
@ -1658,7 +1658,7 @@ static void test_ecdsa_adaptor_extraction_misuse() {
// Try extraction with pre_sig (msg1) + unrelated_sig (msg2)
uint8_t extracted[32];
ufsecp_error_t rc = ufsecp_ecdsa_adaptor_extract(ctx, pre_sig, unrelated_sig, extracted);
const ufsecp_error_t rc = ufsecp_ecdsa_adaptor_extract(ctx, pre_sig, unrelated_sig, extracted);
if (rc == UFSECP_OK) {
// If extraction "succeeds", the extracted secret must NOT match original
@ -1666,7 +1666,7 @@ static void test_ecdsa_adaptor_extraction_misuse() {
ufsecp_pubkey_create(ctx, extracted, ext_point);
uint8_t neg_point[33];
ufsecp_pubkey_negate(ctx, ext_point, neg_point);
bool match = (std::memcmp(ext_point, adaptor_point, 33) == 0) ||
const bool match = (std::memcmp(ext_point, adaptor_point, 33) == 0) ||
(std::memcmp(neg_point, adaptor_point, 33) == 0);
CHECK(!match, "extract from unrelated sig must not yield real secret");
} else {
@ -1836,12 +1836,12 @@ static void test_dleq_malformed_proof() {
// Corruption strategies: flip each half of proof
static const int offsets[] = {0, 4, 16, 32, 48, 60};
for (int offset : offsets) {
for (const int offset : offsets) {
uint8_t bad_proof[UFSECP_ZK_DLEQ_PROOF_LEN];
std::memcpy(bad_proof, proof, UFSECP_ZK_DLEQ_PROOF_LEN);
bad_proof[offset] ^= 0xFF;
ufsecp_error_t rc = ufsecp_zk_dleq_verify(ctx, bad_proof, G33, H33, P33, Q33);
const ufsecp_error_t rc = ufsecp_zk_dleq_verify(ctx, bad_proof, G33, H33, P33, Q33);
CHECK(rc != UFSECP_OK, "DLEQ verify rejects corrupted proof");
}
@ -1884,11 +1884,11 @@ static void test_dleq_wrong_generators() {
ufsecp_zk_dleq_prove(ctx, secret, G33, H33, P33, Q33, aux, proof);
// Verify with G and H swapped -- must reject
ufsecp_error_t rc1 = ufsecp_zk_dleq_verify(ctx, proof, H33, G33, P33, Q33);
const ufsecp_error_t rc1 = ufsecp_zk_dleq_verify(ctx, proof, H33, G33, P33, Q33);
CHECK(rc1 != UFSECP_OK, "DLEQ verify rejects swapped G/H");
// Verify with P and Q swapped -- must reject
ufsecp_error_t rc2 = ufsecp_zk_dleq_verify(ctx, proof, G33, H33, Q33, P33);
const ufsecp_error_t rc2 = ufsecp_zk_dleq_verify(ctx, proof, G33, H33, Q33, P33);
CHECK(rc2 != UFSECP_OK, "DLEQ verify rejects swapped P/Q");
// Verify with an entirely different H' (scalar=7)
@ -1897,7 +1897,7 @@ static void test_dleq_wrong_generators() {
uint8_t H_prime[33];
ufsecp_pubkey_create(ctx, seven, H_prime);
ufsecp_error_t rc3 = ufsecp_zk_dleq_verify(ctx, proof, G33, H_prime, P33, Q33);
const ufsecp_error_t rc3 = ufsecp_zk_dleq_verify(ctx, proof, G33, H_prime, P33, Q33);
CHECK(rc3 != UFSECP_OK, "DLEQ verify rejects proof with different H'");
// Verify with different G' (scalar=5)
@ -1906,7 +1906,7 @@ static void test_dleq_wrong_generators() {
uint8_t G_prime[33];
ufsecp_pubkey_create(ctx, five, G_prime);
ufsecp_error_t rc4 = ufsecp_zk_dleq_verify(ctx, proof, G_prime, H33, P33, Q33);
const ufsecp_error_t rc4 = ufsecp_zk_dleq_verify(ctx, proof, G_prime, H33, P33, Q33);
CHECK(rc4 != UFSECP_OK, "DLEQ verify rejects proof with different G'");
ufsecp_ctx_destroy(ctx);
@ -2476,13 +2476,13 @@ static void test_ffi_undersized_buffers() {
{
uint8_t tiny_der[4] = {}; // way too small (need 70-72)
size_t tiny_len = sizeof(tiny_der);
ufsecp_error_t rc = ufsecp_ecdsa_sig_to_der(ctx, sig64, tiny_der, &tiny_len);
const ufsecp_error_t rc = ufsecp_ecdsa_sig_to_der(ctx, sig64, tiny_der, &tiny_len);
CHECK(rc != UFSECP_OK, "DER encode rejects undersized buffer (4 bytes)");
}
{
uint8_t der_1[1] = {};
size_t len_1 = 1;
ufsecp_error_t rc = ufsecp_ecdsa_sig_to_der(ctx, sig64, der_1, &len_1);
const ufsecp_error_t rc = ufsecp_ecdsa_sig_to_der(ctx, sig64, der_1, &len_1);
CHECK(rc != UFSECP_OK, "DER encode rejects buffer of 1 byte");
}
@ -2490,13 +2490,13 @@ static void test_ffi_undersized_buffers() {
{
char tiny_wif[4] = {}; // WIF is ~52 chars
size_t wif_len = sizeof(tiny_wif);
ufsecp_error_t rc = ufsecp_wif_encode(ctx, priv, 1, 0x80, tiny_wif, &wif_len);
const ufsecp_error_t rc = ufsecp_wif_encode(ctx, priv, 1, 0x80, tiny_wif, &wif_len);
CHECK(rc != UFSECP_OK, "WIF encode rejects undersized buffer (4 bytes)");
}
{
char wif_0[1] = {};
size_t wif_len0 = 0;
ufsecp_error_t rc = ufsecp_wif_encode(ctx, priv, 1, 0x80, wif_0, &wif_len0);
const ufsecp_error_t rc = ufsecp_wif_encode(ctx, priv, 1, 0x80, wif_0, &wif_len0);
CHECK(rc != UFSECP_OK, "WIF encode rejects zero-length buffer");
}
@ -2505,7 +2505,7 @@ static void test_ffi_undersized_buffers() {
uint8_t entropy[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
char tiny_mn[4] = {}; // 12-word mnemonic is ~100+ chars
size_t mn_len = sizeof(tiny_mn);
ufsecp_error_t rc = ufsecp_bip39_generate(ctx, 16, entropy, tiny_mn, &mn_len);
const ufsecp_error_t rc = ufsecp_bip39_generate(ctx, 16, entropy, tiny_mn, &mn_len);
CHECK(rc != UFSECP_OK, "BIP-39 generate rejects undersized mnemonic buffer");
}
@ -2550,8 +2550,7 @@ static void test_ffi_overlapping_buffers() {
uint8_t tweak[32] = {};
tweak[31] = 1;
rc = ufsecp_pubkey_tweak_add(ctx, tweak_buf, tweak, tweak_buf);
// Should either produce correct result or reject -- not crash
(void)ufsecp_pubkey_tweak_add(ctx, tweak_buf, tweak, tweak_buf); // Should either produce correct result or reject -- not crash
CHECK(true, "overlapping tweak_add did not crash");
ufsecp_ctx_destroy(ctx);
@ -2573,13 +2572,13 @@ static void test_ffi_malformed_counts() {
// n=0 pubkeys -- should reject
{
ufsecp_error_t rc = ufsecp_pubkey_combine(ctx, pub33, 0, out33);
const ufsecp_error_t rc = ufsecp_pubkey_combine(ctx, pub33, 0, out33);
CHECK(rc != UFSECP_OK, "pubkey_combine n=0 rejects");
}
// n=1 but only 33 bytes of data -- should work
{
ufsecp_error_t rc = ufsecp_pubkey_combine(ctx, pub33, 1, out33);
const ufsecp_error_t rc = ufsecp_pubkey_combine(ctx, pub33, 1, out33);
if (rc == UFSECP_OK) {
CHECK(std::memcmp(out33, pub33, 33) == 0, "combine n=1 returns same key");
} else {
@ -2598,7 +2597,7 @@ static void test_ffi_malformed_counts() {
// multi_scalar_mul with n=0
{
uint8_t dummy_sc[32], dummy_pt[33], dummy_out[33];
ufsecp_error_t rc = ufsecp_multi_scalar_mul(ctx, dummy_sc, dummy_pt, 0, dummy_out);
const ufsecp_error_t rc = ufsecp_multi_scalar_mul(ctx, dummy_sc, dummy_pt, 0, dummy_out);
CHECK(true, "multi_scalar_mul n=0 did not crash");
(void)rc;
}
@ -2664,7 +2663,7 @@ static void test_ffi_invalid_enums() {
// Invalid compressed flag for WIF encode
{
addr_len = sizeof(addr_buf);
ufsecp_error_t rc = ufsecp_wif_encode(ctx, priv, 42, UFSECP_NET_MAINNET,
const ufsecp_error_t rc = ufsecp_wif_encode(ctx, priv, 42, UFSECP_NET_MAINNET,
addr_buf, &addr_len);
CHECK(rc != UFSECP_OK || addr_len > 0,
"wif_encode with compressed=42 did not crash");
@ -2675,7 +2674,7 @@ static void test_ffi_invalid_enums() {
const char* junk_wif = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
uint8_t out_key[32];
int comp_out = -1, net_out = -1;
ufsecp_error_t rc = ufsecp_wif_decode(ctx, junk_wif,
const ufsecp_error_t rc = ufsecp_wif_decode(ctx, junk_wif,
out_key, &comp_out, &net_out);
CHECK(rc != UFSECP_OK, "wif_decode with junk string rejects");
}

View File

@ -286,8 +286,9 @@ ecies_encrypt(const Point& recipient_pubkey,
const std::uint8_t* plaintext, std::size_t plaintext_len) {
// 33 (pubkey) + 16 (IV) + plaintext_len + 32 (HMAC) = 81 + plaintext_len
if (recipient_pubkey.is_infinity() || !plaintext || plaintext_len == 0
|| plaintext_len > SIZE_MAX - 81)
|| plaintext_len > SIZE_MAX - 81) {
return {};
}
// 1. Generate ephemeral keypair
std::uint8_t eph_bytes[32];

View File

@ -57,11 +57,12 @@ std::array<std::uint8_t, 32> bitcoin_message_hash(const std::uint8_t* msg,
// Construct: prefix + varint(msg_len) + msg
// Then double-SHA256 the result
std::uint8_t varint_buf[9];
std::size_t varint_len = write_varint(varint_buf, msg_len);
const std::size_t varint_len = write_varint(varint_buf, msg_len);
// Overflow guard: prefix(25) + varint(<=9) + msg_len
if (msg_len > SIZE_MAX - BITCOIN_MSG_PREFIX_LEN - 9)
if (msg_len > SIZE_MAX - BITCOIN_MSG_PREFIX_LEN - 9) {
return {};
}
// Total payload size
const std::size_t total = BITCOIN_MSG_PREFIX_LEN + varint_len + msg_len;

View File

@ -541,8 +541,9 @@ ufsecp_error_t ufsecp_ecdsa_verify(ufsecp_ctx* ctx,
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "non-canonical compact sig");
}
auto pk = point_from_compressed(pubkey33);
if (pk.is_infinity())
if (pk.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_PUBKEY, "invalid public key");
}
if (!secp256k1::ecdsa_verify(msg, pk, ecdsasig)) {
return ctx_set_err(ctx, UFSECP_ERR_VERIFY_FAIL, "ECDSA verify failed");
@ -976,8 +977,9 @@ ufsecp_error_t ufsecp_addr_p2wpkh(ufsecp_ctx* ctx,
ctx_clear_err(ctx);
auto pk = point_from_compressed(pubkey33);
if (pk.is_infinity())
if (pk.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_PUBKEY, "invalid pubkey");
}
auto addr = secp256k1::address_p2wpkh(pk, to_network(network));
if (addr.empty()) {
return ctx_set_err(ctx, UFSECP_ERR_INTERNAL, "P2WPKH generation failed");
@ -1707,19 +1709,22 @@ ufsecp_error_t ufsecp_musig2_start_sign_session(
/* Deserialize agg nonce */
secp256k1::MuSig2AggNonce an;
an.R1 = point_from_compressed(aggnonce);
if (an.R1.is_infinity())
if (an.R1.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid agg nonce R1");
}
an.R2 = point_from_compressed(aggnonce + 33);
if (an.R2.is_infinity())
if (an.R2.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid agg nonce R2");
}
/* Deserialize key agg context */
secp256k1::MuSig2KeyAggCtx kagg;
uint32_t nk = 0;
std::memcpy(&nk, keyagg, 4);
kagg.Q_negated = (keyagg[4] != 0);
kagg.Q = point_from_compressed(keyagg + 5);
if (kagg.Q.is_infinity())
if (kagg.Q.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_KEY, "invalid aggregated key");
}
auto qc = kagg.Q.to_compressed();
std::memcpy(kagg.Q_x.data(), qc.data() + 1, 32);
for (uint32_t i = 0; i < nk && (38u + static_cast<size_t>(i+1)*32u <= UFSECP_MUSIG2_KEYAGG_LEN); ++i) {
@ -1770,8 +1775,9 @@ ufsecp_error_t ufsecp_musig2_partial_sign(
secp256k1::MuSig2KeyAggCtx kagg;
{ uint32_t nk = 0; std::memcpy(&nk, keyagg, 4); kagg.Q_negated = (keyagg[4] != 0);
kagg.Q = point_from_compressed(keyagg + 5);
if (kagg.Q.is_infinity())
if (kagg.Q.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_KEY, "invalid aggregated key");
}
auto qc = kagg.Q.to_compressed(); std::memcpy(kagg.Q_x.data(), qc.data() + 1, 32);
for (uint32_t i = 0; i < nk && (38u + (i+1)*32u <= UFSECP_MUSIG2_KEYAGG_LEN); ++i) {
Scalar s;
@ -1783,8 +1789,9 @@ ufsecp_error_t ufsecp_musig2_partial_sign(
}
secp256k1::MuSig2Session sess;
sess.R = point_from_compressed(session);
if (sess.R.is_infinity())
if (sess.R.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid session R point");
}
if (!scalar_parse_strict(session + 33, sess.b))
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid session scalar b");
}
@ -1825,8 +1832,9 @@ ufsecp_error_t ufsecp_musig2_partial_verify(
secp256k1::MuSig2KeyAggCtx kagg;
{ uint32_t nk = 0; std::memcpy(&nk, keyagg, 4); kagg.Q_negated = (keyagg[4] != 0);
kagg.Q = point_from_compressed(keyagg + 5);
if (kagg.Q.is_infinity())
if (kagg.Q.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_KEY, "invalid aggregated key");
}
auto qc = kagg.Q.to_compressed(); std::memcpy(kagg.Q_x.data(), qc.data() + 1, 32);
for (uint32_t i = 0; i < nk && (38u + (i+1)*32u <= UFSECP_MUSIG2_KEYAGG_LEN); ++i) {
Scalar s;
@ -1838,8 +1846,9 @@ ufsecp_error_t ufsecp_musig2_partial_verify(
}
secp256k1::MuSig2Session sess;
sess.R = point_from_compressed(session);
if (sess.R.is_infinity())
if (sess.R.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid session R point");
}
if (!scalar_parse_strict(session + 33, sess.b))
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid session scalar b");
}
@ -1868,8 +1877,9 @@ ufsecp_error_t ufsecp_musig2_partial_sig_agg(
}
secp256k1::MuSig2Session sess;
sess.R = point_from_compressed(session);
if (sess.R.is_infinity())
if (sess.R.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid session R point");
}
if (!scalar_parse_strict(session + 33, sess.b))
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid session scalar b");
}
@ -1961,8 +1971,9 @@ ufsecp_error_t ufsecp_frost_keygen_finalize(
}
for (uint32_t j = 0; j < cc; ++j) {
auto pt = point_from_compressed(all_commits + pos);
if (pt.is_infinity())
if (pt.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid commitment coefficient");
}
fc.coeffs.push_back(pt);
pos += 33;
}
@ -2050,11 +2061,13 @@ ufsecp_error_t ufsecp_frost_sign(
return ctx_set_err(ctx, UFSECP_ERR_BAD_KEY, "invalid signing share in keypkg");
}
kp.verification_share = point_from_compressed(keypkg + 44);
if (kp.verification_share.is_infinity())
if (kp.verification_share.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_KEY, "invalid verification share");
}
kp.group_public_key = point_from_compressed(keypkg + 77);
if (kp.group_public_key.is_infinity())
if (kp.group_public_key.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_KEY, "invalid group public key");
}
secp256k1::FrostNonce fn;
Scalar h, b;
if (!scalar_parse_strict(nonce, h)) {
@ -2072,11 +2085,13 @@ ufsecp_error_t ufsecp_frost_sign(
const uint8_t* nc = nonce_commits + i * UFSECP_FROST_NONCE_COMMIT_LEN;
std::memcpy(&ncs[i].id, nc, 4);
ncs[i].hiding_point = point_from_compressed(nc + 4);
if (ncs[i].hiding_point.is_infinity())
if (ncs[i].hiding_point.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid hiding nonce point");
}
ncs[i].binding_point = point_from_compressed(nc + 37);
if (ncs[i].binding_point.is_infinity())
if (ncs[i].binding_point.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid binding nonce point");
}
}
auto psig = secp256k1::frost_sign(kp, fn, msg_arr, ncs);
secp256k1::detail::secure_erase(&kp.signing_share, sizeof(kp.signing_share));
@ -2118,11 +2133,13 @@ ufsecp_error_t ufsecp_frost_verify_partial(
const uint8_t* nc = nonce_commits + i * UFSECP_FROST_NONCE_COMMIT_LEN;
std::memcpy(&ncs[i].id, nc, 4);
ncs[i].hiding_point = point_from_compressed(nc + 4);
if (ncs[i].hiding_point.is_infinity())
if (ncs[i].hiding_point.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid hiding nonce point");
}
ncs[i].binding_point = point_from_compressed(nc + 37);
if (ncs[i].binding_point.is_infinity())
if (ncs[i].binding_point.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid binding nonce point");
}
if (ncs[i].id == psig.id) {
signer_commit = ncs[i];
found_signer = true;
@ -2170,15 +2187,18 @@ ufsecp_error_t ufsecp_frost_aggregate(
const uint8_t* nc = nonce_commits + i * UFSECP_FROST_NONCE_COMMIT_LEN;
std::memcpy(&ncs[i].id, nc, 4);
ncs[i].hiding_point = point_from_compressed(nc + 4);
if (ncs[i].hiding_point.is_infinity())
if (ncs[i].hiding_point.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid hiding nonce point");
}
ncs[i].binding_point = point_from_compressed(nc + 37);
if (ncs[i].binding_point.is_infinity())
if (ncs[i].binding_point.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid binding nonce point");
}
}
auto gp = point_from_compressed(group_pubkey33);
if (gp.is_infinity())
if (gp.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_KEY, "invalid group public key");
}
std::array<uint8_t, 32> msg_arr;
std::memcpy(msg_arr.data(), msg32, 32);
auto sig = secp256k1::frost_aggregate(psigs, ncs, gp, msg_arr);
@ -2237,8 +2257,9 @@ ufsecp_error_t ufsecp_schnorr_adaptor_verify(
ctx_clear_err(ctx);
secp256k1::SchnorrAdaptorSig as;
as.R_hat = point_from_compressed(pre_sig);
if (as.R_hat.is_infinity())
if (as.R_hat.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid adaptor R_hat");
}
Scalar shat;
if (!scalar_parse_strict(pre_sig + 33, shat)) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid adaptor sig scalar");
@ -2272,8 +2293,9 @@ ufsecp_error_t ufsecp_schnorr_adaptor_adapt(
ctx_clear_err(ctx);
secp256k1::SchnorrAdaptorSig as;
as.R_hat = point_from_compressed(pre_sig);
if (as.R_hat.is_infinity())
if (as.R_hat.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid adaptor R_hat");
}
Scalar shat;
if (!scalar_parse_strict(pre_sig + 33, shat)) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid adaptor sig scalar");
@ -2300,8 +2322,9 @@ ufsecp_error_t ufsecp_schnorr_adaptor_extract(
ctx_clear_err(ctx);
secp256k1::SchnorrAdaptorSig as;
as.R_hat = point_from_compressed(pre_sig);
if (as.R_hat.is_infinity())
if (as.R_hat.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid adaptor R_hat");
}
Scalar shat;
if (!scalar_parse_strict(pre_sig + 33, shat)) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid adaptor sig scalar");
@ -2309,8 +2332,9 @@ ufsecp_error_t ufsecp_schnorr_adaptor_extract(
as.s_hat = shat;
as.needs_negation = (pre_sig[65] != 0);
secp256k1::SchnorrSignature sig;
if (!secp256k1::SchnorrSignature::parse_strict(sig64, sig))
if (!secp256k1::SchnorrSignature::parse_strict(sig64, sig)) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid schnorr signature");
}
auto [secret, ok] = secp256k1::schnorr_adaptor_extract(as, sig);
if (!ok) {
return ctx_set_err(ctx, UFSECP_ERR_INTERNAL, "adaptor extract failed");
@ -2365,14 +2389,17 @@ ufsecp_error_t ufsecp_ecdsa_adaptor_verify(
ctx_clear_err(ctx);
secp256k1::ECDSAAdaptorSig as;
as.R_hat = point_from_compressed(pre_sig);
if (as.R_hat.is_infinity())
if (as.R_hat.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid adaptor R_hat");
}
Scalar shat;
if (!scalar_parse_strict(pre_sig + 33, shat))
if (!scalar_parse_strict(pre_sig + 33, shat)) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid adaptor sig scalar");
}
as.s_hat = shat;
if (!scalar_parse_strict(pre_sig + 65, as.r))
if (!scalar_parse_strict(pre_sig + 65, as.r)) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid adaptor sig r");
}
auto pk = point_from_compressed(pubkey33);
if (pk.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_PUBKEY, "invalid pubkey");
@ -2398,14 +2425,17 @@ ufsecp_error_t ufsecp_ecdsa_adaptor_adapt(
ctx_clear_err(ctx);
secp256k1::ECDSAAdaptorSig as;
as.R_hat = point_from_compressed(pre_sig);
if (as.R_hat.is_infinity())
if (as.R_hat.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid adaptor R_hat");
}
Scalar shat;
if (!scalar_parse_strict(pre_sig + 33, shat))
if (!scalar_parse_strict(pre_sig + 33, shat)) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid adaptor sig scalar");
}
as.s_hat = shat;
if (!scalar_parse_strict(pre_sig + 65, as.r))
if (!scalar_parse_strict(pre_sig + 65, as.r)) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid adaptor sig r");
}
Scalar secret;
if (!scalar_parse_strict_nonzero(adaptor_secret, secret)) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "adaptor secret is zero or >= n");
@ -2426,14 +2456,17 @@ ufsecp_error_t ufsecp_ecdsa_adaptor_extract(
ctx_clear_err(ctx);
secp256k1::ECDSAAdaptorSig as;
as.R_hat = point_from_compressed(pre_sig);
if (as.R_hat.is_infinity())
if (as.R_hat.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid adaptor R_hat");
}
Scalar shat;
if (!scalar_parse_strict(pre_sig + 33, shat))
if (!scalar_parse_strict(pre_sig + 33, shat)) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid adaptor sig scalar");
}
as.s_hat = shat;
if (!scalar_parse_strict(pre_sig + 65, as.r))
if (!scalar_parse_strict(pre_sig + 65, as.r)) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_SIG, "invalid adaptor sig r");
}
std::array<uint8_t, 64> compact;
std::memcpy(compact.data(), sig64, 64);
secp256k1::ECDSASignature ecdsasig;
@ -2486,8 +2519,9 @@ ufsecp_error_t ufsecp_pedersen_verify(ufsecp_ctx* ctx,
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "blinding >= n");
}
auto commit_pt = point_from_compressed(commitment33);
if (commit_pt.is_infinity())
if (commit_pt.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid commitment point");
}
if (!secp256k1::pedersen_verify(secp256k1::PedersenCommitment{commit_pt}, v, b)) {
return ctx_set_err(ctx, UFSECP_ERR_VERIFY_FAIL, "Pedersen verify failed");
}
@ -2502,14 +2536,16 @@ ufsecp_error_t ufsecp_pedersen_verify_sum(ufsecp_ctx* ctx,
std::vector<secp256k1::PedersenCommitment> pcs(n_pos), ncs(n_neg);
for (size_t i = 0; i < n_pos; ++i) {
auto p = point_from_compressed(pos + i * 33);
if (p.is_infinity())
if (p.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid positive commitment");
}
pcs[i] = secp256k1::PedersenCommitment{p};
}
for (size_t i = 0; i < n_neg; ++i) {
auto p = point_from_compressed(neg + i * 33);
if (p.is_infinity())
if (p.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid negative commitment");
}
ncs[i] = secp256k1::PedersenCommitment{p};
}
if (!secp256k1::pedersen_verify_sum(pcs.data(), n_pos, ncs.data(), n_neg)) {
@ -2522,16 +2558,21 @@ ufsecp_error_t ufsecp_pedersen_blind_sum(ufsecp_ctx* ctx,
const uint8_t* blinds_in, size_t n_in,
const uint8_t* blinds_out, size_t n_out,
uint8_t sum32_out[32]) {
if (!ctx || (!blinds_in && n_in > 0) || (!blinds_out && n_out > 0) || !sum32_out)
if (!ctx || (!blinds_in && n_in > 0) || (!blinds_out && n_out > 0) || !sum32_out) {
return UFSECP_ERR_NULL_ARG;
}
ctx_clear_err(ctx);
std::vector<Scalar> ins(n_in), outs(n_out);
for (size_t i = 0; i < n_in; ++i)
if (!scalar_parse_strict(blinds_in + i * 32, ins[i]))
for (size_t i = 0; i < n_in; ++i) {
if (!scalar_parse_strict(blinds_in + i * 32, ins[i])) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid input blind");
for (size_t i = 0; i < n_out; ++i)
if (!scalar_parse_strict(blinds_out + i * 32, outs[i]))
}
}
for (size_t i = 0; i < n_out; ++i) {
if (!scalar_parse_strict(blinds_out + i * 32, outs[i])) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid output blind");
}
}
auto sum = secp256k1::pedersen_blind_sum(ins.data(), n_in, outs.data(), n_out);
scalar_to_bytes(sum, sum32_out);
return UFSECP_OK;
@ -2637,8 +2678,9 @@ ufsecp_error_t ufsecp_zk_dleq_prove(
auto H = point_from_compressed(H33);
auto P = point_from_compressed(P33);
auto Q = point_from_compressed(Q33);
if (G.is_infinity() || H.is_infinity() || P.is_infinity() || Q.is_infinity())
if (G.is_infinity() || H.is_infinity() || P.is_infinity() || Q.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_PUBKEY, "invalid DLEQ point");
}
std::array<uint8_t, 32> aux_arr;
std::memcpy(aux_arr.data(), aux_rand, 32);
auto proof = secp256k1::zk::dleq_prove(s, G, H, P, Q, aux_arr);
@ -2659,8 +2701,9 @@ ufsecp_error_t ufsecp_zk_dleq_verify(
auto H = point_from_compressed(H33);
auto P = point_from_compressed(P33);
auto Q = point_from_compressed(Q33);
if (G.is_infinity() || H.is_infinity() || P.is_infinity() || Q.is_infinity())
if (G.is_infinity() || H.is_infinity() || P.is_infinity() || Q.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_PUBKEY, "invalid DLEQ point");
}
secp256k1::zk::DLEQProof dp;
if (!secp256k1::zk::DLEQProof::deserialize(proof, dp)) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid DLEQ proof");
@ -2683,11 +2726,13 @@ ufsecp_error_t ufsecp_zk_range_prove(
}
ctx_clear_err(ctx);
Scalar b;
if (!scalar_parse_strict(blinding, b))
if (!scalar_parse_strict(blinding, b)) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "blinding >= n");
}
auto commit_pt = point_from_compressed(commitment33);
if (commit_pt.is_infinity())
if (commit_pt.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid commitment point");
}
auto commit = secp256k1::PedersenCommitment{commit_pt};
std::array<uint8_t, 32> aux_arr;
std::memcpy(aux_arr.data(), aux_rand, 32);
@ -2740,8 +2785,9 @@ ufsecp_error_t ufsecp_zk_range_verify(
bool scalar_ok = true;
auto read_scalar = [&]() -> Scalar {
Scalar s;
if (!scalar_parse_strict(proof + off, s))
if (!scalar_parse_strict(proof + off, s)) {
scalar_ok = false;
}
off += 32;
return s;
};
@ -2751,13 +2797,16 @@ ufsecp_error_t ufsecp_zk_range_verify(
for (int i = 0; i < 6; ++i) rp.L[i] = read_point();
for (int i = 0; i < 6; ++i) rp.R[i] = read_point();
rp.a = read_scalar(); rp.b = read_scalar();
if (!point_ok)
if (!point_ok) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid point in range proof");
if (!scalar_ok)
}
if (!scalar_ok) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid scalar in range proof");
}
auto commit_pt = point_from_compressed(commitment33);
if (commit_pt.is_infinity())
if (commit_pt.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "invalid commitment point");
}
auto commit = secp256k1::PedersenCommitment{commit_pt};
if (!secp256k1::zk::range_verify(commit, rp)) {
return ctx_set_err(ctx, UFSECP_ERR_VERIFY_FAIL, "range proof failed");
@ -2784,8 +2833,9 @@ ufsecp_error_t ufsecp_coin_address(ufsecp_ctx* ctx,
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "unknown coin type");
}
auto pk = point_from_compressed(pubkey33);
if (pk.is_infinity())
if (pk.is_infinity()) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_PUBKEY, "invalid pubkey");
}
auto addr = secp256k1::coins::coin_address(pk, *coin, testnet != 0);
if (addr.empty()) {
return ctx_set_err(ctx, UFSECP_ERR_INTERNAL, "address generation failed");
@ -3094,12 +3144,14 @@ ufsecp_error_t ufsecp_ecies_encrypt(
uint8_t* envelope_out, size_t* envelope_len) {
if (!ctx || !recipient_pubkey33 || !plaintext || !envelope_out || !envelope_len) {
return UFSECP_ERR_NULL_ARG;
if (plaintext_len == 0)
if (plaintext_len == 0) {
return UFSECP_ERR_BAD_INPUT;
}
ctx_clear_err(ctx);
if (plaintext_len > SIZE_MAX - UFSECP_ECIES_OVERHEAD)
if (plaintext_len > SIZE_MAX - UFSECP_ECIES_OVERHEAD) {
return ctx_set_err(ctx, UFSECP_ERR_BAD_INPUT, "plaintext_len too large");
}
size_t const needed = plaintext_len + UFSECP_ECIES_OVERHEAD;
if (*envelope_len < needed) {
return ctx_set_err(ctx, UFSECP_ERR_BUF_TOO_SMALL, "envelope buffer too small");