使用Ruby生成bitcoin的秘钥,公钥以及签名

TL;NR

  1. 随机生成不大于n = 1.158 * 1077(略小于2^256)的随机数作为秘钥k。

  2. 使用椭圆曲线算法从秘钥k生成公钥K。K = k * G(G是椭圆曲线上的点,*是定义在椭圆曲线上的乘法运算,G固定,相当于对G做k次椭圆上的加法运算)

  3. 使用SHA256以及RIPEMD160从公钥K生成地址A。

秘钥的生成

已经说过秘钥是一个不大于n = 1.158 * 1077(略小于2^256)的随机数。一般来说由操作系统的随机熵生成。很多钱包在生成秘钥的时候要求拖拽鼠标之类的行为,就是为了获取随机熵。

从秘钥生成公钥

采用特有的椭圆曲线secp256k1 curve从秘钥生成公钥。

1
k = K * G

在椭圆曲线上,我们可以定义一种加法,在这种加法下,两点的和相当于这两点在椭圆曲线上连线与椭圆曲线的交点。

这样,在椭圆曲线上的一个点的自相加,其和相当于从自己的位置做切线,切线与椭圆曲线相交的点的关于x轴的对称点。

下图就是把一个点G自相加多次的演示。

这样,从密钥生成公钥K就是重复上述的运算k次。

从公钥生成地址

地址相当于对数字签名。

1
A=RIPEMD160(SHA256(K))

SHA256和RIPEMD160是两个hash算法。具体就不展开了。

使用Ruby生成秘钥和公钥

已经有现成的gem可以使用,所以不需要自己重复造轮子。

1
gem install ecdsa

唯一需要注意的是,SecureRandom.random_number不一定secure和不一定非常random。

1
2
3
4
5
6
7
8
9
10
require 'ecdsa'
require 'securerandom'
group = ECDSA::Group::Secp256k1
private_key = 1 + SecureRandom.random_number(group.order - 1)
puts 'private key: %#x' % private_key

public_key = group.generator.multiply_by_scalar(private_key)
puts 'public key: '
puts ' x: %#x' % public_key.x
puts ' y: %#x' % public_key.y

以上。