温故而知新 /比特币(Bitcoin)有关的 Base58 & Base58Check、私钥(Private KEY)、公钥(Public KEY)、地址(Address)

in #cn7 years ago

这两天在学习STEEM的交易签名,由于智商感人,所以进展缓慢。里边涉及有一些公钥私钥方面的内容,然后惊觉我之前对这部分内容的了解,已经忘干净了!从头再学,有些压力,还好之前学习的内容都记录在STEEMIT上,把之前的相关帖子都翻看一下,顺便摘录一些重点贴在这篇文章中,算是做笔记吧。

<p dir="auto"><strong><em>STEEM中<del>照搬了借鉴了比特币(Bitcoin)的那一套东西,所以之前写的比特币(Bitcoin)一系列文章对自己还是很有参考价值的。 <p dir="auto"><span><img src="https://images.hive.blog/768x0/https://steemitimages.com/DQmdqLCmAiWQy8rbk82JTrjNombFv3LfzQKA8vjSbDYkVWE/image.png" srcset="https://images.hive.blog/768x0/https://steemitimages.com/DQmdqLCmAiWQy8rbk82JTrjNombFv3LfzQKA8vjSbDYkVWE/image.png 1x, https://images.hive.blog/1536x0/https://steemitimages.com/DQmdqLCmAiWQy8rbk82JTrjNombFv3LfzQKA8vjSbDYkVWE/image.png 2x" /> <p dir="auto">本文主要涉及以下方面内容: <ul> <li><strong><em>Base58 & Base58Check <li><strong><em>私钥(Private KEY) <li><strong><em>公钥(Public KEY) <li><strong><em>地址(Address)<br /> <br /> <h1>Base58 & Base58Check <p dir="auto">因为涉及私钥、公钥的时候经常要用到<strong><em><code>Base58 & Base58Check编解码,所以首先简要介绍一下这两个东西。 <h4>Base58 <p dir="auto"><strong><em><code>Base58简单地说,就是<strong><em>把数字表示成不容易输入错误的文本编码,因为这组不容易出错的文本编码一共包含58个字符,所以叫Base58 <p dir="auto">编解码规则也很简单,编码就是<strong><em>把文本表示数字串,转换成一个大整数,然后再按58进制表示。 <p dir="auto">58进制和16进制类似,16进制数字0-15和0x0 - 0xF是一一对应的,而这个0-57,需要查表对应,仅此而已!解码就是逆过程! <p dir="auto">码表为:<br /> <strong><em><code>BASE58_ALPHABET = b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" <h4>Base58Check <p dir="auto"><strong><em><code>Base58Check在就是<code>Base58基础上加上了版本信息以及校验,这样如果不小心输错一两个字符,就会检查出来。 <p dir="auto"><strong><em><code>Base58Check流程可以用下图表示:<br /><br /> Image source <a href="http://orm-chimera-prod.s3.amazonaws.com/1234000001802/images/msbt_0406.png" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Here<span> <img src="https://images.hive.blog/768x0/https://steemitimages.com/DQmR6osyE59XryeuQyffbf74WoMcN9vcMs8xYnQ9qDMH3tP/image.png" srcset="https://images.hive.blog/768x0/https://steemitimages.com/DQmR6osyE59XryeuQyffbf74WoMcN9vcMs8xYnQ9qDMH3tP/image.png 1x, https://images.hive.blog/1536x0/https://steemitimages.com/DQmR6osyE59XryeuQyffbf74WoMcN9vcMs8xYnQ9qDMH3tP/image.png 2x" /> <p dir="auto">整理成文字说明如下: <ul> <li>把版本/程序信息字节和负载(payload)按字节连接到一起 <li>对结果一执行两次SHA256操作并取前四个字节 <li>按字节把结果一和结果二的四个字节连接起来 <li>把结果三当成一个大数字,对结果三执行Bash58编码<br /> (原链接第四步,分为4、5、6三个步骤,包括如何处理前导字节零)<br /> <br /> <h1>私钥(Private KEY) <h4>私钥是什么 <p dir="auto"><strong><em>私钥就是一个256位,取值处于1到n - 1之间的随机数<br /> 其中: <strong><em>n = 1.158 * 10<sup>77 <h4>私钥表示方式 <p dir="auto">私钥有几种表示方式<br /><br /> 其中<strong><em><code>WIF亦即: <code>Wallet Import Format (WIF)<span> <img src="https://images.hive.blog/768x0/https://steemitimages.com/DQmSkr2rwj81AanQ5BD41MxvdmVtVEPEba7jf5SeqwZwnEg/image.png" srcset="https://images.hive.blog/768x0/https://steemitimages.com/DQmSkr2rwj81AanQ5BD41MxvdmVtVEPEba7jf5SeqwZwnEg/image.png 1x, https://images.hive.blog/1536x0/https://steemitimages.com/DQmSkr2rwj81AanQ5BD41MxvdmVtVEPEba7jf5SeqwZwnEg/image.png 2x" /> <ul> <li><strong><em>64位16进制串就是把私钥直接转换 <li><strong><em>Base58编码<span>就是对64位16进制串直接编码 (<a href="https://blockchain.info" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">https://blockchain.info中有用到) <li><strong><em>WIF就是在64位16进制串对应的字节串前加上<strong><em><code>前缀0x80, 并用Base58Check编码 <li><strong><em>WIF-compressed就是在64位16进制串对应的字节串前加上<strong><em><code>前缀0x80,并加上<strong><em><code>后缀0x01, 并用Base58Check编码 <h4>私钥的生成 <p dir="auto">私钥可以用hashlib.sha256来生成(仅供参考,请勿使用) <pre><code>>>> import hashlib >>> from binascii import hexlify, unhexlify >>> s = hashlib.sha256(bytes('Hello World', 'utf-8')).digest() >>> print(hexlify(s).decode('ascii')) a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e <p dir="auto"><br /> <h1>公钥(Public KEY) <p dir="auto">涉及到椭圆曲线等数学知识我就方了,直接上干货吧。 <h4>如何生成公钥 <ul> <li><code>公钥(K)可以通过椭圆曲线运算由<code>私钥(k)计算得出 <li><code>私钥(k)到<code>公钥(K)计算公式:<strong><em><code>K=k∗G <li>生成过程使用<code>secp256k1标准中定义的椭圆曲线以及一组数学常量 <li>从<code>私钥(k)到<code>公钥(K)结果是确定的,并且只能单向运算 <li>使用Python的ecdsa库,可以轻松实现<code>私钥(k)到<code>公钥(K)的计算 <h4>关于<strong><em><code>K=k∗G <p dir="auto">其中小<strong><em><code>k是我们的<code>私钥,<strong><em><code>G是<code>生成点,<strong><em><code>K是结果亦即<code>公钥是<code>曲线上的另外一个点。 <p dir="auto">因为生成点对所有的比特币用户都是相同的,所以同一个私钥k乘以生成点G,总会得到相同的公钥K。<strong><em>所以从k到K是确定的,并且只能单向运算。这就是为何比特币地址(由公钥生成)可以告诉任何人不用担心泄露私钥。 <h4>公钥压缩 <p dir="auto"><strong><em>公钥(K)是通过私钥(k)乘以生成点(G)得到的,并且是椭圆曲线上的一个点P(x, y)<br /><span> <img src="https://images.hive.blog/768x0/https://steemitimages.com/DQmb7rcLbqp9vb4ZawJTtvPLNCkYzWhPvddmAJjmY69V1cb/image.png" srcset="https://images.hive.blog/768x0/https://steemitimages.com/DQmb7rcLbqp9vb4ZawJTtvPLNCkYzWhPvddmAJjmY69V1cb/image.png 1x, https://images.hive.blog/1536x0/https://steemitimages.com/DQmb7rcLbqp9vb4ZawJTtvPLNCkYzWhPvddmAJjmY69V1cb/image.png 2x" /> <p dir="auto">将<code>点P(x, y)表示成公钥其实就是<strong><em>加上前缀04并把x和y连接起来<br /><span> <img src="https://images.hive.blog/768x0/https://steemitimages.com/DQmTegJz1aAW9VwFRyQ3G7AwGHiRs5GUe8M31b3ucmg7gJg/image.png" srcset="https://images.hive.blog/768x0/https://steemitimages.com/DQmTegJz1aAW9VwFRyQ3G7AwGHiRs5GUe8M31b3ucmg7gJg/image.png 1x, https://images.hive.blog/1536x0/https://steemitimages.com/DQmTegJz1aAW9VwFRyQ3G7AwGHiRs5GUe8M31b3ucmg7gJg/image.png 2x" /> <p dir="auto">一共是520bits (8 + 256 + 256),使用16进制字符串表示,要130个字节,浪费网络资源。 <p dir="auto">公钥压缩原理:<br /> 根据<strong><em>椭圆曲线的方程,我们是可以通过x求得y的,所以我们只要保留x部分就可以了 <p dir="auto">公钥压缩流程:<br /><br /> 公钥压缩的示意图( Source: <a href="http://chimera.labs.oreilly.com/books/1234000001802/ch04.html#_key_formats" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">《Mastering Bitcoin》)<span> <img src="https://images.hive.blog/768x0/https://steemitimages.com/DQmfQFYDtexuAT9x1ELJZJ4oboBUrbLDfkmuz6NvEytvCPT/image.png" srcset="https://images.hive.blog/768x0/https://steemitimages.com/DQmfQFYDtexuAT9x1ELJZJ4oboBUrbLDfkmuz6NvEytvCPT/image.png 1x, https://images.hive.blog/1536x0/https://steemitimages.com/DQmfQFYDtexuAT9x1ELJZJ4oboBUrbLDfkmuz6NvEytvCPT/image.png 2x" /> <h4>示例代码:私钥生成公钥 <pre><code>import ecdsa from binascii import hexlify, unhexlify secret = unhexlify('a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e') order = ecdsa.SigningKey.from_string(secret, curve=ecdsa.SECP256k1).curve.generator.order() p = ecdsa.SigningKey.from_string(secret, curve=ecdsa.SECP256k1).verifying_key.pubkey.point x_str = ecdsa.util.number_to_string(p.x(), order) y_str = ecdsa.util.number_to_string(p.y(), order) compressed = hexlify(bytes(chr(2 + (p.y() & 1)), 'ascii') + x_str).decode('ascii') uncompressed = hexlify(bytes(chr(4), 'ascii') + x_str + y_str).decode('ascii') p = 115792089237316195423570985008687907853269984665640564039457584007908834671663 x = int(hexlify(x_str).decode('ascii'), 16) y = int(hexlify(y_str).decode('ascii'), 16) (x ** 3 + 7 - y**2) % p <p dir="auto"><br /> <h1>地址(Address) <p dir="auto"><strong><em>比特币地址由公钥按固定流程生成。 <p dir="auto">生成流程如下:<br /><span> <img src="https://images.hive.blog/768x0/https://steemitimages.com/DQmZ3Zc3bNTYX12BcsyWdQ8aKuJfd8uUeznRVGS2q8bky17/image.png" srcset="https://images.hive.blog/768x0/https://steemitimages.com/DQmZ3Zc3bNTYX12BcsyWdQ8aKuJfd8uUeznRVGS2q8bky17/image.png 1x, https://images.hive.blog/1536x0/https://steemitimages.com/DQmZ3Zc3bNTYX12BcsyWdQ8aKuJfd8uUeznRVGS2q8bky17/image.png 2x" /> <p dir="auto">根据地址生成流程可知: <ul> <li>压缩公钥生成对应压缩公钥的地址 <li>未压缩公钥生成对应未压缩公钥的地址 <p dir="auto"><strong><em>地址和私钥本身是不压缩的,只是代表对应的公钥是压缩的而已 <h4>示例代码:公钥生成地址 <pre><code>def ripemd160(s): ripemd160 = hashlib.new('ripemd160') ripemd160.update(unhexlify(s)) return ripemd160.digest() def get_address(public_key): pkbin = unhexlify(public_key) addressbin = ripemd160(hexlify(hashlib.sha256(pkbin).digest())) address = base58CheckEncode(0x00, hexlify(addressbin).decode('ascii')) return address <h1>参考资料(以前文章) <ul> <li><a href="https://steemit.com/cn/@oflyhigh/base58" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">学习了一下Base58编解码 <li><a href="https://steemit.com/cn/@oflyhigh/base58-base58check" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">继续学习Base58以及Base58Check <li><a href="https://steemit.com/cn/@oflyhigh/6qp5kr-and" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">继续学习比特币的私钥 & 私钥的表示方法 <li><a href="https://steemit.com/cn/@oflyhigh/61quvw" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">每天进步一点点: 学习比特币的公钥 <li><a href="https://steemit.com/cn/@oflyhigh/4xgqtd" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">每天进步一点点: 比特币的公钥压缩与地址 <li><a href="https://steemit.com/cn/@oflyhigh/26qjos" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">真金白银出真知: 测试一下生成的比特币地址😭😭 <p dir="auto"><strong><em>免责声明,本文为个人理解,示例仅供参考<br /> 因使用文中代码或地址造成的损失,概不负责!
Sort:  

讲的很详细的,但是发现看不懂的占绝大多数,我就放心了,😀

记得很久之前想知道 WIF 是啥意思,一直没找到,结果才这里学到了,哈哈。

我知道啥叫wtf

awesome but can`t understand ur lang

看完我周二的大脑袋开始晕眩。。。反正只要你自己不丢,就都是特别特别安全很难很难解开的密码就是了。。

有种在读 Andreas M. Antonopoulos 的《Mastering Bitcoin》的感觉。

图都是从《Mastering Bitcoin》拿过来的啊 😀
是本超级好书,可惜我只读了一点点

之前看了一阵就停了,太多数学的东西看得好辛苦,读了你的理解再看回去应该会明白更多。

Peace, mercy and blessings of God

i will always support you man!!

腦細胞剩一個了..... T_T

智商感人➕1……

虽然不太懂但感觉很cool

Good post!!Thank you:)

不错哦 椭圆曲线那部分说实话看了也看不懂 听了课 还是懵懵的

讲得挺详细,不过还没看太懂

沒想到你還真的有點料啊?我都帶泳褲來了,卻沒得游泳~~~~

那就把泳裤也脱了吧

很好的信息..投票给你

不明觉厉