加密货币杂谈(一):创生与加密

其实这是一个钱包制作教程(不)

本人和比特币

其实写下这个标题的时候我还挺害怕有人觉得我进了诈骗团伙的,不过我更多的还是想从旁观者的角度写一下加密货币和区块链,顺便聊聊现在互联网上到处充斥的,让人厌烦的 DeFi。假如这个系列的文章可以帮到哪怕一个对加密货币有兴趣的人,拯救一个可能陷入加密货币合约深渊的人,那么这些码字的时间就不仅仅是自娱自乐。

其实我和比特币的渊源应该始于 2010 年的某个夏天(也许是秋天),班级里的一位董姓同学在聊天中提到了比特币,并且发表了对其未来前景的巨大期待,认识我的人应该知道这是哪位神仙。我当时的第一反应是 “小可爱”。作为一个稚气未脱的青少年,当时的自己不但对密码学一无所知,对微观/宏观经济依然一无所知,更对人性一无所知,所以只是应和了一下。不过好奇心驱使之下,在那个周末我还是照着网上的 Step-by-Step 教程在家里的破电脑上挂了个 Miner 开始挖币。

后来接触比特币的人应该无法想象当时有多容易挖币,没记错那会还是单 GPU 挖的动的时代,很短时间内我就挖了数十个币,然后就再也没有打开那个 Miner。直到不久之后电脑重装,那几十个币就随着数据消散在这片星空里了。后来再一次接触 BTC 应该是 15 年那轮牛市的时候,在大学的寝室里尝试下了一个开源的 Miner 挖了挖,发现收益几乎为 0,就完全忘记这回事情了。后面的事情大家也都知道了,比特币的挖掘很快进入了单矿工贡献归零的时代,挖比特币这件事情再也不属于普通人了。最后就是趁着今年春节的空闲,我再次花了一些时间看了一下加密货币这些年的发展和历史,倒觉得这是一个相当有意思的历史故事了。

聊到这里,我并不是惋惜错过了一笔千万巨款,而是惊讶于通过未来的回看,我们会看到一个多么光怪陆离的世界。这也是为什么在加密币成为路边老太都能说上两句的东西的时候,我一直拒绝再次进入这个市场的原因之一(恐惧亦为没有投资才能的一种);当然另一个拒绝的理由是 DeFi 本身的恶。我会尝试在未来的更新谈谈里对 DeFi,山寨币,合约这些东西的个人看法。

把话题拉回来,让我们来聊聊加密货币的创生与加密。

原初的创世

很多人在提到加密货币和区块链的时候经常会提到创世,无论是创世区块还是创世交易,亦或者是比特币这个被尊为创世货币本身的存在。但是我想说的是,一个人只要对 中本聪 (サトシナカモト) 创世论文 Bitcoin: A Peer-to-Peer Electronic Cash System 进行过最粗略的主题阅读,就不可能忽视在论文引用列表之首的 “b-money”。这里不得不提到其作者,Dai Wei

Dai Wei 的个人主页,我们可以看到他引以为豪的成就主要集中于密码学和匿名技术,而在 “b-money” 本篇里更是直接描述了现代加密货币的三大根基。在文章内容 The creation of money 中首次提出了工作证明Proof of Work的概念:

Anyone can create money by broadcasting the solution to a previously unsolved 
computational problem. The only conditions are that it must be easy to determine 
how much computing effort it took to solve the problem and the solution 
must otherwise have no value, either practical or intellectual.

任何人都可以通过广播以前未解决的计算问题的解决方案来赚取加密货币。唯一的条件是必须很容易确定
为了解决这个问题消耗了多少算力,否则这个解决方案将毫无价值。

而在 The transfer of money 交易的定义里,则直接提出了广播的雏形,而这毫无疑问可以认为是后世加密货币交易算法的核心概念:

If Alice (owner of pseudonym K_A) wishes to
transfer X units of money to Bob (owner of pseudonym K_B), she broadcasts
the message "I give X units of money to K_B" signed by K_A. Upon the
broadcast of this message, everyone debits K_A's account by X units and
credits K_B's account by X units, unless this would create a negative
balance in K_A's account in which case the message is ignored.

如果 Alice(笔名 K_A 的所有者)希望转账 X 单位的钱给 Bob(化名 K_B 的所有者),
她将广播由 K_A 签名的消息“我给 K_B X 个单位的钱”。经这条消息的广播,每个人都从K_A的
账户中扣除X个单位,并且以 X 单位记入 K_B 的帐户,除非这会导致 K_A 帐户中的余额变成负数,
而在这种情况下,交易广播将被忽略。

而令人震惊的是,“b-money” 这篇文章发布于 1998 年。这也是我个人更倾向于将 Dai Wei 认定为是区块链和加密货币的那位炼就风火雷电大千世界之人。

10 年后的创世论文 Bitcoin: A Peer-to-Peer Electronic Cash System (比特币白皮书) 更像是一个集大成者,在实践的意义上真正定义了加密货币从 挖掘 - 验证 - 一致性 - 网络协议 - 交易 的完整链条。我无意于抄一遍白皮书内容到博客,但是我确实希望每一个对区块链有兴趣的人读一下白皮书,白皮书早已被翻译成了多种语言的版本,中文版详见 比特币白皮书 - zh_cn

PS 白皮书中一定要仔细阅读交易时间戳这两个个章节的描述,这就是信任交易和根本定义。

至于后续比特币的价格神话,那就是另一个庸俗的脂粉故事了。

小窥密码学

终于来到了正题,加密货币里的密码学。我觉得对多数读者来说,经典密码学著作的内容如果长篇累牍的出现在任何一篇博客里,符合直觉的做法一定是直接关闭页面。所以我想通过更有趣的,手把手的方法,来让大家对密码学在区块链的作用有一丢丢的察觉。因此我觉得手把手制作一个属于自己的冷钱包就非常合适。这个过程不涉及太多的复杂密码学知识,同时又足够有趣,有足够的正反馈,作为回报可以收获一个非常安全的比特币冷钱包,也不算是浪费太多时间。

对于那些对密码学有兴趣的怪胎,我无责任推荐以下相对公认的入门课程:

至于比特币钱包的制作过程,下面几个加密算法是强烈建议看一下的,这会对理解整个钱包的制作有巨大帮助。目前比特币使用了SECP256K1SHA256RIPEMD-160Base58 等加密算法。其中SECP256K1属于椭圆曲线签名算法(ECDSA);SHA-256RIPEMD-160属于 HASH 摘要算法;Base58 则是比特币自己定义的编码方式,去除了Base64编码中的特殊字符和容易看错的字符。如果你理解的够深刻,甚至可以不借助任何现成的函数包,在程序中直接手撸一个比特币钱包生成函数。下面来看看各个算法的视频讲解:

什么是 SECP256K1 椭圆曲线签名算法(ECDSA)

Blockchain tutorial 11: Elliptic Curve key pair generation


什么是 SHA-256 加密算法

SHA 256 | SHA 256 Algorithm Explanation


什么是 RIPEMD-160 加密算法

Hash Function: RIPEMD-160


什么是 BASE-58 加密算法

Blockchain tutorial 13.1: Base-58 encoding


当然,以上内容我自己都没完全看完。而密码学的探索是无止尽的深渊,真诚建议量力而行。

制作比特币冷钱包

这里我们以 Python 为例,有两种方法可以比较快捷的创造一个本地的冷钱包。

其中最简单的一种是使用 bitcoin 包来直接创建,这么做的好处是没几行代码就可以瞬间构建一个你自己的比特币冷钱包。而稍微能够暴露钱包生成过程的方法的话,就是用 esdca, hashlib, base58 这些密码库来一步步制作钱包。

0. 到底他妈的什么是钱包

我认为钱包这个叫法烂透了。因为现在大家口中的加密货币钱包本质是 一对密钥对 + 以此生成的地址字符串。这东西要更合适的说法应该用地址凭证可能会更好。无论是英语还是其他语言翻译里叫做钱包都挺让人有歧义。这东西本质是一个在交易链上证明拥有该地址字符串的凭证。里面既没有存钱,也没有容量。

所谓的钱包余额,只是整个交易链上所有经过这个地址,并且被其所对应的公钥加密的交易广播记录的 unit 总和,且这个 unit 永不为负。当然,如果不想纠结这么多,单纯理解成现实意义的钱包也不是不行,只是这个钱包需要用公私密钥对或者由此衍生的助记词-密码对来证明拥有权限。

1. 使用 bitcoin 快速生成冷钱包

如果使用 bitcoin 是如此的简单,以至于仅需要以下几步:

安装 Python3

请根据 Python Setup and Usage 的指引来进行安装。

安装 pip

请根据 pip install 的指引来进行安装。

安装 bitcoin

pip install bitcoin

创建一个 Python 文件,并填入以下内容来利用 bitcoin 包生成公私钥匙对并生成钱包地址

touch WalletGen.py
vim WalletGen.py

在文件 WalletGen.py 中写入以下内容并运行 python3 WalletGen.py

from bitcoin import *

#生成私钥
priv_key = random_key()
print("私钥:", priv_key)

#使用私钥生成公钥
pub_key = privtopub(priv_key)
print("公钥:", pub_key)

#使用公钥生成地址
address = pubtoaddr(pub_key)
print("地址:", address)

如果一切顺利你将得到类似这样一个结果

私钥: b8cebbff9b1f23554a3ff0854dc8e061861e7fa62510af9c013c29880ade9149
公钥: 04cde2815421ebbc1c843ce0391583d05f5dbf511afa591303ad6aff5115bb11ae18e8d8227ceef05766ddaa9cf385b428cb7b22e5e133da4075954be416520885
地址: 13F7uqbhS2ja18PDGbYCpmY8QRdQP6qZDU

这里的地址就是你全新的冷钱包的地址了,我们可以前往 blockchain.com 进行验证

check_btc.png

2. 使用加密函数包来生成冷钱包

除了使用 bitcoin 这样的懒人包,其实我们可以用一些更加接近钱包生成算法的过程来实现冷钱包的制作。在开始之前我们先看一下比特币钱包的计算流程:

how_to_btc_wallet.png

然后让我们开始按照下面的步骤动手制作新的比特币钱包:

首先安装各类必要的加密库和字符处理库

pip install hashlib ecdsa base58 binascii

生成一个新的 WalletGen2.py 文件,写入以下脚本

import hashlib
import ecdsa
import base58
import binascii

# 使用 ECDSA 库生成一个私钥:
private_key = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1)
print("ECDSA PrivateKey: ", private_key.to_string().hex())

# 从私钥生成一个新的公钥:
public_key = '04' + private_key.get_verifying_key().to_string().hex()
print("ECDSA PublicKey: ", public_key)

# 获取公钥的SHA256哈希值:
hash_public_key = hashlib.sha256(binascii.unhexlify(public_key)).hexdigest()
print("SHA256 - ECDSA PublicKey: ",hash_public_key)

# 对上一步获得的哈希值,再次进行 RIDEMP160 哈希计算:
ripemd_public_key = hashlib.new('ripemd160', binascii.unhexlify(hash_public_key))
print("RIDEMP160 - SHA256 - ECDSA PublicKey: ", ripemd_public_key.hexdigest())

# 在 RIDEMP160 哈希值得头部添加一个网络类型比特:
versioned_public_key = '00' + ripemd_public_key.hexdigest()
print("Prepend Network Byte to RIDEMP160: ", versioned_public_key)

# 对带有头比特的 RIDEMP160 做两次 SHA256 哈希:
hash = versioned_public_key
for x in range(1, 3):
    hash = hashlib.sha256(binascii.unhexlify(hash)).hexdigest()
    print("\t|  >SHA256 #", x, " : ", hash)

# 截取两次 SHA256 后的哈希值的头 4 个字节并且添加到 带有头比特的 RIDEMP160 的尾部
checksum = hash[:8]
append_checksum = versioned_public_key + checksum
print("Checksum first 4 bytes: ", checksum)
print("Append Checksum to RIDEMP160: ", append_checksum)

# 用 BASE58 加密延长后的有头比特的 RIDEMP160 哈希,获得比特币钱包地址:
btc_address = base58.b58encode(binascii.unhexlify(append_checksum))
print("BitCoin Wallet Address: ", btc_address.decode('utf8'))

# 利用私钥转换获得用于导入各种钱包软件的 WIF 密钥 (例如 imToken 等)
private_key_hex = '80' + private_key.to_string().hex()
first_sha256 = hashlib.sha256(binascii.unhexlify(private_key_hex)).hexdigest()
second_sha256 = hashlib.sha256(binascii.unhexlify(first_sha256)).hexdigest()
final_key = private_key_hex + second_sha256[:8]
WIF = base58.b58encode(binascii.unhexlify(final_key))
print("*** This WIF key could be import to any wallet app (eg. imToken) ***")
print("Private Key WIF: ", WIF.decode('utf8'))

运行上面的新脚本我们可以得到以下内容:

ECDSA PrivateKey:  d405813b38050471677c03431f64a1769736677de8fe264ed30377ccb45b4cf0
ECDSA PublicKey:  04a81282bbdd4d5034e762e272eee45bf7cf989a8b5760909cf6a6f1c53a5fd60a6fa1f0e640b5e877599d4d0783d0707e82273458758c48406efa6f486eabe7b1
SHA256 - ECDSA PublicKey:  063a742946b430411855e3fa6c9a43d1312d1a199e8bc5f32c0f56b9096b633d
RIDEMP160 - SHA256 - ECDSA PublicKey:  65646a8b7e051a28aa0fae829d9bf6c880f570cd
Prepend Network Byte to RIDEMP160:  0065646a8b7e051a28aa0fae829d9bf6c880f570cd
        |  >SHA256 # 1  :  ef7c802427b65d8d5e7900cf44f7f8a84e17d786f03d2b908d4df6cc55b2d80e
        |  >SHA256 # 2  :  16c210b39dd7fb2229162450a371d9af25e6c0a6cfed5da2ef63ee1a0b1cf542
Checksum first 4 bytes:  16c210b3
Append Checksum to RIDEMP160:  0065646a8b7e051a28aa0fae829d9bf6c880f570cd16c210b3
BitCoin Wallet Address:  1AF7YR2ADVwjNv6rhV6vkBpATJoicKrqJr
*** This WIF key could be import to any wallet app (eg. imToken) ***
Private Key WIF:  5KRfPMacY6ahNb6kBFAVBgzYPXipsWNzCBEd31p7uiD2VTu4aQ4

我们可以再次前往 blockchain.com 进行地址验证

check_btc2.png

也可以将 WIF 导入 imToken 等软件进行后续的交易等行为

详细可以参考 Wallet import format

3. 別人的才是最好的

事实上不管你怎么样努力的去写一个尽善尽美的钱包生成脚本,结果都会是一个破破烂烂简陋不堪的东西。如果真的希望有一个趁手的工具包可以帮你生成任意想要的钱包,不限于比特币、以太坊这种主流钱包,那么我建议尽快前往 Top Wallet Generator 页面,找个 Star 数量高的成熟生成工具。本博客提供的脚本主要还是为了展示比特币钱包的生成原理和过程。

结语

到这里为止,如果你跟着上面的步骤一步步做下来的话,应该已经成功获得第一个本地的冷钱包了。甚至可以多生成几个构成你自己的钱包组合来完成一些更有趣的交易操作。

那么在下一篇文章 加密货币杂谈(二):Mining 里我会详细讲讲如何最没有门槛的开始挖你第一个毫无意义且无法提现0.00000001 BTC