c++ 比特币SegWit钱包地址计算

yzckvree  于 7个月前  发布在  其他
关注(0)|答案(2)|浏览(77)

对不起,如果这是一个有点误导,但我实际上是这样做的莱特币,而不是比特币,但算法是完全相同的,我很肯定,答案也会.事实上,我几乎可以肯定,当我看,也会有同样的问题与比特币.我有困难生成正确的SegWit地址为一个给定的公钥如下:
莱特币地址生成(与比特币相同)
1.我取一个压缩公钥:03861 b83752 e0 c47 cac 36 fc 5980 ae 8956 f41 f6 d9792 a51 f68 a6 bd 5 f66 cc 7364 b48

  1. SHA 256公钥
  2. RipeMD 160来自2.
    1.添加一个前缀字节,在我的例子中,0x 3a是LTC_TESTNET
    1.将SHA 256结果的4加倍,并将此结果的前四个字节添加到RipeMD 160的末尾。
    1.最后是Base 58编码。
    一切似乎都很好,对吧?弹出SegWit地址:QhQxSZvVDWR 3 JvoKsYVC 6 BBW 3DqkGhesrF
    然而,我很确定这个地址是不正确的。当我将私钥作为(p2 wpkh-p2 sh:)导入到Electrum-LTC时,它为这个私钥生成的地址是:QYYWqgyWSm 1AJWph 32 GnyY 7 eamG 1 wUDruk
    现在我相信Electrum-LTC是正确的,在生成SegWit地址时我缺少了一些东西,并且地址生成不仅仅是改变网络前缀。我的公钥哈希是:

e444ac77800cdf904b928fc4642ab6fb6d4d696c

Electrum-LTC的公钥哈希是:

87b3e5bf5b2a1381e6549020d245e45b9ac76c82

由于值是如此的不同,这表明初始的SHA 256不仅仅是哈希公钥,我错过了一些东西。我的想法,并希望有人有答案,关于我能在源代码中找到的唯一的东西,在chainparams.cpp是这样的:

base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};

字符串
有人知道我可能做错了什么吗?

更新-有人问的代码-所以在这里

#include <openssl/sha.h>
#include <openssl/ripemd.h>
#include <cstdint>
#include <iostream>
#include <vector>

std::string base58Encode(const std::vector<uint8_t>& data)
{
    const uint8_t mapping[] = {
      '1', '2', '3', '4', '5', '6', '7', '8',
      '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
      'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q',
      'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
      'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
      'h', 'i', 'j', 'k', 'm', 'n', 'o', 'p',
      'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
      'y', 'z' };

    std::vector<uint8_t> digits((data.size() * 137) / 100);
    size_t digitslen = 1;
    for (size_t i = 0; i < data.size(); i++)
    {
        uint32_t carry = static_cast<uint32_t>(data[i]);
        for (size_t j = 0; j < digitslen; j++)
        {
            carry = carry + static_cast<uint32_t>(digits[j] << 8);
            digits[j] = static_cast<uint8_t>(carry % 58);
            carry /= 58;
        }
        for (; carry; carry /= 58)
            digits[digitslen++] = static_cast<uint8_t>(carry % 58);
    }
    std::string result;
    for (size_t i = 0; i < data.size() && !data[i]; i++)
        result.push_back(mapping[0]);
    for (size_t i = 0; i < digitslen; i++)
        result.push_back(mapping[digits[digitslen - 1 - i]]);
    return result;
}

std::vector<uint8_t> SHA256_Hash(const std::vector<uint8_t>& data)
{
    std::vector<uint8_t> SHA256_Digest(SHA256_DIGEST_LENGTH);
    SHA256_CTX ctx;
    SHA256_Init(&ctx);
    SHA256_Update(&ctx, data.data(), data.size());
    SHA256_Final(SHA256_Digest.data(), &ctx);
    return SHA256_Digest;
}

std::vector<uint8_t> RipeMD160_Hash(const std::vector<uint8_t>& data)
{
    std::vector<uint8_t> RipeMD160_Digest(RIPEMD160_DIGEST_LENGTH);
    RIPEMD160_CTX ctx;
    RIPEMD160_Init(&ctx);
    RIPEMD160_Update(&ctx, data.data(), data.size());
    RIPEMD160_Final(RipeMD160_Digest.data(), &ctx);
    return RipeMD160_Digest;
}

std::string getWalletAddress(const std::vector<uint8_t>& public_key, uint8_t id)
{
    std::vector<uint8_t> addr_hash = SHA256_Hash(key);
    std::vector<uint8_t> addr_ripe = RipeMD160_Hash(addr_hash);
    addr_ripe.insert(addr_ripe.begin(), id);
    addr_hash = SHA256_Hash(SHA256_Hash(addr_ripe));
    addr_ripe.insert(addr_ripe.end(), addr_hash.begin(), addr_hash.begin() + sizeof(uint32_t));
    return base58Encode(addr_ripe);
}

int main(int argc, char** argv)
{
    const uint8_t LTC_TESTNET = 0x3a;

    std::vector<uint8_t> public_key{
        0x03, 0x86, 0x1b, 0x83, 0x75, 0x2e, 0x0c, 0x47, 0xca, 0xc3, 0x6f, 0xc5, 0x98, 0x0a, 0xe8, 0x95,
        0x6f, 0x41, 0xf6, 0xd9, 0x79, 0x2a, 0x51, 0xf6, 0x8a, 0x6b, 0xd5, 0xf6, 0x6c, 0xc7, 0x36, 0x4b, 0x48};

    std::cout << "Wallet Address: " << getWalletAddress(public_key, LTC_TESTNET) << std::endl;
    // The above ouputs:  QhQxSZvVDWr3JvoKsYVC6BBW3DqkGhesrF
    // But it should be:  QYyWqgyWSm1AJWph32GnyY7eamG1wUDruk
    return 0;
}

13z8s7eq

13z8s7eq1#

在下面你自己的答案中,你的代码看起来像是有一行代码什么都不做,在is_p2sh == true的情况下。
第一个月
因为addr_hash在if(is_p2sh)块之后被再次分配给
addr_hash = SHA256_Hash(SHA256_Hash(addr_ripe));
还是我错过了什么

deyfvvtc

deyfvvtc2#

终于弄明白了这个问题.当计算一个p2 wpkh-p2 sh地址时,它不仅仅是地址的前缀不同。实际上,我在这里找到了上述问题的答案:https://bitcoin.stackexchange.com/questions/72775/is-it-possible-to-convert-an-address-from-p2pkh-to-p2sh(尽管它在解释上很神秘)。
我问题中的上述代码可以很好地为比特币/莱特币等生成p2pkh地址,但是当生成Q(莱特币),2(比特币)时,它就不起作用了,因为它不仅仅是哈希的公钥。它实际上是一个脚本,0x 00(DUP_0),然后是公钥哈希的长度(0x 14)。
因此,要修复上述代码,如果地址生成代码更改为:

std::string getWalletAddress(const std::vector<uint8_t>& public_key, uint8_t id, bool is_p2sh)
{
    std::vector<uint8_t> addr_hash = SHA256_Hash(key);
    std::vector<uint8_t> addr_ripe = RipeMD160_Hash(addr_hash);
    if (is_p2sh)
    {
        addr_ripe.insert(addr_ripe.begin(), { 0x00, static_cast<uint8_t>(addr_ripe.size()) });
        addr_hash = SHA256_Hash(addr_ripe);
        addr_ripe = RipeMD160_Hash(addr_ripe);
    }
    addr_ripe.insert(addr_ripe.begin(), id);
    addr_hash = SHA256_Hash(SHA256_Hash(addr_ripe));
    addr_ripe.insert(addr_ripe.end(), addr_hash.begin(), addr_hash.begin() + sizeof(uint32_t));
    return base58Encode(addr_ripe);
}

// This will now work for both p2pkh addresses and p2wpkh-p2sh addresses

getWalletAddress(public_key, LTC_TESTNET, true);  // Produces: QYyWqgyWSm1AJWph32GnyY7eamG1wUDruk

字符串

相关问题