主页 > imtoken官网下载安全吗 > 以太坊公钥生成地址的具体过程

以太坊公钥生成地址的具体过程

imtoken官网下载安全吗 2023-02-12 05:58:37

网上有大量文章介绍ECDSA(椭圆曲线加密)算法生成以太坊公私钥对,进而生成一个唯一的以太坊地址。 其中大部分提到,非压缩公钥生成地址时,先进行哈希运算,然后取最后40位作为地址。 但是,我知道这件事必须要做。 如何哈希,公钥私钥是什么格式,相信很多人和我一样不清楚!

因为作者在研究什么,顺便了解下以太坊公钥生成地址的详细过程。 笔者先是百度了一下,参考了知乎上的一篇文章《以太坊的私钥、公钥、地址、账户》。 然而摸索了半天,还是得不到文中所列的结果。 最后,作者将文章中的私钥导入MetaMask后,让人意外的是,最终地址并不是文章中的示例地址。 看来一定是哪里出了问题以太坊根据地址计算私钥,所以笔者决定把公钥到地址的生成过程搞清楚,不能再含糊其辞了。

知乎这篇文章中有一张流程图:

在这里插入图片描述

这个流程图很正确,只有三个简单的步骤,但是结果不对。 最容易出错的地方应该是从公钥通过keccak-256算法到压缩公钥。 Keccak-256的具体功能是什么? 不同的语言有不同的实现。 这里笔者使用最常用的Node.js和ethers框架来验证这个问题。

幸运的是,ethers 框架中有一个函数可以直接使用公钥计算地址。 下面是函数的定义和说明:

ethers.utils.computeAddress( publicOrPrivateKey ) ⇒ string< Address >source
Returns the address for publicOrPrivateKey. A public key may be compressed or uncompressed, 
and a private key will be converted automatically to a public key for the derivation.

sitehqz.com 以太坊和以太坊贸易的关系_以太坊经典和以太坊_以太坊根据地址计算私钥

这是一个打包的计算库。 如果我们想知道详细的过程,可以参考它的源码实现来获取。 具体的参考过程这里就不说了,下面直接贴出验证成功的脚本(假设叫test.js):

//根据公钥生成地址实例详细流程
const eccrypto = require("eccrypto");
const sha3 = require("js-sha3");
const {ethers,utils} = require("ethers")
const private_key  = "18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725";
const my_wallet = new ethers.Wallet(private_key)
const public_key = my_wallet.publicKey

以太坊经典和以太坊_sitehqz.com 以太坊和以太坊贸易的关系_以太坊根据地址计算私钥

printPublicKey(public_key) //第一步: 移除公钥前两位04,如果包含0x就是移除四位了,再重新加上0x构造 let new_key = "0x" + public_key.substring(4) //第二步:对上面的结果转化成bytesLike(不能漏) let new_bytes = utils.arrayify(new_key) //第三步,keccak_256,得到一个长度为64的哈希值 new_key = sha3.keccak_256(new_bytes) //第四步,取上面结果的最后40位,就得到了全小写的地址。

以太坊经典和以太坊_sitehqz.com 以太坊和以太坊贸易的关系_以太坊根据地址计算私钥

let result = "0x" + new_key.substring(24) //最后,将地址转换成检验后的地址 result = utils.getAddress(result) console.log("") console.log(result) console.log(result === my_wallet.address) function printPublicKey(public_key) { console.log(public_key.substring(2,4))

以太坊根据地址计算私钥_以太坊经典和以太坊_sitehqz.com 以太坊和以太坊贸易的关系

let half = (public_key.length - 4)/2 console.log(public_key.substring(4, 4+half)) console.log(public_key.substring(4+half)) }

从上面的代码可以看出,使用公钥生成地址有几个步骤:

去掉公钥的04前缀,知乎文章中提到:

使用椭圆曲线数字签名算法ECDSA-secp256k1将私钥(32字节)映射为公钥(65字节)(前缀04+X公钥+Y公钥):

但是它没有提到在计算Keccak-256时去掉前缀。

以太坊经典和以太坊_sitehqz.com 以太坊和以太坊贸易的关系_以太坊根据地址计算私钥

将上面去掉04后的16进制字符串再次转化为字节数组,对上一步得到的字节数组进行keccak_256操作以太坊根据地址计算私钥,得到长度为64的哈希值(压缩公钥,32字节)。 取上面结果的最后 40 位,得到全小写的地址。 选修的。 将所有小写地址转换为经过验证的地址。

我们直接node test.js会得到如下输出:

04
50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352
2cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6
0x3E9003153d9A39D3f57B126b0c38513D5e289c3E
true

这种格式的输出是为了和知乎原文做对比。

至于为什么原文章末尾得到的地址是错误的,笔者在此转载。 原因是它在去掉04后直接对公钥串进行了Keccak-256操作,并没有转成字节数组。 .