如何使用ECDSA创建公钥

区块链

580人已加入

描述

什么是私钥?

一般我们看到的私钥是这样的一段字符串:5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss

支持比特币协议的应用都可以正确把这段字符串转换成比特币的私钥,再转换出公钥,再得到一个地址,如果该地址上面有对应的比特币,就可以使用这个私钥花费上面的比特币。

私钥本质上是随机数私钥本质上是一个随机数,由32个byte组成的数组,1个byte等于8位二进制,一个二进制只有两个值0或者1。所以私钥的总数是将近2^(8*32)=2^256个,但是有一些私钥并不能使用,他真实的大小是介于:1 ~ 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141之间的数。这个数量已经超过了宇宙中原子的总数,想要遍历所有的私钥,耗尽整个太阳的能量也是不可能的。

我们所说的比特币私钥的是密码学上面安全的,并不是说不可能出现重复的私钥,而是说不可能通过遍历的方式找到某一个特定的私钥,或者通过其它的方式找,而不通过私钥就能花费地址上面的比特币,私钥的安全性是由数学上保证的。

私钥的总数量很大,但是私钥的生成是依赖随机数的,真正的随机是很难做到的,大部分私钥的生成都是依赖于伪随机算法(PRNG)。

伪随机是用函数生成随机数。它并不真正是随机的。只是一个比较近似真随机的随机数。

私钥生成的随机性就很重要的,密码学上安全的随机是指:

随机是不可预测的,随机的结果是不可遍历的,如果不是安全的随机数生成器,生成的私钥就有可能被别人碰撞到。不依赖随机生成的私钥就会大大的降低其生成的概率空间。

什么是公钥?

公钥是由数字和字母组成的另一个地址,这些数字和字母是通过使用数学函数加密后从私钥派生出来的。加密过程是不可逆转的,因此没有人能够找到原始的私钥。这个地址可以让你接收比特币。

公钥的哈希值总是1,它看起来是这样的:1 bvbmseystwetqtfn5au4m4gfg7xjanvn2

这个地址您可以公开提供,以便接收比特币。用户可以生成的公共地址数量没有限制。为了生成这样的密钥并随后生成钱包地址,必须对私钥进行多次转换。这些转换称为哈希函数,是不可逆的转换。

使用ECDSA创建公钥

你要做的第一件事就是将ECDSA应用到你的私钥上,也就是椭圆曲线数字签名算法。定义的一个椭圆曲线方程为y²= x³+ ax + b, a和b为选定值。比特币利用的是secp256k1曲线。

对私钥应用ECDSA将得到一个64字节的整数,该整数由两个32字节的整数组成,它们表示椭圆曲线上点的X和Y。

下面是用Python语言编写的代码:

private_key_bytes = codecs.decode(private_key, ‘hex’)

# Get ECDSA public key

key = ecdsa.SigningKey.from_string(private_key_bytes, curve=ecdsa.SECP256k1).verifying_key

key_bytes = key.to_string()

key_hex = codecs.encode(key_bytes, ‘hex’)

在上面给出的代码中,使用编程器对私钥进行解码。在Python中,至少有两个类可以保存私钥和公钥:“str”、字符串数组和“bytes”——字节数组,事情可能会变得有点混乱。

这是因为X字符串数组不等于X字节数组,但它等于有两个元素的字节数组O《。codecs.decode方法将字符串转换成字节数组。

在应用ECDSA之后,我们必须将字节0x04(04作为前缀)添加到生成的公钥中。这将生成一个完整的比特币公钥。

压缩公钥

我们可以将公钥压缩得更短,而不是使用公钥的长版本。

这是通过从ECDSA公钥中获取X并在Y的最后一个字节是偶数时添加0x02,如果最后一个字节是奇数,则添加0x03字节。

使用SHA-256和RIPEMD-160加密密钥

现在我们继续创建钱包地址。不管应用于公钥的方法是什么,过程都是相同的。显然,您将得到不同的结果地址。

为此,我们需要应用两个哈希函数: 首先,我们将SHA-256应用于公钥,然后使用RIPEMD-160加密结果。非常重要的是,算法应用的顺序要准确。

在这个过程的最后,您将得到一个160位整数,它表示加密的公钥。

下面是在Python中加密公钥所需的代码:

public_key_bytes = codecs.decode(public_key, ‘hex’)

# Run SHA-256 for the public key

sha256_bpk = hashlib.sha256(public_key_bytes)

sha256_bpk_digest = sha256_bpk.digest()

# Run RIPEMD-160 for the SHA-256

ripemd160_bpk = hashlib.new(‘ripemd160’)

ripemd160_bpk.update(sha256_bpk_digest)

ripemd160_bpk_digest = ripemd160_bpk.digest()

ripemd160_bpk_hex = codecs.encode(ripemd160_bpk_digest, ‘hex’)

添加网络字节

由于比特币有两个网络,主网和测试网,我们需要创建一个地址在主网使用。这意味着我们必须向加密的公钥中添加0x00字节。对于测试网的使用,您必须添加0x6f字节。

计算校验和

下一步是计算得到的主网密钥的校验和。校验和确保密钥在整个过程中仍然保持其完整性。如果校验和不匹配,地址将被标记为无效。

为了生成密钥的校验和,必须应用SHA-256哈希函数两次,然后从这个结果中取前4个字节。请记住,4个字节代表8个十六进制数字。

计算校验和所需的代码是:

# Double SHA256 to get checksum

sha256_nbpk = hashlib.sha256(network_bitcoin_public_key_bytes)

sha256_nbpk_digest = sha256_nbpk.digest()

sha256_2_nbpk = hashlib.sha256(sha256_nbpk_digest)

sha256_2_nbpk_digest = sha256_2_nbpk.digest()

sha256_2_hex = codecs.encode(sha256_2_nbpk_digest, ‘hex’)

checksum = sha256_2_hex[:8]

创建地址所需的最后一步是合并主网密钥和校验和。

用Base58编码密钥

您将注意到,生成的密钥看起来不像其他BTC地址。这是因为大多数将它们转换为Base58地址。

下面是将十六进制地址转换为Base58地址所需的算法:

ef base58(address_hex):

alphabet = ‘123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz’

b58_string = ‘’

# Get the number of leading zeros

leading_zeros = len(address_hex) — len(address_hex.lstrip(‘0’))

# Convert hex to decimal

address_int = int(address_hex, 16)

# Append digits to the start of string

while address_int 》 0:

digit = address_int % 58

digit_char = alphabet[digit]

b58_string = digit_char + b58_string

address_int //= 58

# Add ‘1’ for each 2 leading zeros

ones = leading_zeros // 2

for one in range(ones):

b58_string = ‘1’ + b58_string

return b58_string

结果字符串将代表压缩的比特币钱包地址。

结论

如果您密切关注上述步骤,那么从私钥生成比特币钱包地址的过程并不困难。如果您的私钥已满或已压缩,即使生成的地址将看起来不同,但它们都是有效的。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分