diff --git a/src/key.h b/src/key.h index 6ed6fd0fc3da7..d2ac120a0b062 100644 --- a/src/key.h +++ b/src/key.h @@ -204,6 +204,7 @@ class CKey ECDHSecret ComputeBIP324ECDHSecret(const EllSwiftPubKey& their_ellswift, const EllSwiftPubKey& our_ellswift, bool initiating) const; + /** Compute a KeyPair * * Wraps a `secp256k1_keypair` type. @@ -220,6 +221,31 @@ class CKey * Merkle root of the script tree). */ KeyPair ComputeKeyPair(const uint256* merkle_root) const; + + /** Straight-forward serialization of key bytes (and compressed flag). + * Use GetPrivKey() for OpenSSL compatible DER encoding. + */ + template + void Serialize(Stream& s) const + { + if (!IsValid()) { + throw std::ios_base::failure("invalid key"); + } + s << fCompressed; + ::Serialize(s, Span{*this}); + } + + template + void Unserialize(Stream& s) + { + s >> fCompressed; + MakeKeyData(); + s >> Span{*keydata}; + if (!Check(keydata->data())) { + ClearKeyData(); + throw std::ios_base::failure("invalid key"); + } + } }; CKey GenerateRandomKey(bool compressed = true) noexcept; diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 90e04bed8751d..b6670218383f0 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -390,4 +390,27 @@ BOOST_AUTO_TEST_CASE(key_schnorr_tweak_smoke_test) secp256k1_context_destroy(secp256k1_context_sign); } +BOOST_AUTO_TEST_CASE(key_serialization) +{ + { + DataStream s{}; + CKey key; + BOOST_CHECK_EXCEPTION(s << key, std::ios_base::failure, + HasReason{"invalid key"}); + + s << MakeByteSpan(std::vector(33, std::byte(0))); + BOOST_CHECK_EXCEPTION(s >> key, std::ios_base::failure, + HasReason{"invalid key"}); + } + + for (bool compressed : {true, false}) { + CKey key{GenerateRandomKey(/*compressed=*/compressed)}; + DataStream s{}; + s << key; + CKey key_copy; + s >> key_copy; + BOOST_CHECK(key == key_copy); + } +} + BOOST_AUTO_TEST_SUITE_END()