diff options
Diffstat (limited to 'src/pubkey.cpp')
-rw-r--r-- | src/pubkey.cpp | 53 |
1 files changed, 49 insertions, 4 deletions
diff --git a/src/pubkey.cpp b/src/pubkey.cpp index fc1624af25..51cc826b00 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -5,9 +5,16 @@ #include <pubkey.h> +#include <hash.h> #include <secp256k1.h> +#include <secp256k1_extrakeys.h> #include <secp256k1_recovery.h> #include <secp256k1_schnorrsig.h> +#include <span.h> +#include <uint256.h> + +#include <algorithm> +#include <cassert> namespace { @@ -173,6 +180,12 @@ XOnlyPubKey::XOnlyPubKey(Span<const unsigned char> bytes) std::copy(bytes.begin(), bytes.end(), m_keydata.begin()); } +bool XOnlyPubKey::IsFullyValid() const +{ + secp256k1_xonly_pubkey pubkey; + return secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &pubkey, m_keydata.data()); +} + bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> sigbytes) const { assert(sigbytes.size() == 64); @@ -181,13 +194,45 @@ bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> si return secp256k1_schnorrsig_verify(secp256k1_context_verify, sigbytes.data(), msg.begin(), &pubkey); } -bool XOnlyPubKey::CheckPayToContract(const XOnlyPubKey& base, const uint256& hash, bool parity) const +static const CHashWriter HASHER_TAPTWEAK = TaggedHash("TapTweak"); + +uint256 XOnlyPubKey::ComputeTapTweakHash(const uint256* merkle_root) const +{ + if (merkle_root == nullptr) { + // We have no scripts. The actual tweak does not matter, but follow BIP341 here to + // allow for reproducible tweaking. + return (CHashWriter(HASHER_TAPTWEAK) << m_keydata).GetSHA256(); + } else { + return (CHashWriter(HASHER_TAPTWEAK) << m_keydata << *merkle_root).GetSHA256(); + } +} + +bool XOnlyPubKey::CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool parity) const +{ + secp256k1_xonly_pubkey internal_key; + if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &internal_key, internal.data())) return false; + uint256 tweak = internal.ComputeTapTweakHash(&merkle_root); + return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_verify, m_keydata.begin(), parity, &internal_key, tweak.begin()); +} + +std::optional<std::pair<XOnlyPubKey, bool>> XOnlyPubKey::CreateTapTweak(const uint256* merkle_root) const { secp256k1_xonly_pubkey base_point; - if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &base_point, base.data())) return false; - return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_verify, m_keydata.begin(), parity, &base_point, hash.begin()); + if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &base_point, data())) return std::nullopt; + secp256k1_pubkey out; + uint256 tweak = ComputeTapTweakHash(merkle_root); + if (!secp256k1_xonly_pubkey_tweak_add(secp256k1_context_verify, &out, &base_point, tweak.data())) return std::nullopt; + int parity = -1; + std::pair<XOnlyPubKey, bool> ret; + secp256k1_xonly_pubkey out_xonly; + if (!secp256k1_xonly_pubkey_from_pubkey(secp256k1_context_verify, &out_xonly, &parity, &out)) return std::nullopt; + secp256k1_xonly_pubkey_serialize(secp256k1_context_verify, ret.first.begin(), &out_xonly); + assert(parity == 0 || parity == 1); + ret.second = parity; + return ret; } + bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const { if (!IsValid()) return false; @@ -293,7 +338,7 @@ void CExtPubKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) { bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const { out.nDepth = nDepth + 1; CKeyID id = pubkey.GetID(); - memcpy(&out.vchFingerprint[0], &id, 4); + memcpy(out.vchFingerprint, &id, 4); out.nChild = _nChild; return pubkey.Derive(out.pubkey, out.chaincode, _nChild, chaincode); } |