Repository: bitcoin/bitcoin
File: src/key.cpp (C++)

Code before:
    assert(rec != -1);
    vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
    // Additional verification step to prevent using a potentially corrupted signature
    secp256k1_pubkey epk, rpk;
    ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &epk, UCharCast(begin()));
    assert(ret);
    ret = secp256k1_ecdsa_recover(secp256k1_context_static, &rpk, &rsig, hash.begin());
    assert(ret);
    ret = secp256k1_ec_pubkey_cmp(secp256k1_context_static, &epk, &rpk);
    assert(ret == 0);
    return true;
}

bool CKey::SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint256* merkle_root, const uint256& aux) const
{
    assert(sig.size() == 64);
    bool ret = 1;
    KeyPair keypair = ComputeKeyPair();
    if (!keypair.IsValid()) return false;
    if (merkle_root) {
        secp256k1_xonly_pubkey pubkey;
        ret &= secp256k1_keypair_xonly_pub(secp256k1_context_sign, &pubkey, nullptr, reinterpret_cast<const secp256k1_keypair*>(keypair.data()));
        unsigned char pubkey_bytes[32];
        ret &= secp256k1_xonly_pubkey_serialize(secp256k1_context_sign, pubkey_bytes, &pubkey);
        uint256 tweak = XOnlyPubKey(pubkey_bytes).ComputeTapTweakHash(merkle_root->IsNull() ? nullptr : merkle_root);
        ret &= secp256k1_keypair_xonly_tweak_add(secp256k1_context_static, reinterpret_cast<secp256k1_keypair*>(keypair.data()), tweak.data());
    }
    if (!ret) return false;
    ret &= secp256k1_schnorrsig_sign32(secp256k1_context_sign, sig.data(), hash.data(), reinterpret_cast<const secp256k1_keypair*>(keypair.data()), aux.data());
    if (ret) {
        // Additional verification step to prevent using a potentially corrupted signature
        secp256k1_xonly_pubkey pubkey_verify;
        ret &= secp256k1_keypair_xonly_pub(secp256k1_context_static, &pubkey_verify, nullptr, reinterpret_cast<const secp256k1_keypair*>(keypair.data()));
        ret &= secp256k1_schnorrsig_verify(secp256k1_context_static, sig.data(), hash.begin(), 32, &pubkey_verify);
    }
    if (!ret) memory_cleanse(sig.data(), sig.size());
    memory_cleanse(&keypair, sizeof(keypair));
    return ret;
}

bool CKey::Load(const CPrivKey &seckey, const CPubKey &vchPubKey, bool fSkipCheck=false) {
    MakeKeyData();
    if (!ec_seckey_import_der(secp256k1_context_sign, (unsigned char*)begin(), seckey.data(), seckey.size())) {
        ClearKeyData();
        return false;
    }
    fCompressed = vchPubKey.IsCompressed();

    if (fSkipCheck)
        return true;


Review comment (refactor):
Might make the code more uniform (and maybe the diff simpler, if we'd extract it as suggested above) if instead of not making this a const cast, like the rest, we rather added the const to the method's signature:
```patch
diff --git a/src/secp256k1/include/secp256k1_extrakeys.h b/src/secp256k1/include/secp256k1_extrakeys.h
--- a/src/secp256k1/include/secp256k1_extrakeys.h	(revision 21d031e7867ef97c07cee691c115d59b3aebfd19)
+++ b/src/secp256k1/include/secp256k1_extrakeys.h	(date 1721245901582)
@@ -236,7 +236,7 @@
  */
 SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add(
     const secp256k1_context *ctx,
-    secp256k1_keypair *keypair,
+    const secp256k1_keypair *keypair,
     const unsigned char *tweak32
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
 
Index: src/secp256k1/src/modules/extrakeys/main_impl.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/secp256k1/src/modules/extrakeys/main_impl.h b/src/secp256k1/src/modules/extrakeys/main_impl.h
--- a/src/secp256k1/src/modules/extrakeys/main_impl.h	(revision 21d031e7867ef97c07cee691c115d59b3aebfd19)
+++ b/src/secp256k1/src/modules/extrakeys/main_impl.h	(date 1721245849520)
@@ -252,7 +252,7 @@
     return 1;
 }
 
-int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *tweak32) {
+int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, const secp256k1_keypair *keypair, const unsigned char *tweak32) {
     secp256k1_ge pk;
     secp256k1_scalar sk;
     int y_parity;
```

Code after:
    assert(rec != -1);
    vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
    // Additional verification step to prevent using a potentially corrupted signature
    secp256k1_pubkey epk, rpk;
    ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &epk, UCharCast(begin()));
    assert(ret);
    ret = secp256k1_ecdsa_recover(secp256k1_context_static, &rpk, &rsig, hash.begin());
    assert(ret);
    ret = secp256k1_ec_pubkey_cmp(secp256k1_context_static, &epk, &rpk);
    assert(ret == 0);
    return true;
}

bool CKey::SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint256* merkle_root, const uint256& aux) const
{
    KeyPair kp = ComputeKeyPair(merkle_root);
    return kp.SignSchnorr(hash, sig, aux);
}

bool CKey::Load(const CPrivKey &seckey, const CPubKey &vchPubKey, bool fSkipCheck=false) {
    MakeKeyData();
    if (!ec_seckey_import_der(secp256k1_context_sign, (unsigned char*)begin(), seckey.data(), seckey.size())) {
        ClearKeyData();
        return false;
    }
    fCompressed = vchPubKey.IsCompressed();

    if (fSkipCheck)
        return true;

    return VerifyPubKey(vchPubKey);
}

bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const {
    assert(IsValid());
    assert(IsCompressed());
    std::vector<unsigned char, secure_allocator<unsigned char>> vout(64);
    if ((nChild >> 31) == 0) {
        CPubKey pubkey = GetPubKey();
        assert(pubkey.size() == CPubKey::COMPRESSED_SIZE);
        BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, vout.data());
    } else {
        assert(size() == 32);
        BIP32Hash(cc, nChild, 0, UCharCast(begin()), vout.data());
    }
    memcpy(ccChild.begin(), vout.data()+32, 32);
    keyChild.Set(begin(), begin() + 32, true);
    bool ret = secp256k1_ec_seckey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), vout.data());
    if (!ret) keyChild.ClearKeyData();
    return ret;
}