内容简介:手动生成Bitcoin地址看似有点儿事倍功半,如果你了解了这个过程,就会明白眼花缭乱的Bitcoin分叉币地址只是私钥的不同显示方式,对了解Eth EOS地址也很有帮助,也可以更清楚的了解Bitcoin是如何...本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。
手动生成Bitcoin地址看似有点儿事倍功半,如果你了解了这个过程,就会明白眼花缭乱的Bitcoin分叉币地址只是私钥的不同显示方式,对了解Eth EOS地址也很有帮助,也可以更清楚的了解Bitcoin是如何...
手动生成Bitcoin地址看似有点儿事倍功半,如果你了解了这个过程,就会明白眼花缭乱的Bitcoin分叉币地址只是私钥的不同显示方式,对了解Eth EOS地址也很有帮助,也可以更清楚的了解Bitcoin是如何花费的,一通则百通,妙哉。
我们使用私钥 0xccea9c5a20e2b78c2e0fbdd8ae2d2b67e6b1894ccb7a55fc1de08bd53994ea64
生成了一个主网地址 14xfJr1DArtYR156XBs28FoYk6sQqirT2s
。
生成Bitcoin地址,先由私钥生成公钥,再有公钥生成hash160,最后hash160再进行base58运算得到地址,如下图所示:
由私钥得到公钥,是由ECDSA实现的。ECDSA是 Elliptic Curve Digital Signature Algorithm
的缩写, 即 椭圆曲线数字签名算法 。
椭圆曲线其实不是椭圆,而是下面的模样:
比特币用到的椭圆曲线是 secp256k1: $y^2=x^3+7$ 那我们言归正传,直接进入主题,我把这个过程分成了8个步骤。
Step1. 生成私钥
Bitcoin要使用到Secp256k1这条特殊的椭圆曲线得到公私钥, 我们通过OpenSSL命令来生成私钥。
openssl ecparam -name secp256k1 -genkey > priv.pem # 输出DER格式 openssl ec -in priv.pem -outform DER | tail -c +8 | head -c 32 | xxd -p -c 32 # 结果 ccea9c5a20e2b78c2e0fbdd8ae2d2b67e6b1894ccb7a55fc1de08bd53994ea64
这里的结果是个16进制数据 0xccea9c5a20e2b78c2e0fbdd8ae2d2b67e6b1894ccb7a55fc1de08bd53994ea64
更快捷的方式是 openssl rand 32 -hex
Step2. 生成公钥
通过priv.pem 生成 pub_key
openssl ec -in priv.pem -pubout -outform DER | tail -c 65 | xxd -p -c 65 # 输出 04d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f691757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d
输出DER格式, 字符长度是130 pub_key = 04d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f691757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d
这是未压缩公钥,压缩公钥是 03d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f69
一步到位生成私钥、公钥
openssl ecparam -genkey -name secp256k1 -text -noout -outform DER | \ xxd -p -c 1000 | \ sed 's/41534e31204f49443a20736563703235366b310a30740201010420/PrivKey: /' | \ sed 's/a00706052b8104000aa144034200/\'$'\nPubKey: /'
详细内容请看 压缩公钥与非压缩公钥
Step3. 第2步结果进行hash160运算
hash160运算就是先进行SHA256,再进行RMD160。
bytes = [pub_key].pack("H*") # 转为16进制 hash160_val = Digest::RMD160.hexdigest(Digest::SHA256.digest(bytes) )
hash160_val = 2b6f3b9e337cedbb7c40839523fb1100709c12f7
Step4. 第3步结果加上前缀符
普通的主网地址的前缀符是 00
,Bitcoin 地址前缀符有很多种, 具体看https://en.bitcoin.it/wiki/List_of_address_prefixes
'00'+ '2b6f3b9e337cedbb7c40839523fb1100709c12f7'
step_04 = 002b6f3b9e337cedbb7c40839523fb1100709c12f7
Step5. 第4步结果, 执行2次SHA256, 取前8位作为校验和
hex_str = [step_04].pack("H*") checksum = Digest::SHA256.hexdigest(Digest::SHA256.digest(hex_str) )[0...8]
checksum = 86b2e90c
Step6. 第4步结果跟第5步结果合并
'002b6f3b9e337cedbb7c40839523fb1100709c12f7' + '86b2e90c' # step_04 + checksum
step_06 = 002b6f3b9e337cedbb7c40839523fb1100709c12f786b2e90c
Step7. Base58编码
Base58是一种独特的编码方式,是Base64的变形,主要用于Bitcoin的钱包地址。相比Base64,Base58去掉了数字 0
,大写字母 O
,大写字母 I
,小写字母 l
, +
和 /
,避免引起视觉混淆。
来个base58算法
def encode_base58(int_val, leading_zero_bytes=0) alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" base58_val, base = '', alpha.size while int_val > 0 int_val, remainder = int_val.divmod(base) base58_val = alpha[remainder] + base58_val end base58_val end
Step8. 第6步结果进行base58编码
step_06 = "002b6f3b9e337cedbb7c40839523fb1100709c12f786b2e90c" leading_zero_bytes = (step_06.match(/^([0]+)/) ? $1 : '').size / 2 # leading_zero_bytes的作用是字母填充 address = ("1" * leading_zero_bytes) + encode_base58(step_06.to_i(16) )
得到 14xfJr1DArtYR156XBs28FoYk6sQqirT2s
,这是一个标准的bitcoin地址,终于大功告成。
思考:通过Bitcoin 地址能反向得到hash160_val么?
汇总代码: gen_addr.rb
可以使用 bitcoin-ruby 生成地址
require 'bitcoin' pri_key, pub_key = Bitcoin.generate_key # 私钥 公钥 # 通过ffi调用OpenSSL得到,很多类库都是这么做的 address = Bitcoin::pubkey_to_address(pub_key)
生成测试网地址
require 'bitcoin' Bitcoin::network = :testnet #使用测试网 pri_key, pub_key = Bitcoin.generate_key address = Bitcoin::pubkey_to_address(pub_key)
在Bitcoin系统中,私钥能得公钥,公钥能得到钱包地址, 私钥=>公钥=>钱包地址,而反向是不可以的。 牢记你的私钥 ,而且 私钥不能修改 , 地址也不能修改 ,谁掌握了私钥谁就拥有了这些币!!!
参考:
How do these OpenSSL commands create a Bitcoin private/key from a ECDSA keypair How to convert an ECDSA key to PEM format
https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses https://en.bitcoin.it/wiki/Address https://en.bitcoin.it/wiki/List_of_address_prefixes https://github.com/liushooter/learn-blockchain/blob/master/gen_addr.rb
手动生成Bitcoin地址看似有点儿事倍功半,如果你了解了这个过程,就会明白眼花缭乱的Bitcoin分叉币地址只是私钥的不同显示方式,对了解Eth EOS地址也很有帮助,也可以更清楚的了解Bitcoin是如何花费的,一通则百通,妙哉。
我们使用私钥 0xccea9c5a20e2b78c2e0fbdd8ae2d2b67e6b1894ccb7a55fc1de08bd53994ea64
生成了一个主网地址 14xfJr1DArtYR156XBs28FoYk6sQqirT2s
。
生成Bitcoin地址,先由私钥生成公钥,再有公钥生成hash160,最后hash160再进行base58运算得到地址,如下图所示:
由私钥得到公钥,是由ECDSA实现的。ECDSA是 Elliptic Curve Digital Signature Algorithm
的缩写, 即 椭圆曲线数字签名算法 。
椭圆曲线其实不是椭圆,而是下面的模样:
比特币用到的椭圆曲线是 secp256k1: $y^2=x^3+7$ 那我们言归正传,直接进入主题,我把这个过程分成了8个步骤。
Step1. 生成私钥
Bitcoin要使用到Secp256k1这条特殊的椭圆曲线得到公私钥, 我们通过OpenSSL命令来生成私钥。
openssl ecparam -name secp256k1 -genkey > priv.pem # 输出DER格式 openssl ec -in priv.pem -outform DER | tail -c +8 | head -c 32 | xxd -p -c 32 # 结果 ccea9c5a20e2b78c2e0fbdd8ae2d2b67e6b1894ccb7a55fc1de08bd53994ea64
这里的结果是个16进制数据 0xccea9c5a20e2b78c2e0fbdd8ae2d2b67e6b1894ccb7a55fc1de08bd53994ea64
更快捷的方式是 openssl rand 32 -hex
Step2. 生成公钥
通过priv.pem 生成 pub_key
openssl ec -in priv.pem -pubout -outform DER | tail -c 65 | xxd -p -c 65 # 输出 04d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f691757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d
输出DER格式, 字符长度是130 pub_key = 04d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f691757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d
这是未压缩公钥,压缩公钥是 03d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f69
一步到位生成私钥、公钥
openssl ecparam -genkey -name secp256k1 -text -noout -outform DER | \ xxd -p -c 1000 | \ sed 's/41534e31204f49443a20736563703235366b310a30740201010420/PrivKey: /' | \ sed 's/a00706052b8104000aa144034200/\'$'\nPubKey: /'
详细内容请看 压缩公钥与非压缩公钥
Step3. 第2步结果进行hash160运算
hash160运算就是先进行SHA256,再进行RMD160。
bytes = [pub_key].pack("H*") # 转为16进制 hash160_val = Digest::RMD160.hexdigest(Digest::SHA256.digest(bytes) )
hash160_val = 2b6f3b9e337cedbb7c40839523fb1100709c12f7
Step4. 第3步结果加上前缀符
普通的主网地址的前缀符是 00
,Bitcoin 地址前缀符有很多种, 具体看https://en.bitcoin.it/wiki/List_of_address_prefixes
'00'+ '2b6f3b9e337cedbb7c40839523fb1100709c12f7'
step_04 = 002b6f3b9e337cedbb7c40839523fb1100709c12f7
Step5. 第4步结果, 执行2次SHA256, 取前8位作为校验和
hex_str = [step_04].pack("H*") checksum = Digest::SHA256.hexdigest(Digest::SHA256.digest(hex_str) )[0...8]
checksum = 86b2e90c
Step6. 第4步结果跟第5步结果合并
'002b6f3b9e337cedbb7c40839523fb1100709c12f7' + '86b2e90c' # step_04 + checksum
step_06 = 002b6f3b9e337cedbb7c40839523fb1100709c12f786b2e90c
Step7. Base58编码
Base58是一种独特的编码方式,是Base64的变形,主要用于Bitcoin的钱包地址。相比Base64,Base58去掉了数字 0
,大写字母 O
,大写字母 I
,小写字母 l
, +
和 /
,避免引起视觉混淆。
来个base58算法
def encode_base58(int_val, leading_zero_bytes=0) alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" base58_val, base = '', alpha.size while int_val > 0 int_val, remainder = int_val.divmod(base) base58_val = alpha[remainder] + base58_val end base58_val end
Step8. 第6步结果进行base58编码
step_06 = "002b6f3b9e337cedbb7c40839523fb1100709c12f786b2e90c" leading_zero_bytes = (step_06.match(/^([0]+)/) ? $1 : '').size / 2 # leading_zero_bytes的作用是字母填充 address = ("1" * leading_zero_bytes) + encode_base58(step_06.to_i(16) )
得到 14xfJr1DArtYR156XBs28FoYk6sQqirT2s
,这是一个标准的bitcoin地址,终于大功告成。
思考:通过Bitcoin 地址能反向得到hash160_val么?
汇总代码: gen_addr.rb
可以使用 bitcoin-ruby 生成地址
require 'bitcoin' pri_key, pub_key = Bitcoin.generate_key # 私钥 公钥 # 通过ffi调用OpenSSL得到,很多类库都是这么做的 address = Bitcoin::pubkey_to_address(pub_key)
生成测试网地址
require 'bitcoin' Bitcoin::network = :testnet #使用测试网 pri_key, pub_key = Bitcoin.generate_key address = Bitcoin::pubkey_to_address(pub_key)
在Bitcoin系统中,私钥能得公钥,公钥能得到钱包地址, 私钥=>公钥=>钱包地址,而反向是不可以的。 牢记你的私钥 ,而且 私钥不能修改 , 地址也不能修改 ,谁掌握了私钥谁就拥有了这些币!!!
参考:
How do these OpenSSL commands create a Bitcoin private/key from a ECDSA keypair How to convert an ECDSA key to PEM format
https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses https://en.bitcoin.it/wiki/Address https://en.bitcoin.it/wiki/List_of_address_prefixes https://github.com/liushooter/learn-blockchain/blob/master/gen_addr.rb
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。
- 发表于 2分钟前
- 阅读 ( 2 )
- 学分 ( 0 )
- 分类:比特币
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Java离线生成比特币地址
- Flutter / Dart生成以太坊地址
- 从零开始学习比特币开发:生成地址
- Laravel 生成 Gravatar 头像地址的优雅姿势
- 使用PHP从扩展公钥生成比特币钱包地址
- 学习 btc 钱包私钥、公钥和地址的生成过程
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。