如何用python生成自己的比特币私钥

在加密货币中,私钥允许用户访问其钱包。持有私钥的人完全控制该钱包中数字货币。出于这个原因,你应该保守秘密。如果你真的想自己生成密钥,那么以安全的方式生成密钥是有意义的。在这里,我将介绍私钥,并向你展示如何使用各种加密函数生成自己的密钥。我将在Python中提供算法和代码的描述。

我需要生成私钥吗?

大多数时候你没有。例如,如果你使用Coinbase或Blockchain.info等网络钱包,他们会为你创建和管理私钥。交易所也是如此。

移动和桌面钱包通常也会为你生成私钥,但他们可以选择使用你自己的私钥创建钱包。

那么为什么要生成呢?以下是我的原因:

  • 你想确保没有人知道密钥。
  • 你只想了解有关加密和随机数生成(RNG)的更多信息。

什么是私钥?

形式上,比特币(以及许多其他加密货币)的私钥是一系列32字节。现在,有很多方法可以记录这些字节。它可以是256个1和0(32*8=256)或100个骰子所组成的字符串。它可以是二进制字符串,Base64字符串,WIF密钥,助记符短语,或最后是十六进制字符串。出于我们的目的,我们将使用64个字符长的十六进制字符串。

相同的私钥,以不同的格式编写。

为什么正好是32字节?好问题!你可以看到,要从私有密钥创建公钥,比特币使用ECDSA或椭圆曲线数字签名算法。更具体地说,它使用一个称为secp256k1的特定曲线。

现在,该曲线具有256位的量级,以256位作为输入,并输出256位整数。256位正好是32个字节。因此,换句话说,我们需要32字节的数据来提供给这种曲线算法。

私钥还有一个额外的要求。因为我们使用ECDSA,所以关键应该是正数,并且应该小于曲线的顺序。secp256k1的顺序是FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,它非常大:几乎任何32字节的数字都会比它小。

简单粗暴的方法

那么,我们如何生成一个32字节的整数? 首先想到的是只使用你选择的语言的RNG库。Python甚至提供了一种生成足够位的友好方式:

1
2
3
4
5
6
7
import random
bits = random.getrandbits(256)
# 30848827712021293731208415302456569301499384654877289245795786476741155372082
bits_hex = hex(bits)
# 0x4433d156e8c53bf5b50af07aa95a29436f29a94e0ccc5d58df8e57bdc8583c32
private_key = bits_hex[2:]
# 4433d156e8c53bf5b50af07aa95a29436f29a94e0ccc5d58df8e57bdc8583c32

看起来很好,但实际上,它不是。你看,普通的RNG库不适用于加密,因为它们不是很安全。它们根据种子生成数字,默认情况下,种子是当前时间。这样,如果你大致知道我上面生成的那些位,你需要做的就是暴力破解一些变种。

生成私钥时,你希望非常安全。请记住,如果有人学习私钥,他们可以轻松地从相应的钱包中窃取所有硬币,而你没有机会将其取回。

所以让我们尝试更安全地做到这一点。

密码学上强大的RNG

除了标准的RNG方法,编程语言通常还提供专门用于加密操作的RNG。这种方法通常更加安全,因为它直接从操作系统中提取熵。这种RNG的结果很难再现。你不能通过知道生成时间或种子来做到这一点,因为没有种子。好吧,至少用户不输入种子;相反,它是由程序创建的。

在Python中,密码强的RNG在secrets模块中实现。让我们修改上面的代码,使私钥生成安全!

1
2
3
4
5
6
7
import secrets
bits = secrets.randbits(256)
# 46518555179467323509970270980993648640987722172281263586388328188640792550961
bits_hex = hex(bits)
# 0x66d891b5ed7f51e5044be6a7ebe4e2eae32b960f5aa0883f7cc0ce4fd6921e31
private_key = bits_hex[2:]
# 66d891b5ed7f51e5044be6a7ebe4e2eae32b960f5aa0883f7cc0ce4fd6921e31

这是惊人的。我敢打赌,即使访问我的电脑,你也无法重现这一点。但我们可以更深入了吗?

专业的网站

有些网站会为你生成随机数。我们在这里只考虑两个。一个是random.org ,一个众所周知的通用随机数发生器。另一个是bitaddress.org ,专门用于比特币私钥生成。

random.org可以帮助我们生成密钥吗? 当然,因为他们有生成随机字节的服务 。但是这里出现了两个问题。Random.org声称是一个真正的随机发生器,但你能相信吗? 你能确定它确实是随机的吗? 你能确定所有者不记录所有代的结果,特别是那些看起来像私钥的结果吗? 答案取决于你。哦,你不能在本地运行它,这是一个额外的问题。此方法不是100%安全。

现在,bitaddress.org是一个完全不同的故事。它是开源的,所以你可以看到它的内部代码。它是客户端,因此即使没有Internet连接,你也可以下载并在本地运行它。

那么它是怎样工作的? 它使用你——是的,你自己——作为熵的来源。它会要求你移动鼠标或按随机键。你做得足够长,使得重现结果变得不可行。

通过随机移动鼠标生成熵的过程。大块符号显示了pool。

你是否有兴趣了解bitaddress.org的工作原理?出于学习目的,我们将查看其代码并尝试在Python中重现它。

快速说明:bitaddress.org为你提供压缩WIF格式的私钥,该格式接近我们之前讨论过的WIF格式。出于我们的目的,我们将使算法返回一个十六进制字符串,以便我们以后可以使用它来生成公钥。

Bitaddress:具体细节

Bitaddress以两种形式创建熵:通过鼠标移动和按键压力。我们将讨论两者,但我们将重点关注按键,因为很难在Python lib中实现鼠标跟踪。我们希望最终用户在我们有足够的熵之前键入按钮,然后我们将生成一个密钥。

Bitaddress做了三件事。它初始化字节数组,试图从你的计算机获得尽可能多的熵,它用用户输入填充数组,然后生成一个私钥。

Bitaddress使用256字节数组来存储熵。这个数组是循环重写的,所以当第一次填充数组时,指针变为零,并且填充过程再次开始。

程序从window.crypto启动一个256字节的数组。然后,它写入时间戳以获得额外的4个字节的熵。最后,它获取的数据包括屏幕大小,时区,浏览器插件信息,区域设置等。这给了它另外6个字节。

初始化之后,程序不断等待用户输入以重写初始字节。当用户移动光标时,程序会写入光标的位置。当用户按下按钮时,程序会写入按下的按钮的字符代码。

最后,bitaddress使用累积的熵来生成私钥。它需要生成32个字节。对于此任务,bitaddress使用名为ARC4的RNG算法。程序用当前时间初始化ARC4并收集熵,然后逐个获取32次字节。

这完全是对程序运作方式的过度简化,但我希望你能得到这个想法。你可以在Github上详细查看算法。

自己动手吧

为了我们的目的,我们将构建一个更简单的bitaddress版本。首先,我们不会收集有关用户机器和位置的数据。其次,我们将仅通过文本输入熵,因为使用Python脚本持续接收鼠标位置非常具有挑战性(如果你想这样做,请检查PyAutoGUI)。

这将我们带到了我们的生成器库的正式规范。首先,它将使用加密RNG初始化一个字节数组,然后它将填充时间戳,最后它将填充用户创建的字符串。种子池填满后,库将让开发人员创建一个密钥。实际上,他们将能够创建任意数量的私钥,所有私钥都由收集的熵保护。

初始化池

这里我们从加密RNG和时间戳中放入一些字节。__seed_int__seed_byte是两个将熵插入池数组的辅助方法。请注意,我们使用secrets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def __init_pool(self):
for i in range(self.POOL_SIZE):
random_byte = secrets.randbits(8)
self.__seed_byte(random_byte)
time_int = int(time.time())
self.__seed_int(time_int)
def __seed_int(self, n):
self.__seed_byte(n)
self.__seed_byte(n >> 8)
self.__seed_byte(n >> 16)
self.__seed_byte(n >> 24)
def __seed_byte(self, n):
self.pool[self.pool_pointer] ^= n & 255
self.pool_pointer += 1
if self.pool_pointer >= self.POOL_SIZE:
self.pool_pointer = 0

输入种子

这里我们首先放置一个时间戳,然后输入字符串。

1
2
3
4
5
6
def seed_input(self, str_input):
time_int = int(time.time())
self.__seed_int(time_int)
for char in str_input:
char_code = ord(char)
self.__seed_byte(char_code)

生成私钥

这部分可能看起来很难,但实际上非常简单。

首先,我们需要使用我们的池生成32字节的数字。不幸的是,我们不能只创建自己的random对象,只能用于密钥生成。相反,有一个共享对象,由在一个脚本中运行的任何代码使用。

这对我们意味着什么?

这意味着在每个时刻,代码中的任何地方,一个简单的random.seed(0)都可以破坏我们收集的所有熵。我们不希望这样。值得庆幸的是,Python提供了getstatesetstate方法。因此,为了在每次生成密钥时保存我们的熵,我们记住我们停下来的状态,并在下次我们想要创建密钥时设置它。

其次,我们只确保我们的键在范围内(1,CURVE_ORDER)。这是所有ECDSA私钥的要求。CURVE_ORDER是secp256k1曲线的顺序,它是FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141

最后,为方便起见,我们转换为十六进制,并剥离'0x'部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def generate_key(self):
big_int = self.__generate_big_int()
big_int = big_int % (self.CURVE_ORDER — 1) # key < curve order
big_int = big_int + 1 # key > 0
key = hex(big_int)[2:]
return key
def __generate_big_int(self):
if self.prng_state is None:
seed = int.from_bytes(self.pool, byteorder=’big’, signed=False)
random.seed(seed)
self.prng_state = random.getstate()
random.setstate(self.prng_state)
big_int = random.getrandbits(self.KEY_BYTES * 8)
self.prng_state = random.getstate()
return big_int

行动

我们试着使用这个库。实际上,它非常简单:你可以使用三行代码生成私钥!

1
2
3
4
kg = KeyGenerator()
kg.seed_input(‘Truly random string. I rolled a dice and got 4.’)
kg.generate_key()
# 60cf347dbc59d31c1358c8e5cf5e45b822ab85b79cb32a9f3d98184779a9efc2

你可以自己看看。密钥是随机的,完全有效。而且,每次运行此代码时,都会得到不同的结果。

结论

如你所见,有很多方法可以生成私钥。它们的简单性和安全性不同。

生成私钥只是第一步。下一步是提取可用于接收付款的公钥和钱包地址。

如果你想使用代码,我将它发布到这个Github存储库

======================================================================

如果你想学习区块链并在Blockchain Technologies建立职业生涯,那么请查看我们分享的一些以太坊、比特币、EOS、Fabric等区块链相关的交互式在线编程实战教程:

  • java以太坊开发教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
  • python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
  • php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和交易等内容。
  • 以太坊入门教程,主要介绍智能合约与dapp应用开发,适合入门。
  • 以太坊开发进阶教程,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
  • ERC721以太坊通证实战,课程以一个数字艺术品创作与分享DApp的实战开发为主线,深入讲解以太坊非同质化通证的概念、标准与开发方案。内容包含ERC-721标准的自主实现,讲解OpenZeppelin合约代码库二次开发,实战项目采用Truffle,IPFS,实现了通证以及去中心化的通证交易所。
  • C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和交易等。
  • java比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Java代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Java工程师不可多得的比特币开发学习课程。
  • php比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Php代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Php工程师不可多得的比特币开发学习课程。
  • c#比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在C#代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是C#工程师不可多得的比特币开发学习课程。
  • EOS入门教程,本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。
  • 深入浅出玩转EOS钱包开发,本课程以手机EOS钱包的完整开发过程为主线,深入学习EOS区块链应用开发,课程内容即涵盖账户、计算资源、智能合约、动作与交易等EOS区块链的核心概念,同时也讲解如何使用eosjs和eosjs-ecc开发包访问EOS区块链,以及如何在React前端应用中集成对EOS区块链的支持。课程内容深入浅出,非常适合前端工程师深入学习EOS区块链应用开发。
  • Hyperledger Fabric 区块链开发详解,本课程面向初学者,内容即包含Hyperledger Fabric的身份证书与MSP服务、权限策略、信道配置与启动、链码通信接口等核心概念,也包含Fabric网络设计、nodejs链码与应用开发的操作实践,是Nodejs工程师学习Fabric区块链开发的最佳选择。
  • Hyperledger Fabric java 区块链开发详解,课程面向初学者,内容即包含Hyperledger Fabric的身份证书与MSP服务、权限策略、信道配置与启动、链码通信接口等核心概念,也包含Fabric网络设计、java链码与应用开发的操作实践,是java工程师学习Fabric区块链开发的最佳选择。
  • tendermint区块链开发详解,本课程适合希望使用tendermint进行区块链开发的工程师,课程内容即包括tendermint应用开发模型中的核心概念,例如ABCI接口、默克尔树、多版本状态库等,也包括代币发行等丰富的实操代码,是go语言工程师快速入门区块链开发的最佳选择。

汇智网原创翻译,转载请标明出处。这里是如何用python生成自己的比特币私钥