比特币钱包地址的演变(一)-P2PKH

  • seashell
  • 更新于 5小时前
  • 阅读 43

比特币钱包地址的变迁

比特币钱包地址主要有三种类型,它们分别是:

1. P2PKH地址(Pay-to-Public-Key-Hash)

以数字“1”开头。

例如:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa

2. P2SH地址(Pay-to-Script-Hash)

以数字“3”开头。

例如:3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy

3. Bech32地址(SegWit地址)

以“bc1”开头。

例如:bc1qar0srrr7x3n5q0g5x6l6g0z4c2s4h0l8h6k3qf

我将分三篇文章,分别介绍三种地址的生成步骤、地址由来以及应用场景。

生成这些地址将使用Python的ECDSA库,还有hashlibbase58

生成钱包地址

P2PKH地址的生成步骤:

  1. 引入三个库:
from ecdsa import SECP256k1, SigningKey
import hashlib
import base58
  1. 先生成私钥,再生成公钥:
private_key = SigningKey.generate(curve=SECP256k1)
public_key = private_key.get_verifying_key()
  1. 对公钥进行SHA256哈希,再进行RIPEMD160哈希,添加比特币主网前缀'\x00':
public_key_bytes = public_key.to_string()
sha256 = hashlib.sha256(public_key_bytes).digest()
ripemd160 = hashlib.new('ripemd160', sha256).digest()
address = b'\x00' + ripemd160  # \x00 bitcoin mainnet

至此,P2PKH的地址主体已经生成了。

  1. 再进行两次SHA256哈希,但是只取前四字节作为尾部校验码:
checksum = hashlib.sha256(hashlib.sha256(address).digest()).digest()[:4]
address += checksum
  1. 最后进行base58编码,地址生成
address = base58.b58encode(address).decode()

图示生成过程:

最后,找个在线工具验证我们生成的地址

</br>

151Wm9Xps2sR4wnTr8ffszL92U6WTFugC8

</br>

P2PKH地址应用解析

P2PKH地址仅含有公钥信息,所以是公钥哈希地址。只要提供同一公钥,按照相同的步骤总是可以得到相同的地址。所以区块链网络在花费比特币的时候,先拿到交易请求信息内的公钥,进行P2PKH计算得到钱包地址,校验公钥是否合法。其次再用公钥验签私钥签名的交易信息,通过则证明比特币花费请求是合法的。

比特币开放了一个小小的窗口,用于定义校验花费条件。这个窗口为了安全考虑,功能较弱,它称之为比特币脚本语言。基于栈数据结构和定义好的操作码,操作码可以认为是单一功能的函数。

P2PKH地址对应的解锁脚本定义如下示例:

OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG

该脚本的处理流程如下:

输入数据到堆栈:

  • PUSHDATA(Sig):交易签名数据压入栈。

  • PUSHDATA(PubKey):公钥压入栈。

    此时栈内两个元素:

image.png

执行操作码,操作堆栈里的数据:

  • DUP:复制PubKey,堆栈里有两个元素都是公钥。
  • HASH160:执行SHA256后执行RIMEPD160,压入栈内。
  • PUSHDATA(PubKeyHash):将输出脚本中提供的公钥哈希压入栈。
  • EQUALVERIFY:栈头部两个公钥哈希对比,如上表。相同则验证通过,并删除元素。

image.png

  • CHECKSIG:栈内还有两个元素,公钥和交易签名数据,验签通过则执行花费交易。

操作码大全

当前,比特币操作码有如下几类,后续我们分析其他类型地址的时候会陆续用到。比特币闪电网络也离不开这些操作码的支持。

以下截取自Bitcoin core项目:

std::string GetOpName(opcodetype opcode)
{
    switch (opcode)
    {    
        // push value    
        case OP_0                      : return "0";
        case OP_PUSHDATA1              : return "OP_PUSHDATA1";
        case OP_PUSHDATA2              : return "OP_PUSHDATA2";    
        case OP_PUSHDATA4              : return "OP_PUSHDATA4";    
        case OP_1NEGATE                : return "-1";    
        case OP_RESERVED               : return "OP_RESERVED";    
        case OP_1                      : return "1";    
        case OP_2                      : return "2";    
        case OP_3                      : return "3";    
        case OP_4                      : return "4";    
        case OP_5                      : return "5";    
        case OP_6                      : return "6";    
        case OP_7                      : return "7";    
        case OP_8                      : return "8";    
        case OP_9                      : return "9";    
        case OP_10                     : return "10";    
        case OP_11                     : return "11";    
        case OP_12                     : return "12";    
        case OP_13                     : return "13";    
        case OP_14                     : return "14";    
        case OP_15                     : return "15";    
        case OP_16                     : return "16";

        // control
        case OP_NOP                    : return "OP_NOP";    
        case OP_VER                    : return "OP_VER";    
        case OP_IF                     : return "OP_IF";    
        case OP_NOTIF                  : return "OP_NOTIF";    
        case OP_VERIF                  : return "OP_VERIF";    
        case OP_VERNOTIF               : return "OP_VERNOTIF";    
        case OP_ELSE                   : return "OP_ELSE";    
        case OP_ENDIF                  : return "OP_ENDIF";    
        case OP_VERIFY                 : return "OP_VERIFY";    
        case OP_RETURN                 : return "OP_RETURN";

        // stack ops    
        case OP_TOALTSTACK             : return "OP_TOALTSTACK";    
        case OP_FROMALTSTACK           : return "OP_FROMALTSTACK";    
        case OP_2DROP                  : return "OP_2DROP";    
        case OP_2DUP                   : return "OP_2DUP";    
        case OP_3DUP                   : return "OP_3DUP";    
        case OP_2OVER                  : return "OP_2OVER";    
        case OP_2ROT                   : return "OP_2ROT";    
        case OP_2SWAP                  : return "OP_2SWAP";    
        case OP_IFDUP                  : return "OP_IFDUP";    
        case OP_DEPTH                  : return "OP_DEPTH";    
        case OP_DROP                   : return "OP_DROP";    
        case OP_DUP                    : return "OP_DUP";    
        case OP_NIP                    : return "OP_NIP";    
        case OP_OVER                   : return "OP_OVER";    
        case OP_PICK                   : return "OP_PICK";    
        case OP_ROLL                   : return "OP_ROLL";    
        case OP_ROT                    : return "OP_ROT";    
        case OP_SWAP                   : return "OP_SWAP";   
        case OP_TUCK                   : return "OP_TUCK";

        // splice ops    
        case OP_CAT                    : return "OP_CAT";    
        case OP_SUBSTR                 : return "OP_SUBSTR";    
        case OP_LEFT                   : return "OP_LEFT";    
        case OP_RIGHT                  : return "OP_RIGHT";    
        case OP_SIZE                   : return "OP_SIZE";

        // bit logic    
        case OP_INVERT                 : return "OP_INVERT";    
        case OP_AND                    : return "OP_AND";    
        case OP_OR                     : return "OP_OR";    
        case OP_XOR                    : return "OP_XOR";    
        case OP_EQUAL                  : return "OP_EQUAL";    
        case OP_EQUALVERIFY            : return "OP_EQUALVERIFY";    
        case OP_RESERVED1              : return "OP_RESERVED1";    
        case OP_RESERVED2              : return "OP_RESERVED2";

        // numeric    
        case OP_1ADD                   : return "OP_1ADD";    
        case OP_1SUB                   : return "OP_1SUB";    
        case OP_2MUL                   : return "OP_2MUL";    
        case OP_2DIV                   : return "OP_2DIV";    
        case OP_NEGATE                 : return "OP_NEGATE";    
        case OP_ABS                    : return "OP_ABS";    
        case OP_NOT                    : return "OP_NOT";    
        case OP_0NOTEQUAL              : return "OP_0NOTEQUAL";    
        case OP_ADD                    : return "OP_ADD";    
        case OP_SUB                    : return "OP_SUB";    
        case OP_MUL                    : return "OP_MUL";    
        case OP_DIV                    : return "OP_DIV";    
        case OP_MOD                    : return "OP_MOD";    
        case OP_LSHIFT                 : return "OP_LSHIFT";    
        case OP_RSHIFT                 : return "OP_RSHIFT";    
        case OP_BOOLAND                : return "OP_BOOLAND";    
        case OP_BOOLOR                 : return "OP_BOOLOR";    
        case OP_NUMEQUAL               : return "OP_NUMEQUAL";    
        case OP_NUMEQUALVERIFY         : return "OP_NUMEQUALVERIFY";    
        case OP_NUMNOTEQUAL            : return "OP_NUMNOTEQUAL";    
        case OP_LESSTHAN               : return "OP_LESSTHAN";    
        case OP_GREATERTHAN            : return "OP_GREATERTHAN";    
        case OP_LESSTHANOREQUAL        : return "OP_LESSTHANOREQUAL";    
        case OP_GREATERTHANOREQUAL     : return "OP_GREATERTHANOREQUAL";    
        case OP_MIN                    : return "OP_MIN";    
        case OP_MAX                    : return "OP_MAX";    
        case OP_WITHIN                 : return "OP_WITHIN";

        // crypto    
        case OP_RIPEMD160              : return "OP_RIPEMD160";    
        case OP_SHA1                   : return "OP_SHA1";    
        case OP_SHA256                 : return "OP_SHA256";    
        case OP_HASH160                : return "OP_HASH160";    
        case OP_HASH256                : return "OP_HASH256";    
        case OP_CODESEPARATOR          : return "OP_CODESEPARATOR";    
        case OP_CHECKSIG               : return "OP_CHECKSIG";    
        case OP_CHECKSIGVERIFY         : return "OP_CHECKSIGVERIFY";    
        case OP_CHECKMULTISIG          : return "OP_CHECKMULTISIG";    
        case OP_CHECKMULTISIGVERIFY    : return "OP_CHECKMULTISIGVERIFY";

        // expansion    
        case OP_NOP1                   : return "OP_NOP1";    
        case OP_CHECKLOCKTIMEVERIFY    : return "OP_CHECKLOCKTIMEVERIFY";    
        case OP_CHECKSEQUENCEVERIFY    : return "OP_CHECKSEQUENCEVERIFY";    
        case OP_NOP4                   : return "OP_NOP4";    
        case OP_NOP5                   : return "OP_NOP5";    
        case OP_NOP6                   : return "OP_NOP6";    
        case OP_NOP7                   : return "OP_NOP7";    
        case OP_NOP8                   : return "OP_NOP8";    
        case OP_NOP9                   : return "OP_NOP9";    
        case OP_NOP10                  : return "OP_NOP10";

        // Opcode added by BIP 342 (Tapscript)    
        case OP_CHECKSIGADD            : return "OP_CHECKSIGADD";    
        case OP_INVALIDOPCODE          : return "OP_INVALIDOPCODE";
        default:        return "OP_UNKNOWN";    
    }
}
点赞 2
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
seashell
seashell
区块链+金融,个人公众号SeashellMovingOn