Bitcoin中公私密钥定义与操作测试示例

Bitcoin中公私密钥定义与操作示例

Bicoint(0.16.0)私钥定义:

/**
 * secure_allocator is defined in allocators.h
 * CPrivKey is a serialized private key, with all parameters included
 * (PRIVATE_KEY_SIZE bytes)
 */
//typedef std::vector > CPrivKey;
// 为测试方便,将容器存储分配修改为系统默认方式
typedef std::vector<unsigned char> CPrivKey;

/** An encapsulated private key. */
class CKey
{
public:
    /**
     * secp256k1:
     */
    static const unsigned int PRIVATE_KEY_SIZE            = 279;// 私钥长度
    static const unsigned int COMPRESSED_PRIVATE_KEY_SIZE = 214;// 压缩私钥长度
    /**
     * see www.keylength.com
     * script supports up to 75 for single byte push
     */
    static_assert(
        PRIVATE_KEY_SIZE >= COMPRESSED_PRIVATE_KEY_SIZE,
        "COMPRESSED_PRIVATE_KEY_SIZE is larger than PRIVATE_KEY_SIZE");

private:
    //! Whether this private key is valid. We check for correctness when modifying the key
    //! data, so fValid should always correspond to the actual state.
    bool fValid;//私钥有效标识

    //! Whether the public key corresponding to this private key is (to be) compressed.
    bool fCompressed;//私钥压缩标识

    //! The actual byte data
    //std::vector > keydata;
    std::vector<unsigned char> keydata;//私钥数据

    //! Check whether the 32-byte array pointed to by vch is valid keydata.
    bool static Check(const unsigned char* vch);//检测vch中的数据是否为有效私钥

public:
    //! Construct an invalid private key.
    // 构造一个无效的私钥
    CKey() : fValid(false), fCompressed(false)
    {
        // Important: vch must be 32 bytes in length to not break serialization
        keydata.resize(32);
    }

    friend bool operator==(const CKey& a, const CKey& b)
    {
        return a.fCompressed == b.fCompressed &&
            a.size() == b.size() &&
            memcmp(a.keydata.data(), b.keydata.data(), a.size()) == 0;
    }

    //! Initialize using begin and end iterators to byte data.
    // 使用迭代器初始化私钥数据
    template <typename T>
    void Set(const T pbegin, const T pend, bool fCompressedIn)
    {
        if (size_t(pend - pbegin) != keydata.size()) {
            fValid = false;
        } else if (Check(&pbegin[0])) {
            memcpy(keydata.data(), (unsigned char*)&pbegin[0], keydata.size());
            fValid = true;
            fCompressed = fCompressedIn;
        } else {
            fValid = false;
        }
    }

    //! Simple read-only vector-like interface.
    unsigned int size() const { return (fValid ? keydata.size() : 0); }
    const unsigned char* begin() const { return keydata.data(); }
    const unsigned char* end() const { return keydata.data() + size(); }

    //! Check whether this private key is valid.
    bool IsValid() const { return fValid; }

    //! Check whether the public key corresponding to this private key is (to be) compressed.
    bool IsCompressed() const { return fCompressed; }

    //! Generate a new private key using a cryptographic PRNG.
    // 生成一个随机私钥
    void MakeNewKey(bool fCompressed);

    /**
     * Convert the private key to a CPrivKey (serialized OpenSSL private key data).
     * This is expensive.
     */
    CPrivKey GetPrivKey() const;

    /**
     * Compute the public key from a private key.
     * This is expensive.
     */
     // 获取公钥
    CPubKey GetPubKey() const;

    /**
     * Create a DER-serialized signature.
     * The test_case parameter tweaks the deterministic nonce.
     */
     // 生成一个DER签名
    bool Sign(const uint256& hash, std::vector<unsigned char>& vchSig, uint32_t test_case = 0) const;

    /**
     * Create a compact signature (65 bytes), which allows reconstructing the used public key.
     * The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
     * The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
     *                  0x1D = second key with even y, 0x1E = second key with odd y,
     *                  add 0x04 for compressed keys.
     */
     // 生成一个协议签名,可用来重构建公钥
    bool SignCompact(const uint256& hash, std::vector<unsigned char>& vchSig) const;

    //! Derive BIP32 child key.
    // 派生BIP32子私钥
    bool Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;

    /**
     * Verify thoroughly whether a private key and a public key match.
     * This is done using a different mechanism than just regenerating it.
     */
     // 验证公钥和私钥是否匹配
    bool VerifyPubKey(const CPubKey& vchPubKey) const;

    //! Load private key and check that public key matches.
    // 从CPrivKey数据中导入私钥
    bool Load(const CPrivKey& privkey, const CPubKey& vchPubKey, bool fSkipCheck);
};

Bicoint(0.16.0)公钥定义:

const unsigned int BIP32_EXTKEY_SIZE = 74;

/** A reference to a CKey: the Hash160 of its serialized public key */
// 公钥的Hash-160值(SHA-256+RIPEMD-160)
class CKeyID : public uint160
{
public:
    CKeyID() : uint160() {}
    explicit 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[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 COMPRESSED_PUBLIC_KEY_SIZE;
        if (chHeader == 4 || chHeader == 6 || chHeader == 7)
            return PUBLIC_KEY_SIZE;
        return 0;
    }

    //! Set this key data to be invalid
    // 设置公钥无效
    void Invalidate()
    {
        vch[0] = 0xFF;
    }

public:
    //! Construct an invalid public key.
    // 构造一个无效公钥
    CPubKey()
    {
        Invalidate();
    }

    //! Initialize a public key using begin/end iterators to byte data.
    // 使用容器初始化公钥数据
    template <typename T>
    void Set(const T pbegin, const T pend)
    {
        int len = pend == pbegin ? 0 : GetLen(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 <typename T>
    CPubKey(const T pbegin, const T pend)
    {
        Set(pbegin, pend);
    }

    //! Construct a public key from a byte vector.
    // 使用字节数组构造公钥
    explicit CPubKey(const std::vector<unsigned char>& _vch)
    {
        Set(_vch.begin(), _vch.end());
    }

    //! Simple read-only vector-like interface to the pubkey data.
    unsigned int size() const { return GetLen(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 CPubKey& a, const CPubKey& b)
    {
        return a.vch[0] == b.vch[0] &&
               memcmp(a.vch, b.vch, a.size()) == 0;
    }
    friend bool operator!=(const CPubKey& a, const CPubKey& b)
    {
        return !(a == b);
    }
    friend bool operator<(const CPubKey& a, const CPubKey& 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.
//    template 
//    void Serialize(Stream& s) const
//    {
//        unsigned int len = size();
//        ::WriteCompactSize(s, len);
//        s.write((char*)vch, len);
//    }
//    template 
//    void Unserialize(Stream& s)
//    {
//        unsigned int len = ::ReadCompactSize(s);
//        if (len <= PUBLIC_KEY_SIZE) {
//            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)
    // 获取公钥的Hash160哈希值(SHA-256+RIPEMD-160哈希值)
    CKeyID GetID() const
    {
        return CKeyID(Hash160(vch, vch + size()));
    }

    //! Get the 256-bit hash of this public key.
    // 获取公钥Hash256值(两次SHA-256哈希值)
    uint256 GetHash() const
    {
        return Hash(vch, vch + size());
    }

    /*
     * Check syntactic correctness.
     *
     * Note that this is consensus critical as CheckSig() calls it!
     */
    bool IsValid() const
    {
        return size() > 0;
    }

    //! 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
    {
        return size() == COMPRESSED_PUBLIC_KEY_SIZE;
    }

    /**
     * Verify a DER signature (~72 bytes).
     * If this public key is not fully valid, the return value will be false.
     */
     // 验证DER签名是否正确
    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.
    // 从协议签名中恢复公钥,见私钥SignCompact
    bool RecoverCompact(const uint256& hash, const std::vector<unsigned char>& vchSig);

    //! Turn this public key into an uncompressed public key.
    bool Decompress();

    //! Derive BIP32 child pubkey.
    // 派生BIP32子公钥
    bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;
};

测试程序主函数:(Dev-C++(4.9.9.2))

int main(int argc, char** argv) {
    // 测试私钥数据
    //9a9a6539856be209b8ea2adbd155c0919646d108515b60b7b13d6a79f1ae5174
    unsigned char testPriKey[32] = {0x9a, 0x9a, 0x65, 0x39, 0x85, 0x6b, 0xe2, 0x09,
                                0xb8, 0xea, 0x2a, 0xdb, 0xd1, 0x55, 0xc0, 0x91,
                                0x96, 0x46, 0xd1, 0x08, 0x51, 0x5b, 0x60, 0xb7,
                                0xb1, 0x3d, 0x6a, 0x79, 0xf1, 0xae, 0x51, 0x74};
    // 测试公钥数据
    //0340a609475afa1f9a784cad0db5d5ba7dbaab2147a5d7b9bbde4d1334a0e40a5e
    std::vector<unsigned char> testPubKey = {0x03, 0x40, 0xa6, 0x09, 0x47, 0x5a, 0xfa, 0x1f, 0x9a,
                                0x78, 0x4c, 0xad, 0x0d, 0xb5, 0xd5, 0xba, 0x7d, 
                                0xba, 0xab, 0x21, 0x47, 0xa5, 0xd7, 0xb9, 0xbb, 
                                0xde, 0x4d, 0x13, 0x34, 0xa0, 0xe4, 0x0a, 0x5e};
    CPrivKey LoadPriKey;

    CKey priKey;
    //priKey.MakeNewKey(true);
    ECCVerifyHandle eccVerifyHandle ;//必须定义一个ECCVerifyHandle
    ECC_Start();//初始化椭圆加密上下文结构体
    // 设置私钥数据 
    priKey.Set(testPriKey, testPriKey+sizeof(testPriKey), true);    
    LoadPriKey = priKey.GetPrivKey();
    std::cout<<std::setw(2)<<std::hex;
    std::cout<<std::setfill('0');
    // 打印私钥 
    std::cout<<"Private key [0x"<"]:";
    for(int ii = 0; ii < priKey.size(); ii++)
    {
        std::cout<<std::setw(2)<<std::hex;
        std::cout<<(int)(*(priKey.begin() + ii));
    }
    std::cout<<std::endl;
    // 获取公钥 
    CPubKey pubKey(testPubKey); 
    // 打印公钥 
    std::cout<<"Public key  [0x"<"]:";
    for(int ii = 0; ii < pubKey.size(); ii++)
    {
        std::cout<<std::setw(2);
        std::cout<<std::setfill('0')<<std::hex<<(int)(*(pubKey.begin() + ii));
    }
    std::cout<<std::endl;
    // 检测公私钥是否匹配 
    if(priKey.VerifyPubKey(pubKey)){
        std::cout<<"Private Key vs. Public Key Match."<<std::endl;
    }
    // 获取公钥 Hash-160
    uint160 hash160 = pubKey.GetID(); 
    // 打印公钥 Hash-160
    std::cout<<"Hash-160    [0x"<"]:";
    for(int ii = 0; ii < hash160.size(); ii++)
    {
        std::cout<<std::setw(2);
        std::cout<<std::setfill('0')<<std::hex<<(int)(*(hash160.begin() + ii));
    }
    std::cout<<std::endl;
    // 获取公钥哈希值 
    uint256 hash = pubKey.GetHash();
    // 打印公钥哈希值  
    std::cout<<"Hash        [0x"<"]:";
    for(int ii = 0; ii < hash.size(); ii++)
    {
        std::cout<<std::setw(2);
        std::cout<<std::setfill('0')<<std::hex<<(int)(*(hash.begin() + ii));
    }
    std::cout<<std::endl;
    std::vector<unsigned char> vchSig; 
    priKey.Sign(hash, vchSig);
    // 打印签名
    std::cout<<"Sign        [0x"<"]:"; 
    for(int ii = 0; ii < vchSig.size(); ii++){
        std::cout<<std::setw(2);
        std::cout<<std::setfill('0')<<std::hex<<(int)(*(vchSig.begin() + ii));
    }
    std::cout<<std::endl;

    // 校验签名 
    if(pubKey.CheckLowS(vchSig) && pubKey.Verify(hash, vchSig)){
        std::cout<<"Public Key Signed."<<std::endl;
    }
    // 获取非压缩公钥 
    pubKey.Decompress();
    // 打印公钥 
    std::cout<<"Public key  [0x"<"]:";
    for(int ii = 0; ii < pubKey.size(); ii++)
    {
        std::cout<<std::setw(2);
        std::cout<<std::setfill('0')<<std::hex<<(int)(*(pubKey.begin() + ii));
    }
    std::cout<<std::endl;

    priKey.SignCompact(hash, vchSig);
    pubKey.RecoverCompact(hash, vchSig);
    // 打印公钥 
    std::cout<<"Public key Recovered From SignCompact  [0x"<"]:";
    for(int ii = 0; ii < pubKey.size(); ii++)
    {
        std::cout<<std::setw(2);
        std::cout<<std::setfill('0')<<std::hex<<(int)(*(pubKey.begin() + ii));
    }
    std::cout<<std::endl;
    if(priKey.Load(LoadPriKey, pubKey, true)){
        std::cout<<"Load private key ok."<<std::endl;
    }
    // 获取子私钥 
    CKey keyChild;
    CPubKey pubkeyChild;
    ChainCode ccChild;
    unsigned int nChild = 1;
    ChainCode cc = hash;
    std::cout<<std::setw(100);
    std::cout<<std::endl<<std::setfill('=')<<"="<<std::endl;
    while(nChild <= 5){
        std::cout<<"Child key: [0x";
        std::cout<<std::setw(2);
        std::cout<<std::setfill('0')<<std::hex<"]"<<std::endl;
        std::cout<<"------------------------------------"<<std::endl;
        if(priKey.Derive(keyChild, ccChild, nChild, cc)){
            // 打印私钥 
            std::cout<<"Private key  [0x"<"]:";
            for(int ii = 0; ii < keyChild.size(); ii++)
            {
                std::cout<<std::setw(2);
                std::cout<<std::setfill('0')<<std::hex<<(int)(*(keyChild.begin() + ii));
            }
            std::cout<<std::endl;
        }
        if(pubKey.Derive(pubkeyChild, ccChild, nChild, cc)){
            // 打印公钥 
            std::cout<<"Public key   [0x"<"]:";
            for(int ii = 0; ii < pubkeyChild.size(); ii++)
            {
                std::cout<<std::setw(2);
                std::cout<<std::setfill('0')<<std::hex<<(int)(*(pubkeyChild.begin() + ii));
            }
            std::cout<<std::endl;
        }
        // 验证公钥私钥是否匹配 
        if(!priKey.VerifyPubKey(pubKey)){
            break;
        }
        cc = ccChild;
        nChild++;
        std::cout<<"------------------------------------"<<std::endl;
    }   
    std::cout<<std::setw(100);
    std::cout<<std::endl<<std::setfill('=')<<"="<<std::endl;
    ECC_Stop();
    return 0;
}

程序输出:

Private key [0x20]:9a9a6539856be209b8ea2adbd155c0919646d108515b60b7b13d6a79f1ae5174
Public key  [0x21]:0340a609475afa1f9a784cad0db5d5ba7dbaab2147a5d7b9bbde4d1334a0e40a5e
Private Key vs. Public Key Match.
Hash-160    [0x14]:154de7cabbb5822075e92c57a27ca3ef3e8be50c
Hash        [0x20]:bfb3881ab6c617bb88b3ccc2c338b7c589697ecdee8b7bce281881bc37b2d2f4
Sign        [0x46]:304402201d7b33869f712b8a34b9f1be40a42dcb55e15d0b7d4f4f314120fd4e937bcaf6022015223e8b35ca63e750ea07259b92e8ba69995339783c58bc0422c20e5a67cef3
Public Key Signed.
Public key  [0x41]:0440a609475afa1f9a784cad0db5d5ba7dbaab2147a5d7b9bbde4d1334a0e40a5e188ac3f1c6bbbc336fdc33cb5e605ff7c3ee2d36249933b0322220a616a11fb3
Public key Recovered From SignCompact  [0x21]:0340a609475afa1f9a784cad0db5d5ba7dbaab2147a5d7b9bbde4d1334a0e40a5e
Load private key ok.

====================================================================================================
Child key: [0x01]
------------------------------------
Private key  [0x21]:601195ea72ec9f79fad5efe86ec9411a868d1a9f7c1a7c9709512471f41a7348
Public key   [0x21]:02167423614e974d6ccad42514ea24f75df91a1c56c034aa7a5db07ecb8a31803e
------------------------------------
Child key: [0x02]
------------------------------------
Private key  [0x21]:ec94b96eb36eb4ff03f6596e3523247a402a26a7d021aaf486843cbb2bdcbeac
Public key   [0x21]:0273cdb90c02d53c8da352bd56cfe219eaf1206d677b01edb9be7303302db2c78a
------------------------------------
Child key: [0x03]
------------------------------------
Private key  [0x21]:5c969056631b9cee3ebc618171f22f44e6f6c6579131bdd4f33c09ecfc255b99
Public key   [0x21]:0355d75406b5cd1c9096fe86f1c761d4487ffd44220606c29e780a6cd6588baa55
------------------------------------
Child key: [0x04]
------------------------------------
Private key  [0x21]:94bb61ee22b5101dcf390358639f105d4704a1b87cfa8bb23ff04dd5aa5d2cb4
Public key   [0x21]:02fb24789c30cee067333c9f7f9738c850de3fe7ece9137f1178a232854e1a5578
------------------------------------
Child key: [0x05]
------------------------------------
Private key  [0x21]:d6cf632cb5e1df23f6399515c8e1d981c2a2914c8726c6cb84e812a017177ccb
Public key   [0x21]:03e311fa62acb96833cbaf74fa916d0acbd514a9f85abcfc5535efc272d8448762
------------------------------------

====================================================================================================

源码地址:

https://github.com/babylco0/bitcoin_code_examples/tree/master/testCKey
https://github.com/babylco0/bitcoin_code_examples/tree/master/TestKey (ubuntu)

你可能感兴趣的:(Bitcoin)