mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-11 21:20:39 +02:00
key: add DeriveExtKey() helper
Co-authored-by: w0xlt <94266259+w0xlt@users.noreply.github.com>
This commit is contained in:
14
src/key.cpp
14
src/key.cpp
@@ -16,6 +16,8 @@
|
||||
#include <secp256k1_recovery.h>
|
||||
#include <secp256k1_schnorrsig.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
static secp256k1_context* secp256k1_context_sign = nullptr;
|
||||
|
||||
/** These functions are taken from the libsecp256k1 distribution and are very ugly. */
|
||||
@@ -364,6 +366,18 @@ bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const {
|
||||
return key.Derive(out.key, out.chaincode, _nChild, chaincode);
|
||||
}
|
||||
|
||||
std::optional<std::pair<CExtKey, KeyOriginInfo>> DeriveExtKey(const CExtKey& ext_key, const std::vector<uint32_t>& path)
|
||||
{
|
||||
CExtKey descendant = ext_key;
|
||||
KeyOriginInfo origin;
|
||||
origin.fingerprint = ext_key.id_key_fingerprint();
|
||||
origin.path = path;
|
||||
for (uint32_t i : path) {
|
||||
if (!descendant.Derive(descendant, i)) return std::nullopt;
|
||||
}
|
||||
return std::make_pair(descendant, origin);
|
||||
}
|
||||
|
||||
void CExtKey::SetSeed(std::span<const std::byte> seed)
|
||||
{
|
||||
Assert(16 <= seed.size() && seed.size() <= 64);
|
||||
|
||||
@@ -8,11 +8,14 @@
|
||||
#define BITCOIN_KEY_H
|
||||
|
||||
#include <pubkey.h>
|
||||
#include <script/keyorigin.h>
|
||||
#include <serialize.h>
|
||||
#include <support/allocators/secure.h>
|
||||
#include <uint256.h>
|
||||
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
struct secp256k1_context_struct;
|
||||
@@ -257,6 +260,12 @@ struct CExtKey {
|
||||
void SetSeed(std::span<const std::byte> seed);
|
||||
};
|
||||
|
||||
//! Get extended key and origin info for a given path
|
||||
//! @param[in] ext_key The extended private key to derive from
|
||||
//! @param[in] path The BIP 32 path
|
||||
//! @return the resulting extended private key and origin info
|
||||
std::optional<std::pair<CExtKey, KeyOriginInfo>> DeriveExtKey(const CExtKey& ext_key, const std::vector<uint32_t>& path);
|
||||
|
||||
/** KeyPair
|
||||
*
|
||||
* Wraps a `secp256k1_keypair` type, an opaque data structure for holding a secret and public key.
|
||||
|
||||
@@ -184,6 +184,34 @@ BOOST_AUTO_TEST_CASE(bip32_test5) {
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(bip32_derive_ext_key)
|
||||
{
|
||||
const CExtKey master{DecodeExtKey(test1.vDerive[0].prv)};
|
||||
const std::vector<uint32_t> path{test1.vDerive[0].nChild, test1.vDerive[1].nChild};
|
||||
const auto derived{DeriveExtKey(master, path)};
|
||||
BOOST_REQUIRE(derived);
|
||||
BOOST_CHECK(EncodeExtKey(derived->first) == test1.vDerive[2].prv);
|
||||
|
||||
KeyOriginInfo expected_origin;
|
||||
expected_origin.fingerprint = master.id_key_fingerprint();
|
||||
expected_origin.path = path;
|
||||
BOOST_CHECK(derived->second == expected_origin);
|
||||
|
||||
const auto root{DeriveExtKey(master, {})};
|
||||
BOOST_REQUIRE(root);
|
||||
BOOST_CHECK(root->first == master);
|
||||
expected_origin.path.clear();
|
||||
BOOST_CHECK(root->second == expected_origin);
|
||||
|
||||
CExtKey max_depth{master};
|
||||
for (auto i{0}; i++ < 255;) {
|
||||
CExtKey next_key;
|
||||
BOOST_REQUIRE(max_depth.Derive(next_key, 0));
|
||||
max_depth = next_key;
|
||||
}
|
||||
BOOST_CHECK(!DeriveExtKey(max_depth, {0}));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(bip32_max_depth) {
|
||||
CExtKey key_parent{DecodeExtKey(test1.vDerive[0].prv)}, key_child;
|
||||
CExtPubKey pubkey_parent{DecodeExtPubKey(test1.vDerive[0].pub)}, pubkey_child;
|
||||
|
||||
Reference in New Issue
Block a user