比特币私钥是每个比特币钱包都有的数字秘密。这个256位的数字可以用几种格式表示:十六进制-256位,十六进制是32个字节,或0-9或a-f范围内的64个字符,Base64字符串,WIF键或助记短语。
例如:
e 9873d 79 c 6d 87 DC 0 FB 6a 5778633389 f 4453213303 da 61 f 20 BD 67 fc 233 aa 33262
第一种方法
生成32字节整数最简单的方法是使用你所知道的语言中的RNG库。以下是Python中的一些例子:
bits=random.getrandbits(256)
# 30848827712021293731208415302456569301499384654877289245795786476741155372082
bits_hex=十六进制(位)
#0x 4433d 156 E8 c 53 BF 5b 50 af 07 aa 95a 29436 f 29 a 94 e 0 cc C5 d 58 df 8 e 57 BDC 8583 c 32
private_key=bits_hex[2:]
# 4433d 156 E8 c 53 BF 5b 50 af 07 aa 95a 29436 f 29 a 94 e 0 cc C5 d 58 df 8 e 57 BDC 8583 c 32
然而,公共RNG库并不是生成密钥的最安全的选择。因为生成的字符串基于种子,所以种子表示当前时间。如果你知道时间,你可以对它进行几次猛烈的攻击。
密码强大的RNG
除了标准的RNG方法,编程语言还为特定的加密任务提供了RNG。由于RNG是由操作系统直接生成的,因此这种方法具有很高的安全性。
这使得RNG的繁殖更加困难,因为你无法确定时间或种子。甚至他都不需要种子,因为是程序自己创造的。
在Python中,可以在secret模块中实现加密的强RNG。
bits=secrets.randbits(256)
#46518555179467323509970270980993648640987722172281263586388328188640792550961
bits_hex=十六进制(位)
#0x 66d 891 b 5 ed 7 f 51 e 5044 be 6a 7 ebe 4 e 2e EAE 32 b 960 f 5aa 0883 f 7 cc 0 ce 4 FD 6921 e 31
private_key=bits_hex[2:]
# 66d 891 b5 ed 7 f 51 e 5044 be 6a 7 ebe 4 e 2e ea 32 b 960 f 5 aa 0883 f 7 cc 0 ce 4 FD 6921 e 31
专题网站
有几个网站可以为你随机生成这些数字。Random.org是一个出于各种目的随机生成数字的网站。另一个受欢迎的网站isbitaddress.org是专门用来生成比特币私钥的。
因为你无法知道random.org是否保存或记录任何生成的数字,这不是一个安全的选择。
然而,Bitaddress.org是一个开源网站,这意味着你可以检查它的代码来了解它的功能,并以离线模式下载和运行它。
这个程序使用鼠标或键的移动来产生熵(热力学函数)。这使得复制你的结果变得非常不可能。
然后,私钥以压缩的WIF格式传递,但是我们将使算法返回一个十六进制字符串,稍后生成公钥时将需要它。
Bitaddress首先初始化字节数组,试图从计算机中获得尽可能多的熵。它用用户输入填充数组,然后生成私钥。该服务使用一个256字节的数组来存储熵。这个数组是用循环填充的,所以当数组第一次被填充时,指针被重置为零,数组会再次被填充。
从窗口启动阵列后。它写一个时间戳来产生额外的4个字节的熵。它收集屏幕大小、时区、浏览器插件信息、地区等数据再加6个字节。
然后,在初始化之后,程序反复等待用户输入来重写初始字节。当光标移动时,光标的位置被写入。当按钮被按下时,被按下按钮的字符码由程序写入。
RNG算法生成的32字节私钥的累积熵称为ARC4。
DIY版
您也可以创建自己版本的Bitaddress。我们不会收集有关用户电脑和位置的数据。熵只会由文本产生,因为通过Python脚本初始化光标位置是相当困难的。
字节数组将用加密的RNG初始化,然后用时间戳填充,再用用户生成的字符串填充。
填充第二个种子池后,库将允许您创建密钥。
初始化连接池
我们从加密的RNG中插入几个字节和一个时间戳。__seed_int和__seed_byte是将熵插入池数组的两种方法。我们还将在示例中使用secrets模块。
def __init_pool(self):
因为我在范围内(自我。POOL_SIZE):
random_byte=secrets.randbits(8)
自我。_ _种子字节(随机字节)
time_int=int(time.time())
自我__seed_int(time_int)
def __seed_int(self,n):
自我。_ _种子字节(名词)
自我__seed_byte(n》 8
自我_ _种子_字节(n)》16
自我_ _种子_字节(n)》24
def __seed_byte(self,n):
^=n 255
self.pool_pointer=1
如果自我。pool _ pointer"》=self .POOL_SIZE:
self.pool_pointer=0
在这里,我们插入一个时间戳,然后输入字符串的每个字符。
定义种子_输入(self,str_input):
time_int=int(time.time())
自我__seed_int(time_int)
对于字符串输入中的字符:
char_code=ord(char)
自我。_ _种子字节(字符代码)
生成私钥
为了用我们的池生成一个32字节的数字,我们必须使用一个共享对象,它被运行在一个脚本中的任何代码所使用。
为了节省每次生成键时的熵,我们将记住在此停止的状态,并为下一次生成键设置状态。
现在我们只需要确保我们的键在范围(1,曲线_顺序)内,这是ECDSA私钥所必需的。曲线的阶数是secp256k1曲线的阶数。
我们将把密钥转换为十六进制,并删除"0x"部分。
def generate_key(self):
big_int=self .__generate_big_int()
big_int=big_int %(自我).曲线顺序— 1) #键《曲线顺序
big _ int=big _ int 1 # key"0
key=hex(big_int)[2:]
回车键
def __generate_big_int(self):
如果self.prng_state为无:
seed=int.from_bytes(self.pool,byteorder='big 'signed=False)
随机种子(种子)
自我。prng _ state=random。getstate()
随机的。设定状态(自我。prng _ state)
big _ int=随机。getrandbits(self .密钥字节* 8)
自我。prng _ state=random。getstate()
返回大整数
为了使用该库,您可以使用以下代码生成私钥:
kg=密钥生成器()
千克种子_输入
kg.generate_key()
# 60cf 347 DBC 59d 31 c 1358 c8e 5 cf 5 e 45 b 822 ab 85b 79 CB 32 a9 f3d 98184779 a9 EFC 2
您将注意到,每次运行代码时,您都会得到不同的结果。
结论
根据安全性和实现的容易程度不同,有许多方法可以帮助您生成私钥。