共计 8286 个字符,预计需要花费 21 分钟才能阅读完成。
比特币钱包波及钱包程序和钱包文件。钱包程序创立公钥来承受比特币 (satoshis) 付款,并应用对应的私钥来花掉比特币。钱包文件保留私钥和其余与钱包程序相干的交易信息(可选)。
钱包程序 Wallet Programs
容许承受和领取比特币是钱包软件的惟一性能,然而一个特定的钱包程序不须要同时做这两件事,两个钱包程序能够一起工作,一个程序散发公钥来接管比特币,一个程序进行交易签名来领取这些比特币。
钱包程序也须要和 peer-to-peer 网络进行交互,以从区块链中取得信息并播送出新的交易。当然,散发公钥和交易签名程序并不需要和 peer-to-peer 网络自身进行交互。
因而钱包零碎 (wallet system) 就有三个必须的,然而缺能够独立的局部:一个公钥散发程序,一个签名程序,一个联网程序。
<!–more–>
NOTE: 这里说的是公钥散发的通常情景。在一些状况下,P2PKH 和 P2SH 的散列值将被散发来代替公钥的散发,理论的公钥只有在他们管制的 output 被领取时才散发。
下面和上面说的输入 outputs,通常就是指 未应用的交易输入 unspent transaction outputs 缩写是 UTXO,就是比特币。
残缺性能的钱包 Full-Service Wallets
最简略的钱包是一个执行三个性能的程序:
- 生成私钥,并派生对应的公钥,并在须要时候发这些公钥;
- 监控领取给这个公钥的 outputs,在领取 outputs 时,创立交易和进行交易签名;
- 播送曾经实现签名的交易。
当初简直所有风行的 BTC 钱包都是Full-Service Wallets。
Full-Service Wallets的长处是容易应用,独自的一个程序能够实现用户领取和接管比特币的全副工作。
Full-Service Wallets的毛病是,他们把私钥保留在能够连贯到 Internet 的设施上,因为联网所以这样的设施中的私钥被攻打会很容易。
签名钱包 Signing-Only Wallets
私钥能够保留在一个在更平安环境中的独自的钱包程序中来进步安全性,这些签名钱包和能够与 peer-to-peer 网络交互的联网钱包配合应用。
签名钱包通常由确定性密钥 (deterministic key) 创立,用来创立能够生成子公私钥的父公私钥。
当第一次运行时,签名钱包创立一个父私钥,并将对应的公钥传输给联网钱包。
联网钱包应用父公钥派生出子公钥,帮忙散发他们(可选的),监控领取给这些公钥的 outputs,创立没有签名的领取交易,并把没有签名的领取交易传输给签名钱包。
通常用户有机会应用签名钱包查看未签名交易的详情(尤其是 outputs 的详情)。
在用户查看步骤 (可选的) 之后,签名钱包应用父私钥派生相应的子私钥并进行交易签名,将签名的交易传回给联网钱包。
联网钱包把签名的交易播送到 peer-to-peer 网络上。
离线钱包 Offline Wallets
几个 full-service wallets 也能够当作两个独立的钱包应用:一个程序实例当作签名钱包(通常称为“离线钱包”),另一个程序实例当作联网钱包(通常称作在线钱包或者监控钱包)。
脱机钱包在不联网的设施上运行,能够缩小供给量。如果这种状况,通常由用户来把握所有数据的传输和应用可挪动设施比方 USB 驱动器。用户的工作流是这样的:
- 1.(离线)敞开设施上所有网络连接,并装置钱包软件。以脱机模式启动软件,创立父私钥和父公钥,并赋值父公钥到可挪动介质上。
- 2.(在线)在另一台设施上装置钱包软件。这台设施联网,从可挪动介质上导入父公钥。上面的过程就像应用 full-service wallet 一样,散发公钥来接管领取。当筹备生产比特币时,填写 output 详情并把钱包生成的未签名的交易保留到可挪动介质上。
- 3.(离线)在脱机实例中关上未签名的交易,审查交易的详情,确保领取金额和地址正确。这个能够阻止恶意软件 (malware) 坑骗用户签订交易,从而领取给攻击者。审查后,签订交易并保留到可挪动介质。
- 4.(在线)在在线实例中关上已签名的交易,以便播送到 peer-to-peer 网络。
离线钱包的次要长处在于同残缺性能的钱包相比,大大的提告了安全性。只有脱机钱包没有被毁坏(或者有缺点),用户在签名之前会查看所有领取的交易,即便在线钱包被毁坏,用户的比特币也是平安的。
离线钱包的次要毛病是麻烦,为了最大的安全性,要求用户必须离线操作。任何时候要领取比特币,都必须启动离线设施,用户必须从在线设施物理拷贝数据到离线设施并再从离线设施拷贝数据回在线设施。
硬件钱包 Hardware Wallets
硬件钱包是专门用于签名的钱包设施,个别是智能卡等平安芯片开发的设施。他们能够平安与其余联网设施通信,用户也不须要手动传输数据了。硬件钱包的工作流程是这样的:
- (硬件)生成父私钥和公钥,将硬件钱包连贯到一个联网设施上,这样联网设施就能够取得父公钥;
- (联网)像应用残缺性能钱包一样,散发公钥来接管领取,当筹备领取比特币时,填写交易详情,连贯硬件钱包,而后点击生产,联网钱包会将交易详情发送给硬件钱包;
- (硬件)查看硬件钱包屏幕上的交易详情,一些硬件钱包可能会提醒输出 PIN,硬件钱包对交易进行签名,并将交易签名返回给联网钱包。
散发钱包 Distributing-Only Wallets
运行再很难保障平安的环境中 (比方 web 服务器) 的钱包程序,只能设计成分发公钥而不能有其余性能。这种简略的钱包有两种常见的设计办法:
- 把大量的公钥或者地址保留到数据库中,而后依据申请散发一条数据库内的条目比方一个公钥或者地址。为了防止重复使用密钥,web 服务器应该追踪应用过的密钥,并且永远不要用尽数据库中的公钥。
- 应用父公钥创立子公钥。为了防止重复使用密钥,必须应用一种办法确保一个公钥不会被散发两次。
这两种办法都不会减少大量的开销。
钱包文件 Wallet Files
比特币钱包的外围是一组私钥。这些汇合被数字化的保留在一个文件中,甚至能够保留在一张纸上。
私钥格局 Private Key Formats
私钥是用来解锁对应公钥地址的比特币的。在比特币中,规范格局的私钥是一个 256bit 的数字,值在下列范畴内:
0x01 ~ 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140
这个范畴是由比特币应用的 secp256k1 ECDSA 加密规范治理。
钱包导入格局 Wallet Import Format(WIF)
为了使得私钥复制不容易出错,能够应用钱包导入格局 WIF。WIF 应用 base58Check 对私钥进行编码,大大的升高了复制出错的机会,就像规范比特币地址一样。
- 1. 应用一个私钥
- 2. 在后面增加一个 0x80 作为 mainnet 地址,或者增加一个 0xEF 作为 testnet 地址;
- 3. 如果他应该和压缩公钥一起应用,在前面追加一个 0x01. 如果与未压缩的公钥一起应用,则不会追加任何数据。
- 4. 对扩大后的密钥进行 SHA-256 哈希;
- 5. 对 SHA-256 的后果进行 SHA-256 哈希;
- 6. 取第二个哈希后果的前 4 字节作为校验和;
- 7. 把从第 5 布取得的校验和增加到第 2 步扩大密钥的开端;
- 8. 应用 Base58Check 编码把第 7 步的数据转换未 Base58 字符串。
迷你私钥格局 Mini Private Key Format
迷你私钥格局是一种将私钥编码到 30 个字符以内的办法,能够将密钥嵌入到较小的物理空间中,比方物理比特币 Token,或者 QR Code 中。
- 1. 迷你密钥的第一个字符是‘S’;
- 2. 为了确定私钥格局良好,再私钥上增加一个问号;
- 3. 计算 SHA256 哈希,如果产生的第一个字节是‘00’,他是格局良好的。密钥的限度规定是一种输出查看 typo-checking 办法,用户应用应用随机数生成密钥,直到生成格局良好的密钥;
- 4. 为了生成残缺私钥,用户只须要获取原始迷你私钥的单个 SHA256 哈希值。这个过程是单向的,很难从生成密钥计算出迷你私钥格局;
-
5. 在很多实现中不容许字符‘1’呈现在迷你私钥中,因为它与‘l’在视觉上类似;
下面写的很顺当,我回头再整顿一下,从新写一下。
## 公钥格局 Public Key Formats
比特币的 ECDSA 公钥示意特定椭圆曲线上的一个点,比特币应用的是 secp256k1。再传统的未压缩模式中,公钥蕴含 identification byte,一个 32 bytes 的 X 坐标,一个 32 bytes 的 Y 坐标。
上面一个超级简略的图示意比特币应用的椭圆曲线上的一个点,$y^2= x^3+7$
沿着曲线只有两个点共享任何 X 坐标,所以只须要一个 bit 来示意 Y 坐标的正负即可,也就是把 Y 坐标压缩成 1bit,这样就在不扭转任何内容的状况下,实现了靠近 50% 的公钥压缩
应用这个压缩公钥不会失落数据,只须要应用大量运算就能够重建 Y 坐标并应用未压缩的公钥。在 secp256 官网文档中形容了未压缩和压缩的公钥,宽泛应用的明码算法库个别都反对这两种格局公钥。
因为容易应用,他们缩小了区块链的空间,压缩的公钥是比特币内核 Bitcoin Core 的默认值,也是所有比特币软件的举荐默认值。
Bitcoin Core 在 0.6 之前的版本,应用了未压缩密钥。这个造成一些复杂性。未压缩的密钥和压缩的密钥哈希模式不同。所以同一个密钥实用两个不同的 P2PKH 地址。这也就意味着在签名脚本中密钥必须以正确的格局提交,以便与后面输入的公钥脚本中的哈希值匹配。
因为这个起因,Bitcoin Core 应用了几个不同的 identifier byte 来帮忙程序辨认密钥应该如何应用:
- 与压缩公钥一起应用的私钥在 Base58 编码之前附加了 0x01;
- 未压缩的公钥以 0x04 结尾;压缩的公钥 0x03 或者 0x02 结尾,这个前缀也在 secp256k1
官网文档中应用。
分层确定性密钥创立 Hierarchical Deterministic Key Creation
晚期的比特币客户端中钱包都是随机生成的私钥汇合,这些密钥都须要用户本人保留正本,如果一旦密钥失落,那么对应的钱包就不能拜访,钱包管制的比特币也就无奈应用了。比特币有一个防止地址重复使用的准则,每个比特币地址只能一次交易,这样用户就会有大量的私钥要进行保留和备份,所以晚期计划不是一个好的方法。
分层确定性密钥和传输协定大大简化了钱包备份,打消了应用同一个钱包的多个程序之间反复通信的须要,容许创立能够独立操作的子账户,赋予每个父账户监控或者管制其子账户的能力,即便子账户受到破坏,每个账户分为齐全拜访和限度拜访两局部,这样不受信赖的用户就或者程序就能够接管或者监控领取,然而不能对外领取。
HD 协定利用了 ECDSA 公钥创立函数 -point(),它去一个大数(私钥),并将其转换为曲线上的的点(公钥):
point(private_key) == public_key
因为 point() 的工作形式,它让通过组合一个曾经存在的公钥(父公钥)和另一个公钥(通过一个 integer(i)值)来创立子公钥成为可能。 p 是一个所有比特币软件都应用的全局常量。
point((parent_private_key + i) % p ) == parent_public_key + point(i)
这就意味着两个或者多个独立的程序,如果对一个整数序列达成统一,就能够从繁多的父密钥对创立一系列惟一的子密钥对,而不须要进行额定的通信。此外,为收款散发新的公钥,程序能够在不接触私钥的状况实现,从而容许公钥散发程序在一个不平安的环境 (web 服务器) 上运行。
子公钥也能够通过重复子密钥扩散操作来创立他们本人的子公钥(孙公钥):
point((child_private_key + i) % p ) == child_public_key + point(i)
是否创立子公钥或者更后辈的公钥,对于所有交易来说,应用一个可预测的整数序列不会比应用繁多公钥好,因为任何人晓得一个子公钥能够找到所有其余的通过这个父公钥扩散的子公钥。相同的,应用一个随机种子来确定生成的整数序列,这样没有种子的人无奈看到子公钥之间的关系。
HD 协定应用一个繁多的根种子和无关联的确定代际 (unlinkable deterministically-generated) 的整数来创立子代,孙子代和其余更后辈的密钥。每个子密钥也通过它的父代取得一个代际 (deterministically-generated) 种子,称为链代码(chain code),所以一个 chain code 受到破坏,不会毁坏整个序列的层次结构。
HD 密钥扩散须要四个输出:
- 父私钥和父公钥,惯例的未压缩 256 bits 的 ECDSA 密钥;
- 父 chain code 是 256 bits 看起来随机的数据;
- 索引 index 是程序指定的 32-bit 整数。
在上图所示的规范模式中,父 chain code、父公钥和索引 index 被输出到单向哈希 HMAC-SHA512 中,生成确定代际然而看起来随机 (determistically-generated-but-seemingly-random) 的 512 bits 数据。哈希输入总共 512 bits,左边的 256 bits(低 256 bits)数据被用来作为新的子 chain code。哈希输入的右边 256 bits 被当作一个整数和父私钥或者父公钥组合(父私钥和哈希输入的高 256bits 椭圆曲线上做加法模 G 运算),来创立子私钥或者子公钥:
child_private_key == (parent_private_key + lefthand_hash_output) % G
child_public_key == point((parent_private_key + lefthand_hash_output) % G )
child_public_key == point(child_private_key) == parent_public_key + point(lefthand_hash_output)
父 chain code、父公钥、索引 index 计算 HMAC-SHA512 的过程如下:父公钥 (256bits) 和子密钥的 index(32bits)进行拼接,公钥在高位索引在位置,合并后的字节序是大端,对合并后的数据进行 HMAC-SHA512 运算,父 chain code 作为哈希密钥。
能够看进去,父私钥和对应代际的 chain code 能够算出子私钥,而后用 point()和子私钥能够算出子公钥,还能够用子公钥和 point(父 chain code)算出子公钥,这样也能够在不须要私钥的状况下,只晓得某一代际的公钥和对应代际的 chain code 就能够算出下一代的公钥。
指定不同的代际索引 index,能够应用雷同的父密钥扩散出不同的无关联的子密钥。子密钥应用子 chain code 反复密钥扩散过程能够生成无关联的孙密钥。
因为创立子密钥须要密钥和 chain code 两者,密钥和 chain code 合在一起被称作扩大密钥。一个扩大私钥和对应的扩大公钥具备雷同的 chain code。主私钥 (最顶层) 和主 chain code 是由随机数生成。
根种子 (root seed) 是由 123 bits、256 bits 或者 512 bits 的随机数生成的。这个根种子,起码 128 bits 是须要用户备份的惟一数据,未来用于通过特定的钱包和设置来扩散所有的密钥。
根种子通过哈希来创立 512 bits 看起来随机的数据,通过这些数据来创立主私钥和主 chain code(合在一起称作主扩大密钥)。主公钥通过主私钥应用 point() 计算得出,主公钥和主 chain code 合在一起称作主扩大公钥。主扩大密钥和其余扩大密钥在性能上等效,只是因为它位于最上层的地位,所以才显得不同。
根种子的哈希后 512 bits 的输入,右边 256 bits 作为主私钥,左边 256bits 作为主 chain code
强化密钥 Hardened Keys
强化扩大密钥 (Hardened extended keys) 修复了一般扩大密钥的一个潜在问题。如果攻击者取得了一个一般扩大密钥的父 chain code 和父公钥,他就能够暴力取得所有的通过这个 chain code 派生进去的 chain code。如果攻击者还取得了一个子私钥、孙子私钥或者更下一代的私钥,他就能够应用 chain code 生成这个私钥后辈所有的私钥了。
更蹩脚的是,攻击者能够逆向 (reverse) 一般的子私钥扩散公式,只有从子私钥中减去父 chain code 就能够复原父私钥,如上图子代和父代所示。这意味着一个攻击者,只有取得了一个扩大公钥和及其后辈的任何私钥,就能够复原出改公钥的私钥及其扩散出的所有密钥。
因为扩大公钥中有对应层级的 chain code,所以能够失去这个公钥后辈任意代际的公钥,所以只有取得了这个公钥后辈的私钥,就能够算到这个私钥上一代的 chain code,而后通过私钥 -chain code 计算出上一代私钥,最初推算出这个公钥和后辈的所有密钥。
下面的强化公示将索引 index、父 chain code 和父私钥组合在一起用来创立产生子 chain code 和子私钥的数据。这个公示让在不晓得父私钥的状况下不能创立子公钥。换句话说,父扩大公钥不能创立强化子公钥。
强化密钥生成过程,在父私钥后面补一个 0x00 字节,父私钥和索引 index 拼接,私钥在高位,索引在低位,字节序为大端。对拼接后的数据进行 HMAC-SHA512 运算,哈希密钥是父 chain code,父私钥和哈希的高 256 bits 做椭圆曲线上的加法模运算生成子私钥,低 256 bits 是子 chain code。如果 ECC 模运算后果呈现 0,那么索引值递增,而后再次计算密钥。子公钥能够通过子私钥计算出来。
因而,强化扩大私钥没有一般的扩大私钥有用,然而强化扩大私钥会创立一个防火墙,使得多层密钥扩散泄露不会产生。因为强化子扩大公钥无奈仅仅靠本人生成孙 chain code,父扩大公钥的泄露不能和孙私钥的泄露组合创立重孙扩大私钥。
HD 协定应用不同的索引 index 来批示是生成一般还是强化密钥。索引 Index 从 0x00~0x7FFFFFFF 将生成一般密钥;索引 Index 从 0x80000000~0xFFFFFFFF 将生成强化密钥。为了便于形容,许多开发者应用 '(prime symbol)来示意强化密钥,所以第一个一般密钥 (0x00) 是 0,第一个强化密钥 (0x80000000) 是 0 ’。
(比特币的开发者通常应用 ASCII 的撇号,而不是应用 unicode 的 prime symbol。)
这个压缩形容进一步联合斜杠和 m 或者 M 前缀,批示档次 (hierarchy) 和密钥类型。m 示意私钥,M 示意公钥。例如,m/0’/0/122′示意主私钥的第 1 代 (index=0) 强化子密钥的第 1 代 (index=0) 一般子密钥的第 123 代 (index=122) 强化子私钥(通过索引 index)。
恪守 BIP32 HD 协定的钱包只创立主私钥 (m) 的强化子密钥来避免子密钥泄露而导致主密钥泄露。因为主密钥不存在一般子密钥,所以主公钥也不会在 HD 钱包里应用。所有其余密钥能够有一般子密钥,所以能够应用对应的一般扩大公钥。
HD 协定还形容了扩大公钥和扩大私钥的序列化格局。详细情况能够参看 BIP32 协定。
保留根种子 Storing Root Seeds
HD 协定里的根种子 (root seeds) 是 128、256 或者 512 bits 的随机数,这些种子须要备份保留。为了不便,能够应用非数字化备份的办法,比方记忆、手抄等。BIP39 定义了一个办法,通过助记符来创立 512 bits 的根种子。
生成单词数与应用的熵值相干:
Entropy Bits | Words |
---|---|
128 | 12 |
160 | 15 |
192 | 18 |
224 | 21 |
256 | 24 |
明码短语 (passphrase) 能够是任意长度,它能够简略得追加到助记符 pseudo-sentence,mnemonic 和 password 将应用 2048 次 HMAC-SHA512 运算,产生一个看起来随机的 512 bits 种子。
涣散密钥钱包 Loose-Key Wallets
涣散密钥钱包仿佛中文也有叫零型非确定钱包,也被称作Just a Bunch Of Keys(JBOK),是一种 Bitcoin Core 客户端晚期的钱包模式,曾经被弃用。Bitcoin Core 客户端钱包通过伪随机数发生器主动创立 100 个公私钥对供当前应用。
这些没有应用的私钥存储在一个虚构的密钥池 (key pool) 中,之前生成的密钥被应用后,就会生成新的密钥放到池中,保障池中有 100 个未应用的密钥。