| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 区块链 -> 以太坊区块链钱包原理 -> 正文阅读 |
|
[区块链]以太坊区块链钱包原理 |
钱包的本质私钥就是资金的所有和使用权。钱包控制对以太币的访问、管理私钥和地址、跟踪账户的余额。 私钥通过 ECDSA(椭圆曲线签名算法)推导出公钥,继而经过 Keccak 单向散列函数推导出地址。 具体分为以下三个步骤:
以太坊黄皮书上关于钱包(私钥、公钥、地址)的描述如下: 椭圆曲线公钥密码学加密通常分为对称加密与非对称加密。在对称密码中,由于加密和解密的密钥相同,所以必须向接收者配送密钥用于解密。但发送密钥过程中,窃听者可以窃取密钥解密,不发送密钥吧,接收者无法解密,密钥必须发送,但又不能发送,这问题称为密钥配送问题。在非对称加密中,将密钥分为加密密钥和解密密钥,也就是我们常说的公钥和私钥。 一个公钥密码学系统必须满足如下要求:
椭圆曲线原理椭圆曲线由满足下列形式方程的所有点组成: 点加法椭圆曲线上的点加法按照如下方式定义。 如果想要得到 点
P
P
P 和 点
Q
Q
Q 相加的结果: 首先,找到经过这两点的直线: 这条直线与椭圆曲线相交于第三个点: 最后,将这个交点关于
x
x
x轴 做对称: 如果选取一个基准点
P
P
P ,使得它不断地加上自身,我们可以得到
1
?
P
,
2
?
P
,
…
,
k
?
P
1\cdot P,2\cdot P,\ldots,k \cdot P
1?P,2?P,…,k?P 。点
P
P
P与自身相加的结果可以定义为过点
P
P
P 的切线与椭圆曲线相交得到交点,交点再关于
x
x
x轴 对称。 对于以太坊钱包中用到的椭圆曲线 s e c p 256 k 1 secp256k1 secp256k1 选取的基准点的 x x x轴 和 y y y轴 坐标分别为: x = 55066263022277343669578718895168534326250603453777594175500187360389116729240 x=55066263022277343669578718895168534326250603453777594175500187360389116729240 x=55066263022277343669578718895168534326250603453777594175500187360389116729240 y = 32670510020758816978083085130507043184471273380659243275938904335757337482424 y=32670510020758816978083085130507043184471273380659243275938904335757337482424 y=32670510020758816978083085130507043184471273380659243275938904335757337482424 快速点加法如果 x x x 是一个随机的 256 256 256 位的整数,那么需要多少步才能算出 x ? P x\cdot P x?P 呢?我们可以知道, x ? P x\cdot P x?P 的结果可以在 510 510 510 次点加法之内被计算出来。具体分析流程如下。 首先,计算出以下序列: 2 0 ? P , 2 1 ? P , 2 2 ? P , 2 3 ? P , 2 4 ? P , … , 2 255 ? P 2^0\cdot P, 2^1\cdot P, 2^2\cdot P, 2^3\cdot P, 2^4\cdot P, \ldots, 2^{255}\cdot P 20?P,21?P,22?P,23?P,24?P,…,2255?P 全部序列的计算需要 255 255 255次点加法。注意到, 2 n ? P + 2 n ? P = 2 n + 1 ? P 2^n\cdot P+2^n\cdot P=2^{n+1}\cdot P 2n?P+2n?P=2n+1?P 。于是任意的 x x x 都可以由上述的序列所表示。如 1 000 … 000 ? 254 个 0 1 1\underbrace{000\ldots 000}_{254个0}1 1254个0 000…000??1 可以由 2 255 ? P + 2 0 ? P 2^{255}\cdot P+ 2^0\cdot P 2255?P+20?P 表示。因此,通过计算出相应的序列,再由这些序列表示对应的数值最多需要 510 510 510 次计算。 公钥和私钥根据椭圆曲线点加法的定义,我们可以知道如果 X = x ? P X=x\cdot P X=x?P ,在给定 X X X 的情况下我们无法计算出对应的 x x x(每进行一次点加法,点的位置都变化很大,因此我们无法预测出在给定初始点的情况下,需要经过多少次加法才能得到最终的点),但是在给定 x x x 的情况下,我们却可以快速地计算出 X X X 。因此,椭圆曲线密码学就利用了这一原理,在给定基准点 P P P 的情况下,随机生成私钥 x x x ,再利用椭圆曲线快速计算出公钥 X X X 。 由于上述模型计算出的点无法表示 512 512 512 位的标准公钥(因为上面计算的结果很有可能是浮点数, 512 512 512 位通常不够表示相应的结果),因此我们需要定义我们的椭圆曲线在一个有限域上,也就是说曲线上所有点的坐标取值只能为整数。因此,我们将椭圆曲线的定义转化为: y 2 ≡ x 3 + a x + b ( m o d p ) y^2\equiv x^3+ax+b\qquad (mod\quad p) y2≡x3+ax+b(modp) 其中
p
p
p 为 小于
2
256
2^{256}
2256 的最大质数。因此,修改后的椭圆曲线可能如下所示: 应用如何应用椭圆曲线?需要考虑两个问题:
问题一对于第一个问题,我们可以根据 X = x ? P X=x\cdot P X=x?P 计算出 X X X 如果我们知道 x x x 的话。根据椭圆曲线点加法的定义,我们可以知道: x ? P + r ? P = ( x + r ) ? P x\cdot P+r\cdot P=(x+r)\cdot P x?P+r?P=(x+r)?P 我们将上式进行修改可以得到: h a s h ( m , r ? P ) ? x ? P + r ? P = ( h a s h ( m , r ? P ) × x + r ) ? P hash(m,r\cdot P)\cdot x\cdot P+r\cdot P=(hash(m,r\cdot P)\times x+r)\cdot P hash(m,r?P)?x?P+r?P=(hash(m,r?P)×x+r)?P 由于 X = x ? P X=x\cdot P X=x?P : h a s h ( m , r ? P ) ? X + r ? P = ( h a s h ( m , r ? P ) × x + r ) ? P hash(m,r\cdot P)\cdot X+r\cdot P=(hash(m,r\cdot P)\times x+r)\cdot P hash(m,r?P)?X+r?P=(hash(m,r?P)×x+r)?P 令 R = r ? P , s = h a s h ( m , R ) × x + r R=r\cdot P, s=hash(m,R)\times x+r R=r?P,s=hash(m,R)×x+r ,可以得到: h a s h ( m , R ) ? X + R = s ? P (1) hash(m,R)\cdot X+R=s\cdot P \tag{1} hash(m,R)?X+R=s?P(1) 如果我们知道 x x x ,我们可以选定一个 m , r m, r m,r ,从而根据 R = r ? P , s = h a s h ( m , R ) × x + r R=r\cdot P, s=hash(m,R)\times x+r R=r?P,s=hash(m,R)×x+r 计算出 R R R 和 s s s 使得(1)成立。于是,我们可以得出结论,如果能够给出 m , R , s m, R, s m,R,s 使得(1)成立,那么便能够证明其知道私钥 x x x 。 如果我们不知道 x x x ,想要使得(1)成立。固定任意两个数,去寻找第三个数,这个过程根据圆锥曲线点加法的计算方式,都是计算上不可行的。 因此,我们可以得出结论:
问题二首先, m , R m, R m,R 的值与 x x x 无关,因此它不能揭示任何与私钥 x x x 相关的信息。 我们知道 s = h a s h ( m , R ) × x + r s=hash(m,R)\times x+r s=hash(m,R)×x+r ,因此我们可以得到: x = s ? r h a s h ( m , R ) x=\frac{s-r}{hash(m,R)} x=hash(m,R)s?r? 因此,要想知道私钥 x x x 的值,我们需要首先获取 r r r 的值,但是根据 R = r ? P R=r\cdot P R=r?P ,由椭圆曲线点加法的计算方式,我们无法从 R R R 的取值来推导 r r r 的取值(计算上不可行)。 所以,在证明过程中不会暴露关于私钥 x x x 的信息。 数字签名通过验证等式 h a s h ( m , R ) ? X + R = s ? P hash(m,R)\cdot X+R=s\cdot P hash(m,R)?X+R=s?P 是否成立, m , R , s m, R, s m,R,s 可以被用来证明某人知道公钥 X X X 对应的私钥 x x x ,其中 X = x ? P X=x\cdot P X=x?P 。 如果 m m m 是一个给定的具体信息(用户即将发送),那么用户只需要提供 R R R 和 s s s 作为其数字签名,最终接收方验证等式 (1)是否成立来验证这个信息是否是由相应的用户所发生的(即用户对这条消息进行了签名认证)。如果验证通过,说明是由本人发送的这条消息,并不是其他人伪造的,在区块链上,这条消息就是一个交易请求信息,如果矿工验证通过了这个消息,那么他将会执行这条消息中的内容。 也就是说,对于一个(发送者发出的)具体消息 m m m ,通过提供数字签名 R R R 和 s s s 一个人可以证明他知道(发送者)公钥 X X X 对应的私钥 x x x (消息是由本人发出的)。 以太坊私钥存储(Keystore)文件通常一些钱包会对用户的私钥进行加密等操作,使得私钥不会被直接暴露在外界,这提高了私钥的安全性。 以太坊客户端提供了私钥管理的功能,通过下述命令:
上述命令将会创建一个新的账户,账户信息以 keystore 文件的形式存放在 ~/.ethereum/keystore 目录( Linux 操作系统)下。如果你丢失了这个文件,你就丢失了私钥,意味着你失去了签署交易的能力,意味着你的资金被永久的锁定在了你的账户里。 当然,你可以直接把你的以太坊私钥存储在一个加密文件里,但是这样你的私钥容易受到攻击,攻击者简单的读取你的文件、用你的私钥签署交易,把钱转到他们的账户中。你的币会在你意识到发生什么了之前的短时间内丢失。 这就是以太坊 keystore 文件被创建的原因:它允许你以加密的方式存储密钥。这是安全性(一个攻击者需要 keystore 文件和你的密码才能盗取你的资金)和可用性(你只需要keystore文件和密码就能用你的钱了)两者之间完美的权衡。 为了让你发送一些以太币,大多数的以太坊客户端会让你输入密码(与创建账户时密码相同)以解密你的以太坊私钥。一旦解密,客户端程序就得到私钥签署交易,允许你移动资金。 Keystore 文件格式大致内容如下:
其中包括
工作流程1. 加密你的私钥为了确保你的私钥没有在文件中明文存储(即任何人只要能得到这个文件就能读),使用强对称算法(cipher)对其加密至关重要。 这些对称算法使用密钥来加密数据。加密后的数据可以使用相同的方法和同样的密钥来解密,因此算法命名为对称算法。在本文中,我们称这个对称密钥为解密密钥,因为它将用于对我们的以太坊私钥进行解密。 以下是 cipher,cipherparams 和 ciphertext 对应的概念:
所以,在这里,你已经有了进行解密以太坊私钥计算所需要的一切。等等。你需要首先取回你的解密密钥。 2. 用你的密码来保护它要确保解锁你的账户很容易,你不需要记住你的每一个又长又非用户友好型的用于解密 ciphertext 密文解密密钥。相反,以太坊开发者选择了基于密码的保护,也就是说你只需要输入密码就能拿回解密密钥。 为了能做到这一点,以太坊用了一个密钥生成函数,输入密码和一系列参数就能计算解密密钥。 这就是 kdf 和 kdfparams 的用途:
在这里,用 kdfparams 参数对 scrypt 函数进行调整,反馈到我们的密码中,你就会得到解密密钥也就是密钥生成函数的输出。 3. 确保你的密码是对的我们描述了用密码和 keystore 文件生成以太坊私钥所需要的所有东西。然而,如果解锁账户的密码错误会发生什么? 根据迄今为止我们所看到的,所有操作(密码派生和解密)都会成功,但是最终计算的以太坊私钥不是正确的,这首先违背了密钥文件的使用初衷! 我们要保证输入解锁账户的密码是正确的,和最初创建 keystore 文件时一样(回想一下 geth 下创建新账户时两次输入的密码)。 这就是 keystore 文件中 mac 值起作用的地方。在密钥生成函数执行之后,它的输出(解密密钥)和 ciphertext 密文就被处理,并且和 mac(就像一种认可的印章)作比较。如果结果和 mac 相同,那么密码就是正确的,并且解密就可以开始了。处理过程如下图所示: 总体流程系统总体工作流程如下:
钱包技术概述第一类是非确定性钱包,其中保存的每一个私钥都是通过不同的随机数相互独立地生成的。私钥之间没有任何关联。这类钱包被称为 JBOK (Just a Bunch Of Keys)钱包。 第二类钱包是确定性钱包,其中所有的密钥都是从一个主密钥衍生而来的,这个主密钥就是种子密钥。这类钱包中所有的密钥之间都存在关联关系,如果获得了“种子密钥”,则可以重新生成所有密钥。确定性钱包有多种密钥派生方法。最常用的派生方法是使用一个类似树形的结构,我们称之为层级式确定性(hierarchical deterministic)钱包,或简称为 HD 钱包。 注:用户如果长期使用同一个账户地址进行交易,那么用户的账户就可能存在被跟踪的风险,导致用户的隐私泄露。因此,为了保证隐私性,通常需要用户不断更换发起交易的地址。在比特币网络中,由于账户模型是 UTXO 模型,每笔交易可以设置一个找零账户,交易中剩余的金额会被转入这个账户,这就使得同一个用户可以使用不同的地址发起交易(交易结束后将剩余的钱转入一个新的地址,这个在以太坊上不适用,因为以太坊需要收取交易的手续费)。这就使得一个用户可能同时拥有多个比特币的地址,因此要管理多个这样的地址,钱包中也就需要管理多个私钥。由于非确定性钱包中,各个私钥之间不相关,因此管理起来相对麻烦(需要同时管理多个私钥),而确定性钱包各个私钥之间存在关联,可以通过主密钥来派生出所有的子密钥,因此钱包中只需要管理主密钥,就可以衍生出所有相关的密钥。 非确定性钱包上述以太坊通过存储 keystore 文件来管理密钥,就是一种确定性钱包。 确定性钱包主要以层级式确定性钱包为例。它的目的是让人们更容易地从单一的“种子”中衍生出多个密钥。目前,确定性钱包最高级的形式便是由比特币 BIP-32 标准定义的 HD 钱包。HD钱包可以保存用树状结构推导的多个密钥,比如一把私钥可以推导出一系列子密钥,每一个子密钥都可以推演出一系列孙子密钥,如此类推至于无穷。如图所示: 以下是一些钱包设计中的行业标准 BIP (Bitcoin Improvement Proposal):
助记词标准 (BIP-39)助记词中的单词代表用来生成钱包的种子密钥中的内容。这一串助记词足够用来重新创建种子密钥,进而恢复整个钱包中所有从这个种子派生而来的密钥。本节说明了如何生成助记词以及如何通过助记词创建种子密钥。 生成助记词助记词由钱包根据BIP—39所定义的标准流程自动生成,钱包从随机源获取一个随机数,然后添加校验码,再把这个数字映射为一串英文单词:
从助记词到种子密钥助记词代表128比特或256比特的随机数。使用密钥扩展算法,例如 PBKDF2,可以将这个随机数衍生成 512 512 512 比特长的种子,进而用来构建确定性钱包和派生其他密钥。 密钥扩展算法需要两个参数:助记词和盐(salt) 。加盐的目的是防止通过循环表格的方式来实现暴力破解。在 BIP-39 标准中,加盐还有另外一个目的:引入额外的密码来保护种子密钥。
BIP-39 标准允许用户在生成种子密钥的过程中使用可选密码。如果用户没有设定密码,那么默认使用字符串 ”mnemonic” 进行助记词的密钥扩展运算,生成一个特定的 512 512 512 比特的种子密钥。如果用户提供了密码,那么对于同样的助记词,密钥扩展运算会生成完全不同的种子密钥。实际上,给定一组助记词,每一个密码都会导致不同的种子密钥。特别是,这里没有正确或者错误的密码,所有密码都可以生成用来衍生无数钱包地址的种子密钥。可能的钱包的范围非常巨大,如果密码的复杂度足够强,那么暴力破解或猜测都没有可能实现。举个栗子🌰: 层级式确定性钱包 (BIP-32)BIP-32 为 HD 钱包的核心提案,说明了私钥生成方法以及树状结构的构造方式。其定义了如下两个内容:
在 BIP-32 中根据父节点去派生子节点的方法被称作 Child Key Derivation Function,简称为 CKD。CKD 根据如下 3 个参数去生成子节点:
如何生成子公钥?根据父节点公钥生成子节点公钥的流程如下图:
如何生成子私钥?根据父节点私钥 (Parent Private Key) 生成子节点私钥 (Child Private Key) 的流程如下图:
为什么要有 Chain Code?钱包安全的核心在私钥,而公钥则比较容易被找到,如果子节点生成过程只依赖父节点公钥和子节点序号,那么黑客拿到父节点公钥之后就能复原出所有子节点、孙节点的公钥,这样就会破坏隐私性,CKD 里面引入的 Chain Code 则是在整个子节点派生过程中引入确定的随机数,为 HD 钱包的隐私性增加了一重保障。 注:公钥是可以被暴露在外的,Chain Code 如果在钱包中被安全的保存,因此光利用公钥是无法还原整棵树的公钥的。但是,如果 Chain Code 也被暴露,那么黑客同样可以还原所有子节点、孙节点的公钥。 什么是 Extended Key?因为在子节点生成过程中会同时用到父节点公钥和父节点链码,BIP-32 里面约定把两者拼接再做特定结构编码产生的结果叫做 Extended Key,也叫做可扩展的钥匙,顾名思义就是根据 Extended Key 我们就可以开始派生子节点。父节点公钥、私钥和链码结合产生的 Extended Key 分别是:
因为从 Extended Key 可以解出父节点私钥、公钥和链码,可以说 Extended Key 代表了 HD 钱包中某个分支、子树的根或者起点,也正是因为这种特性,对 Extended Key 的数据保密要格外小心。 什么是 Master Key?既然是一颗树,那么必须要有一个根节点(主节点),所有子节点的生成都从这个根节点开始。这里,主节点由种子密钥生成。 通过将种子密钥拆分成两个 256 256 256 位的数字,分别作为主节点私钥和主节点链码,主节点公钥可以由主节点私钥计算得出,而后递归生成子节点。 安全增强的 CKD 函数因为区块链钱包里面保存的私钥能转移用户的资产,对安全性再怎么强调都不为过,对于上面的子节点私钥和公钥生成函数是否足够安全呢?我们设想下面的场景:
如果安全问题是没有办法彻底避免的,如何在某个子节点私钥泄露的时候把破坏性降到最低呢?这就需要对 CKD 函数稍作改进,在 BIP-32 中称之为 安全增强的子私钥派生函数,记为 HCKD (Hardened Child Key Derivation),原来的 CKD 函数 (Normal Child Key Derivation) 和安全增强的 CKD 函数流程对比如下图: 安全增强的 CKD 函数产生的节点属性称呼也响应的发生变化:
不同点在于,安全增强的 CKD 函数中子节点私钥的生成不再使用父节点公钥,而是直接使用父节点私钥,因为相比私钥而言公钥更容易被黑客截获,这样必须在有父节点私钥的情况下才能推导出子节点私钥,只靠父节点的公钥和链码不能推导出增强的子节点公钥。这样子节点之间的兄弟关系就不那么容易被获悉,而即使某个增强子节点私钥泄露,也不会影响到父节点。 BIP-32 约定 CKD 函数的节点序号取值范围在 [ 0 , 2 31 ) [0,2^{31}) [0,231) 之间,而 HCKD 的节点序号在 [ 2 31 , 2 32 ) [2^{31},2^{32}) [231,232) 之间,这样每个节点就可以生成 2 31 2^{31} 231 个子节点。 注:在 CKD 的情况下,如果知道了父节点的公钥和链码,可以推到出所有子节点、孙节点的公钥和链码;如果再知道了某个孙节点的私钥,就可以推到重孙节点的私钥;同时由于孙节点的私钥是由其父节点的私钥以及其父节点的公钥经过单向哈希运算的结果共同作用得到的,因此有可能推到出其父节点的私钥。 HCKD 的情况下,即使黑客知道了父节点的公钥和链码,也无法推到子节点的公钥和链码,因为这一步需要用到父节点的私钥。某个孙节点的私钥泄露之后,由于不知道孙节点的链码,因此也无法推导其他的重孙节点。 层级式确定性钱包的标识符(路径)HD 钱包中的密钥采用 “路径” 的命名规范进行表示,根据树形结构在每一层之间采用 “/” 分割。从主私钥派生出的私钥由 m 开头,而从主公钥派生出的公钥由 M 开头。因此,主私钥派生的第一个子私钥表示为
m
/
0
m/0
m/0,主公钥派生出的第一个子公钥表示为
M
/
0
M/0
M/0 。第一个子私钥的第二个下一级孙子私钥表示为
m
/
0
/
1
m/0/1
m/0/1,以此类推。 层级式确定性钱包的树状结构显然,BIP-32 的在钱包安全性、易用性方面做了比较不错的平衡,但是不同的钱包应用开发者可以自定义自己的节点结构,这就很容易导致没有办法 100% 保证在使用了 HD 钱包 A 的用户能将自己的种子导入到 HD 钱包 B 中还能正常工作;也没有办法保证 HD 钱包能支持多个链的私钥管理。 因为这个原因,比特币社区在 BIP32 的基础上提出了比较规范的 BIP-43 和比较具体的 BIP-44,两者的目的在于就 HD 钱包子节点派生路径的模式、每段的含义上做出具体的规定,形成共识,事实上现如今的 HD 钱包都遵循了 BIP-32 和 BIP-44 的规定,也只有遵循了这两个规范的钱包应用才是大概率完全兼容的。 BIP-44 的内容相比 BIP-32 就简单很多,里面规定了子节点派生路径的范式:
示例如下:
每个段的含义分别是:
以太坊元交易通过元交易,我们可以用一个完全没有以太币的账户来与区块链进行交互。对于推动以太坊的普及来说,这种技术可能是不可或缺的。用户并不关心去中心化或者私钥;他们更关心的是可以使用你的 Dapp 来做一些对他们而言重要的事情。 参考[1] 关于钱包的密码学基础 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 | -2024/12/27 11:13:41- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |
数据统计 |