Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Eunovo committed Jun 3, 2024
1 parent a6c0806 commit 99c4f43
Show file tree
Hide file tree
Showing 19 changed files with 646 additions and 164 deletions.
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ BITCOIN_CORE_H = \
script/signingprovider.h \
script/solver.h \
signet.h \
silentpaymentkey.h \
streams.h \
support/allocators/pool.h \
support/allocators/secure.h \
Expand Down Expand Up @@ -463,6 +464,7 @@ libbitcoin_node_a_SOURCES = \
rpc/txoutproof.cpp \
script/sigcache.cpp \
signet.cpp \
silentpaymentkey.cpp \
timedata.cpp \
torcontrol.cpp \
txdb.cpp \
Expand Down
4 changes: 4 additions & 0 deletions src/kernel/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ class CMainParams : public CChainParams {
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,128);
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
base58Prefixes[SP_PUBLIC_KEY] = {0x22, 0x48, 0x2F, 0xFE}; //0x22482ffe
base58Prefixes[SP_SECRET_KEY] = {0x07, 0xC4, 0x5A, 0xB9, 0xEB}; //0x07c45ab9eb

bech32_hrp = "bc";
silent_payment_hrp = "sp";
Expand Down Expand Up @@ -253,6 +255,8 @@ class CTestNetParams : public CChainParams {
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
base58Prefixes[SP_PUBLIC_KEY] = {0x22, 0x48, 0x2F, 0xFE}; //0x22482ffe
base58Prefixes[SP_SECRET_KEY] = {0x07, 0xC4, 0x5A, 0xB9, 0xEB}; //0x07c45ab9eb

bech32_hrp = "tb";
silent_payment_hrp = "tsp";
Expand Down
28 changes: 0 additions & 28 deletions src/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,34 +244,6 @@ struct CExtKey {
void SetSeed(Span<const std::byte> seed);
};

struct SpKey {
unsigned char version[1];
unsigned char vchFingerprint[4];
int maximumNumberOfLabels;
CKey scanKey;
CKey spendKey;

friend bool operator==(const SpKey& a, const SpKey& b)
{
return memcmp(a.version, b.version, sizeof(version)) == 0 &&
memcmp(a.vchFingerprint, b.vchFingerprint, sizeof(vchFingerprint)) == 0 &&
memcmp(a.maximumNumberOfLabels, b.maximumNumberOfLabels, sizeof(maximumNumberOfLabels)) == 0 &&
a.scanKey == b.scanKey &&
a.spendKey == b.spendKey;
}

SpKey() = default;
SpKey(const SpPubKey& sppub, const CKey& scanKey_in, const CKey& spendKey_in) : maximumNumberOfLabels(sppub.maxinumNumberOfLabels), scanKey(scanKey_in), spendKey(spendKey_in)
{
std::copy(sppub.version, spppub.version + sizeof(spppub.version), version);
std::copy(sppub.vchFingerprint, spppub.vchFingerprint + sizeof(sppub.vchFingerprint), vchFingerprint);
}

void Encode(unsigned char code[BIP32_SPKEY_SIZE]) const;
void Decode(const unsigned char code[BIP32_SPKEY_SIZE]);
SpPubKey Neuter();
}

/** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */
void ECC_Start();

Expand Down
6 changes: 3 additions & 3 deletions src/key_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,9 +354,9 @@ SpPubKey DecodeSpPubKey(const std::string& str)
{
SpPubKey key;
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data, BIP352_SPPUBKEY_SIZE)) {
if (DecodeBase58Check(str, data, BIP352_SPKEY_SIZE)) {
const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::SP_PUBLIC_KEY);
if (data.size() == BIP352_SPPUBKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
if (data.size() == BIP352_SPKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
key.Decode(data.data() + prefix.size());
}
}
Expand All @@ -367,7 +367,7 @@ std::string EncodeSpPubKey(const SpPubKey& key)
{
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SP_PUBLIC_KEY);
size_t size = data.size();
data.resize(size + BIP352_SPPUBKEY_SIZE);
data.resize(size + BIP352_SPKEY_SIZE);
key.Encode(data.data() + size);
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
Expand Down
1 change: 1 addition & 0 deletions src/key_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <chainparams.h>
#include <key.h>
#include <pubkey.h>
#include <silentpaymentkey.h>

#include <string>

Expand Down
43 changes: 0 additions & 43 deletions src/pubkey.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

const unsigned int BIP32_EXTKEY_SIZE = 74;
const unsigned int BIP32_EXTKEY_WITH_VERSION_SIZE = 78;
const unsigned int BIP352_SPKEY_SIZE = 74;

/** A reference to a CKey: the Hash160 of its serialized public key */
class CKeyID : public uint160
Expand Down Expand Up @@ -377,46 +376,4 @@ struct CExtPubKey {
[[nodiscard]] bool Derive(CExtPubKey& out, unsigned int nChild) const;
};

struct SpPubKey {
unsigned char version[1];
unsigned char vchFingerprint[4];
int maximumNumberOfLabels;
CPubKey scanKey;
CPubKey spendKey;

SpPubKey(CPubKey scan_key, CPubKey spend_key) : scanKey(scan_key), spendKey(spend_key)
{
memset(version, 0, sizeof(version));
memset(vchFingerprint, 0, sizeof(vchFingerprint));
maximumNumberOfLabels = 0;
}

friend bool operator==(const SpPubKey $a, const SpPubKey $b)
{
return memcmp(a.version, b.version, sizeof(version)) == 0 &&
memcmp(a.vchFingerprint, b.vchFingerprint, sizeof(vchFingerprint)) == 0 &&
memcmp(a.maximumNumberOfLabels, b.maximumNumberOfLabels, sizeof(maximumNumberOfLabels)) == 0 &&
a.scanKey == b.scanKey &&
a.spendKey == b.spendKey;
}

friend bool operator!=(const SpPubKey &a, const SpPubKey &b)
{
return !(a == b);
}

friend bool operator<(const SpPubKey &a, const SpPubKey &b)
{
if (a.scanKey < b.scanKey) {
return true;
} else if (a.scanKey > b.scanKey) {
return false;
}
return a.spendKey < b.spendKey;
}

void Encode(unsigned char code[BIP352_SPKEY_SIZE]) const;
void Decode(const unsigned char code[BIP352_SPKEY_SIZE]);
}

#endif // BITCOIN_PUBKEY_H
141 changes: 121 additions & 20 deletions src/script/descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <script/script.h>
#include <script/signingprovider.h>
#include <script/solver.h>
#include <silentpaymentkey.h>
#include <uint256.h>

#include <common/args.h>
Expand Down Expand Up @@ -560,26 +561,18 @@ class BIP32PubkeyProvider final : public PubkeyProvider
class SilentPubkeyProvider final : public PubkeyProvider
{
SpPubKey m_sppk;
// KeyPath m_path;

bool GetSpKey(const SigningProvider& arg, SpKey& ret) const
{
CKey scanKey;
CKey spendKey;
if (!arg.GetKey(m_sppk.scanKey.GetID(), scanKey)) return false;
if (!arg.GetKey(m_sppk.spendKey.GetID(), spendKey)) return false;
ret.scanKey = scanKey;
ret.spendKey = spendKey;
ret.maximumNumberOfLabels = m_sppk.maximumNumberOfLabels;
std::copy(m_sppk.version, m_sppk.version + sizeof(m_sppk.version), ret.version);
std::copy(m_sppk.vchFingerprint, m_sppk.vchFingerprint + sizeof(ret.vchFingerprint), ret.vchFingerprint);
return true;
}

public:
SilentPubkeyProvider(uint32_t exp_index, const SpPubKey& sppk) : PubkeyProvider(exp_index), m_sppk(sppk), m_path(path) {}
SilentPubkeyProvider(uint32_t exp_index, const SpPubKey& sppk) : PubkeyProvider(exp_index), m_sppk(sppk) {}
bool IsRange() const override { return false; }
size_t GetSize() const override { return BIP352_SPKEY_SIZE; }
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
{
return false;
}
bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
{
return false;
}
std::string ToString(StringType type, bool normalized) const
{
std::string ret = EncodeSpPubKey(m_sppk);
Expand All @@ -594,6 +587,54 @@ class SilentPubkeyProvider final : public PubkeyProvider
SpKey key;
if (!GetSpKey(arg, key)) return false;
out = EncodeSpKey(key);
return true;
}
bool ToNormalizedString(const SigningProvider& arg, std::string& out, const DescriptorCache* cache) const override
{
out = ToString(StringType::PUBLIC, /*normalized=*/true);
return true;
}
std::optional<CPubKey> GetRootPubKey() const override
{
return std::nullopt;
}
std::optional<CExtPubKey> GetRootExtPubKey() const override
{
return std::nullopt;
}
bool GetSpKey(const SigningProvider& arg, SpKey& ret) const
{
CKey spendKey;
if (!arg.GetKey(m_sppk.spendKey.GetID(), spendKey)) return false;
ret.scanKey = m_sppk.scanKey;
ret.spendKey = spendKey;
ret.maximumNumberOfLabels = m_sppk.maximumNumberOfLabels;
std::copy(m_sppk.version, m_sppk.version + sizeof(m_sppk.version), ret.version);
std::copy(m_sppk.vchFingerprint, m_sppk.vchFingerprint + sizeof(ret.vchFingerprint), ret.vchFingerprint);
return true;
}
bool GetSpPubKey(SpPubKey& ret) const
{
ret.maximumNumberOfLabels = m_sppk.maximumNumberOfLabels;
std::copy(m_sppk.version, m_sppk.version + sizeof(m_sppk.version), ret.version);
std::copy(m_sppk.vchFingerprint, m_sppk.vchFingerprint + sizeof(ret.vchFingerprint), ret.vchFingerprint);
ret.scanKey = m_sppk.scanKey;
ret.spendKey = m_sppk.spendKey;
return true;
}
void GetSpendPubKey(CPubKey& pubkey, KeyOriginInfo& info) const
{
info.path.clear();
CKeyID keyid = m_sppk.spendKey.GetID();
std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), info.fingerprint);
pubkey = m_sppk.spendKey;
}
void GetScanPubKey(CPubKey& pubkey, KeyOriginInfo& info) const
{
info.path.clear();
CKeyID keyid = m_sppk.scanKey.GetPubKey().GetID();
std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), info.fingerprint);
pubkey = m_sppk.scanKey.GetPubKey();
}
};

Expand Down Expand Up @@ -736,6 +777,18 @@ class DescriptorImpl : public Descriptor
// Construct temporary data in `entries`, `subscripts`, and `subprovider` to avoid producing output in case of failure.
for (const auto& p : m_pubkey_args) {
entries.emplace_back();

try {
auto sppubkeyprovider = dynamic_cast<SilentPubkeyProvider&>(*p);
SpPubKey key;
sppubkeyprovider.GetSpPubKey(key);
out.sppubkeys.emplace(key.GetID(), key);
sppubkeyprovider.GetSpendPubKey(entries.back().first, entries.back().second);
entries.emplace_back();
sppubkeyprovider.GetScanPubKey(entries.back().first, entries.back().second);
continue;
} catch (const std::bad_cast&) {}

if (!p->GetPubKey(pos, arg, entries.back().first, entries.back().second, read_cache, write_cache)) return false;
}
std::vector<CScript> subscripts;
Expand Down Expand Up @@ -773,6 +826,16 @@ class DescriptorImpl : public Descriptor
void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const final
{
for (const auto& p : m_pubkey_args) {
try {
auto sppubkeyprovider = dynamic_cast<SilentPubkeyProvider&>(*p);
SpKey key;
sppubkeyprovider.GetSpKey(provider, key);
out.spkeys.emplace(key.Neuter().GetID(), key);
out.keys.emplace(key.spendKey.GetPubKey().GetID(), key.spendKey);
out.keys.emplace(key.scanKey.GetPubKey().GetID(), key.scanKey);
continue;
} catch (const std::bad_cast&) {}

CKey key;
if (!p->GetPrivKey(pos, provider, key)) continue;
out.keys.emplace(key.GetPubKey().GetID(), key);
Expand Down Expand Up @@ -1348,7 +1411,6 @@ class SpDescriptor final : public DescriptorImpl
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript>, FlatSigningProvider&) const override { return std::vector<CScript>(); }
public:
SpDescriptor(std::unique_ptr<PubkeyProvider> spkey) : DescriptorImpl(Vector(std::move(spkey)), "sp") {};
SpDescriptor(std::unique_ptr<PubkeyProvider> scankey, std::unique_ptr<PubkeyProvider> spendkey) : DescriptorImpl(Vector(std::move(scankey), std::move(spendkey)), "sp") {};

std::optional<OutputType> GetOutputType() const override { return OutputType::SILENT_PAYMENT; }
bool IsSingleType() const final { return true; }
Expand Down Expand Up @@ -1452,8 +1514,31 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S
}
}
}

SpKey spkey = DecodeSpKey(str);
SpPubKey sppubkey = DecodeSpPubKey(str);
CExtKey extkey = DecodeExtKey(str);
CExtPubKey extpubkey = DecodeExtPubKey(str);

if (ctx == ParseScriptContext::SP) {
if (extkey.key.IsValid() || extpubkey.pubkey.IsValid()) {
error = "extended keys are not allowed";
return nullptr;
}
if (spkey.scanKey.IsValid() && spkey.spendKey.IsValid()) {
out.keys.emplace(spkey.scanKey.GetPubKey().GetID(), spkey.scanKey);
out.keys.emplace(spkey.spendKey.GetPubKey().GetID(), spkey.spendKey);
return std::make_unique<SilentPubkeyProvider>(key_exp_index, spkey.Neuter());
}
if (sppubkey.scanKey.IsValid() && sppubkey.spendKey.IsValid()) {
out.keys.emplace(sppubkey.scanKey.GetPubKey().GetID(), sppubkey.scanKey);
return std::make_unique<SilentPubkeyProvider>(key_exp_index, sppubkey);
}

error = "provided key is not a valid silent payment key";
return nullptr;
}

if (!extkey.key.IsValid() && !extpubkey.pubkey.IsValid()) {
error = strprintf("key '%s' is not valid", str);
return nullptr;
Expand Down Expand Up @@ -1667,13 +1752,29 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
if (!Const(",", expr)) {
return std::make_unique<SpDescriptor>(std::move(firstKey));
}
auto spendKey = ParsePubkey(key_exp_index, expr, ctx, out, error);
auto spendKey = ParsePubkey(key_exp_index, expr, ParseScriptContext::SP, out, error);
if (!spendKey) {
error = strprintf("sp(): %s", error);
return nullptr;
}
auto scanPubKey = firstKey->GetRootPubKey();
auto spendPubKey = spendKey->GetRootPubKey();
if (!scanPubKey.has_value()) {
error = "sp(): could not get scan pubkey";
return nullptr;
}
if (!spendPubKey.has_value()) {
error = "sp(): could not get spend pubkey";
return nullptr;
}
auto it = out.keys.find(scanPubKey->GetID());
if (it == out.keys.end()) {
error = "sp(): requires the scan priv key";
return nullptr;
}
auto sppk = std::make_unique<SilentPubkeyProvider>(key_exp_index, SpPubKey(it->second, *spendPubKey));
++key_exp_index;
return std::make_unique<SpDescriptor>(std::move(firstKey), std::move(spendKey));
return std::make_unique<SpDescriptor>(std::move(sppk));
} else if (Func("sp", expr)) {
error = "Can only have sp() at top level";
return nullptr;
Expand Down
3 changes: 3 additions & 0 deletions src/script/signingprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <pubkey.h>
#include <script/keyorigin.h>
#include <script/script.h>
#include <silentpaymentkey.h>
#include <sync.h>

struct ShortestVectorFirstComparator
Expand Down Expand Up @@ -211,6 +212,8 @@ struct FlatSigningProvider final : public SigningProvider
std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> origins;
std::map<CKeyID, CKey> keys;
std::map<XOnlyPubKey, TaprootBuilder> tr_trees; /** Map from output key to Taproot tree (which can then make the TaprootSpendData */
std::map<CKeyID, SpKey> spkeys; /** Silent Payment Keys */
std::map<CKeyID, SpPubKey> sppubkeys; /** Silent Payment PubKeys */

bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
Expand Down
Loading

0 comments on commit 99c4f43

Please sign in to comment.