mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-03 01:33:20 +02:00
Merge bitcoin/bitcoin#30051: crypto, refactor: add new KeyPair class
ec973dd197refactor: remove un-tested early returns (josibake)72a5822d43tests: add tests for KeyPair (josibake)cebb08b121refactor: move SignSchnorr to KeyPair (josibake)c39fd39ba8crypto: add KeyPair wrapper class (josibake)5d507a0091tests: add key tweak smoke test (josibake)f14900b6e4bench: add benchmark for signing with a taptweak (josibake) Pull request description: Broken out from #28201 --- The wallet returns an untweaked internal key for taproot outputs. If the output commits to a tree of scripts, this key needs to be tweaked with the merkle root. Even if the output does not commit to a tree of scripts, BIP341/342 recommend commiting to a hash of the public key. Previously, this logic for applying the taptweak was implemented in the `CKey::SignSchnorr` method. This PR moves introduces a KeyPair class which wraps a `secp256k1_keypair` type and refactors SignSchnorr to use this new KeyPair. The KeyPair class is created with an optional merkle_root argument and the logic from BIP341 is applied depending on the state of the merkle_root argument. The motivation for this refactor is to be able to use the tap tweak logic outside of signing, e.g. in silent payments when retrieving the private key (see #28201). Outside of silent payments, since we almost always convert a `CKey` to a `secp256k1_keypair` when doing anything with taproot keys, it seems generally useful to have a way to model this type in our code base. ACKs for top commit: paplorinc: ACKec973dd197- will happily reack if you decide to apply @ismaelsadeeq's suggestions ismaelsadeeq: Code review ACKec973dd197itornaza: trACKec973dd197theStack: Code-review ACKec973dd197Tree-SHA512: 34947e3eac39bd959807fa21b6045191fc80113bd650f6f08606e4bcd89aa17d6afd48dd034f6741ac4ff304b104fa8c1c1898e297467edcf262d5f97425da7b
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <key_io.h>
|
||||
#include <span.h>
|
||||
#include <streams.h>
|
||||
#include <secp256k1_extrakeys.h>
|
||||
#include <test/util/random.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <uint256.h>
|
||||
@@ -299,6 +300,13 @@ BOOST_AUTO_TEST_CASE(bip340_test_vectors)
|
||||
// Verify those signatures for good measure.
|
||||
BOOST_CHECK(pubkey.VerifySchnorr(msg256, sig64));
|
||||
|
||||
// Repeat the same check, but use the KeyPair directly without any merkle tweak
|
||||
KeyPair keypair = key.ComputeKeyPair(/*merkle_root=*/nullptr);
|
||||
bool kp_ok = keypair.SignSchnorr(msg256, sig64, aux256);
|
||||
BOOST_CHECK(kp_ok);
|
||||
BOOST_CHECK(pubkey.VerifySchnorr(msg256, sig64));
|
||||
BOOST_CHECK(std::vector<unsigned char>(sig64, sig64 + 64) == sig);
|
||||
|
||||
// Do 10 iterations where we sign with a random Merkle root to tweak,
|
||||
// and compare against the resulting tweaked keys, with random aux.
|
||||
// In iteration i=0 we tweak with empty Merkle tree.
|
||||
@@ -312,6 +320,12 @@ BOOST_AUTO_TEST_CASE(bip340_test_vectors)
|
||||
bool ok = key.SignSchnorr(msg256, sig64, &merkle_root, aux256);
|
||||
BOOST_CHECK(ok);
|
||||
BOOST_CHECK(tweaked_key.VerifySchnorr(msg256, sig64));
|
||||
|
||||
// Repeat the same check, but use the KeyPair class directly
|
||||
KeyPair keypair = key.ComputeKeyPair(&merkle_root);
|
||||
bool kp_ok = keypair.SignSchnorr(msg256, sig64, aux256);
|
||||
BOOST_CHECK(kp_ok);
|
||||
BOOST_CHECK(tweaked_key.VerifySchnorr(msg256, sig64));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -345,4 +359,31 @@ BOOST_AUTO_TEST_CASE(bip341_test_h)
|
||||
BOOST_CHECK(XOnlyPubKey::NUMS_H == H);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(key_schnorr_tweak_smoke_test)
|
||||
{
|
||||
// Sanity check to ensure we get the same tweak using CPubKey vs secp256k1 functions
|
||||
secp256k1_context* secp256k1_context_sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
uint256 merkle_root = InsecureRand256();
|
||||
|
||||
// secp256k1 functions
|
||||
secp256k1_keypair keypair;
|
||||
BOOST_CHECK(secp256k1_keypair_create(secp256k1_context_sign, &keypair, UCharCast(key.begin())));
|
||||
secp256k1_xonly_pubkey xonly_pubkey;
|
||||
BOOST_CHECK(secp256k1_keypair_xonly_pub(secp256k1_context_sign, &xonly_pubkey, nullptr, &keypair));
|
||||
unsigned char xonly_bytes[32];
|
||||
BOOST_CHECK(secp256k1_xonly_pubkey_serialize(secp256k1_context_sign, xonly_bytes, &xonly_pubkey));
|
||||
uint256 tweak_old = XOnlyPubKey(xonly_bytes).ComputeTapTweakHash(&merkle_root);
|
||||
|
||||
// CPubKey
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
uint256 tweak_new = XOnlyPubKey(pubkey).ComputeTapTweakHash(&merkle_root);
|
||||
|
||||
BOOST_CHECK_EQUAL(tweak_old, tweak_new);
|
||||
|
||||
secp256k1_context_destroy(secp256k1_context_sign);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
Reference in New Issue
Block a user