Merge remote-tracking branch 'origin/fix/code-scanning-alerts' into dev
This commit is contained in:
commit
d49453d935
@ -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.
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
@ -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];
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user