/* * This file is part of the Flowee project * Copyright (C) 2009-2010 Satoshi Nakamoto * Copyright (C) 2009-2015 The Bitcoin Core developers * Copyright (C) 2019-2023 Tom Zander * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef FLOWEE_PUBLICKEY_H #define FLOWEE_PUBLICKEY_H #include "PublicKeyUtils.h" #include "serialize.h" #include "uint256.h" #include "streaming/ConstBuffer.h" #include /** * secp256k1: * const unsigned int PRIVATE_KEY_SIZE = 279; * const unsigned int PUBLIC_KEY_SIZE = 65; * const unsigned int SIGNATURE_SIZE = 72; * * see www.keylength.com * script supports up to 75 for single byte push */ /** A reference to a Key: the Hash160 of its serialized public key */ class KeyId : public uint160 { public: KeyId() : uint160() {} KeyId(const uint160& in) : uint160(in) {} explicit KeyId(const char *d) : uint160(d) {} }; typedef uint256 ChainCode; /** An encapsulated public key. */ class PublicKey { public: /** * secp256k1: */ static constexpr unsigned int PUBLIC_KEY_SIZE = 65; static constexpr unsigned int COMPRESSED_PUBLIC_KEY_SIZE = 33; static constexpr unsigned int SIGNATURE_SIZE = 72; static constexpr unsigned int COMPACT_SIGNATURE_SIZE = 65; /** * see www.keylength.com * script supports up to 75 for single byte push */ static_assert(PUBLIC_KEY_SIZE >= COMPRESSED_PUBLIC_KEY_SIZE, "COMPRESSED_PUBLIC_KEY_SIZE is larger than PUBLIC_KEY_SIZE"); //! Construct an invalid public key. PublicKey() { invalidate(); } //! Initialize a public key using begin/end iterators to byte data. template void setData(const T pbegin, const T pend) { int len = pend == pbegin ? 0 : PublicKeyUtils::keyLength(pbegin[0]); if (len && len == (pend - pbegin)) memcpy(vch, (unsigned char*)&pbegin[0], len); else invalidate(); } //! Construct a public key using begin/end iterators to byte data. template PublicKey(const T pbegin, const T pend) { setData(pbegin, pend); } //! Construct a public key from a byte vector. PublicKey(const std::vector& vch) { setData(vch.begin(), vch.end()); } PublicKey(const std::vector &vch) { setData(vch.begin(), vch.end()); } PublicKey(const Streaming::ConstBuffer &buf) { setData(buf.begin(), buf.end()); } //! Simple read-only vector-like interface to the pubkey data. unsigned int size() const { return PublicKeyUtils::keyLength(vch[0]); } const unsigned char* begin() const { return vch; } const unsigned char* end() const { return vch + size(); } const unsigned char& operator[](unsigned int pos) const { return vch[pos]; } //! Comparator implementation. friend bool operator==(const PublicKey& a, const PublicKey& b) { return a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) == 0; } friend bool operator!=(const PublicKey& a, const PublicKey& b) { return !(a == b); } friend bool operator<(const PublicKey& a, const PublicKey& b) { return a.vch[0] < b.vch[0] || (a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) < 0); } //! Implement serialization, as if this was a byte vector. unsigned int serializedSize(int nType, int nVersion) const { return size() + 1; } template void Serialize(Stream& s, int nType, int nVersion) const { unsigned int len = size(); ::WriteCompactSize(s, len); s.write((char*)vch, len); } template void Unserialize(Stream& s, int nType, int nVersion) { unsigned int len = ::ReadCompactSizeAsUnsignedInt(s); if (len <= 65) { s.read((char*)vch, len); } else { // invalid pubkey, skip available data char dummy; while (len--) s.read(&dummy, 1); invalidate(); } } //! Get the KeyID of this public key (hash of its serialization) KeyId getKeyId() const; //! Get the 256-bit hash of this public key. uint256 createHash() const; /* * Check syntactic correctness. * * Note that this is consensus critical as CheckSig() calls it! */ bool isValid() const; //! fully validate whether this is a valid public key (more expensive than IsValid()) bool isFullyValid() const; //! Check whether this is a compressed public key. bool isCompressed() const; /** * Verify a DER signature (~72 bytes). * If this public key is not fully valid, the return value will be false. */ bool verifyECDSA(const uint256& hash, const std::vector& vchSig) const; bool verifyCompact(const uint256& hash, const std::vector& vchSig) const; /** * Verify a Schnorr signature (=64 bytes). * If this public key is not fully valid, the return value will be false. */ bool verifySchnorr(const uint256 &hash, const std::vector &vchSig) const; /** * Check whether a signature is normalized (lower-S). */ static bool checkLowS(const std::vector& vchSig); //! Recover a public key from a compact signature. bool recoverCompact(const uint256& hash, const std::vector& vchSig); //! Turn this public key into an uncompressed public key. bool decompress(); //! Derive BIP32 child pubkey. bool derive(PublicKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; private: /** * Just store the serialized data. * Its length can very cheaply be computed from the first byte. */ unsigned char vch[65]; //! Set this key data to be invalid inline void invalidate() { vch[0] = 0xFF; } }; /** Users of this module must hold an ECCVerifyHandle. The constructor and * destructor of these are not allowed to run in parallel, though. */ class ECCVerifyHandle { static int refcount; public: ECCVerifyHandle(); ~ECCVerifyHandle(); }; #endif