// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <stdexcept>
#include <vector>
-/**
- * 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
- */
+const unsigned int BIP32_EXTKEY_SIZE = 74;
/** A reference to a CKey: the Hash160 of its serialized public key */
class CKeyID : public uint160
CKeyID(const uint160& in) : uint160(in) {}
};
+typedef uint256 ChainCode;
+
/** An encapsulated public key. */
class CPubKey
{
+public:
+ /**
+ * secp256k1:
+ */
+ static const unsigned int PUBLIC_KEY_SIZE = 65;
+ static const unsigned int COMPRESSED_PUBLIC_KEY_SIZE = 33;
+ static const unsigned int SIGNATURE_SIZE = 72;
+ static const 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");
+
private:
/**
* Just store the serialized data.
* Its length can very cheaply be computed from the first byte.
*/
- unsigned char vch[65];
+ unsigned char vch[PUBLIC_KEY_SIZE];
//! Compute the length of a pubkey with a given first byte.
unsigned int static GetLen(unsigned char chHeader)
{
if (chHeader == 2 || chHeader == 3)
- return 33;
+ return COMPRESSED_PUBLIC_KEY_SIZE;
if (chHeader == 4 || chHeader == 6 || chHeader == 7)
- return 65;
+ return PUBLIC_KEY_SIZE;
return 0;
}
}
//! Implement serialization, as if this was a byte vector.
- unsigned int GetSerializeSize(int nType, int nVersion) const
- {
- return size() + 1;
- }
template <typename Stream>
- void Serialize(Stream& s, int nType, int nVersion) const
+ void Serialize(Stream& s) const
{
unsigned int len = size();
::WriteCompactSize(s, len);
s.write((char*)vch, len);
}
template <typename Stream>
- void Unserialize(Stream& s, int nType, int nVersion)
+ void Unserialize(Stream& s)
{
unsigned int len = ::ReadCompactSize(s);
- if (len <= 65) {
+ if (len <= PUBLIC_KEY_SIZE) {
s.read((char*)vch, len);
} else {
// invalid pubkey, skip available data
//! Check whether this is a compressed public key.
bool IsCompressed() const
{
- return size() == 33;
+ return size() == COMPRESSED_PUBLIC_KEY_SIZE;
}
/**
*/
bool Verify(const uint256& hash, const std::vector<unsigned char>& vchSig) const;
+ /**
+ * Check whether a signature is normalized (lower-S).
+ */
+ static bool CheckLowS(const std::vector<unsigned char>& vchSig);
+
//! Recover a public key from a compact signature.
bool RecoverCompact(const uint256& hash, const std::vector<unsigned char>& vchSig);
bool Decompress();
//! Derive BIP32 child pubkey.
- bool Derive(CPubKey& pubkeyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const;
+ bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;
};
struct CExtPubKey {
unsigned char nDepth;
unsigned char vchFingerprint[4];
unsigned int nChild;
- unsigned char vchChainCode[32];
+ ChainCode chaincode;
CPubKey pubkey;
- friend bool operator==(const CExtPubKey& a, const CExtPubKey& b)
+ friend bool operator==(const CExtPubKey &a, const CExtPubKey &b)
{
return a.nDepth == b.nDepth && memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], 4) == 0 && a.nChild == b.nChild &&
- memcmp(&a.vchChainCode[0], &b.vchChainCode[0], 32) == 0 && a.pubkey == b.pubkey;
+ a.chaincode == b.chaincode && a.pubkey == b.pubkey;
}
- void Encode(unsigned char code[74]) const;
- void Decode(const unsigned char code[74]);
+ void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const;
+ void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);
bool Derive(CExtPubKey& out, unsigned int nChild) const;
+
+ void Serialize(CSizeComputer& s) const
+ {
+ // Optimized implementation for ::GetSerializeSize that avoids copying.
+ s.seek(BIP32_EXTKEY_SIZE + 1); // add one byte for the size (compact int)
+ }
+ template <typename Stream>
+ void Serialize(Stream& s) const
+ {
+ unsigned int len = BIP32_EXTKEY_SIZE;
+ ::WriteCompactSize(s, len);
+ unsigned char code[BIP32_EXTKEY_SIZE];
+ Encode(code);
+ s.write((const char *)&code[0], len);
+ }
+ template <typename Stream>
+ void Unserialize(Stream& s)
+ {
+ unsigned int len = ::ReadCompactSize(s);
+ unsigned char code[BIP32_EXTKEY_SIZE];
+ if (len != BIP32_EXTKEY_SIZE)
+ throw std::runtime_error("Invalid extended key size\n");
+ s.read((char *)&code[0], len);
+ Decode(code);
+ }
+};
+
+/** 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 // BITCOIN_PUBKEY_H