【Ethereum基础】:账户、地址、私钥和公钥
在以太坊中,账户、地址、私钥(Private Key)和公钥(Public Key)是非常重要的概念。账户扮演着以太坊的中心角色,地址是我们与以太坊系统进行交互的标识,它是以太坊账户与外界进行交互的名字,而私钥与公钥是保护我们账户安全的重要屏障。 |
账户在以太坊中扮演者十分重要的角色,它是以太坊的中心概念。在以太坊中,有两种类型的账户1:一种是外部账户(EOAs,Externally Owned Accounts),另一种是合约账户(Contracts Accounts)。当我们提到账户这个术语的时候,我们通常指的是外部账户(EOA),当提到合约账户的时候我们通常称其为“合约”。
不论是外部账户还是合约账户,它们在以太坊中所维护的都是一系列叫做状态对象(state objects)的实体。这些实体中都拥有状态信息:外部账户存储的是账户的余额(balance),合约账户存储的是余额和合约中的内容。它们存储的这些状态会通过以太坊网络进行更新以及保证数据的一致性。账户是用户在以太坊区块链上创建交易必不可少的一部分。
账户标识了以太坊网络中每一个参与者的身份,每一笔交易都需要通过账户使用公钥加密进行签名才能够正常进行,这样的话,EVM(以太坊虚拟机)才能够对交易发送者进行验证来确保交易的真实可靠。
0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826
,该地址使用的是16进制表示法2)。上述示例中的地址中的字母全部是小写。在EIP553中引入了一种大小写混用的地址表示方法,通过这种表示方法进行表示的地址隐含了一个校验和(checksum)能够验证该地址的有效性。
每个账户都由一对钥匙定义,一个私钥(Private Key)和一个公钥(Public Key)。 账户以地址为索引,地址由公钥衍生而来,取公钥的最后20个字节。每对私钥/地址都编码在一个钥匙文件里。该文件是JSON格式的,下面我们将会查看一个私钥文件示例(Keystore)。
以太坊的私钥是一串64位16进制字符(32字节)。它是账户安全最重要的部分,需要妥善保管,如果丢失了私钥也就意味着你的账户丢失了。
keystore
文件夹下,它是JSON格式的:
{ "address":"358f94366124d9f2817b09c84921d2a653f5ac0c", "crypto":{ "cipher":"aes-128-ctr", "ciphertext":"41c14f88ec8f35c9fe57cd39121a76c2dadbd82ea8fec59866468bc0d7371f2e", "cipherparams":{ "iv":"43443bf394e8f6ebcc687e13bc0effb9" }, "kdf":"scrypt", "kdfparams":{ "dklen":32, "n":262144, "p":1, "r":8, "salt":"aaef6847d09cb1e9f5ceadaf5865d96a7493df1cae146b24e31092cc0a7844af" }, "mac":"5e9781c587db5795c6d41cb4f001bf086cc3db33b6e7eefcc2ef472145e76821" }, "id":"bcd61a88-283f-4d81-8457-30ec9c11521f", "version":3 }
通过keystore文件中的内容,我们可以看到其中包括了私钥加密的相关信息:
cipher:加密方法使用的是AES-128-CTR算法4
ciphertext:加密后的密文
cipherparams:AES-128-CTR算法加密所需的相关参数
kdf:秘钥生成函数,用于使用密码对keystore文件进行加密
kdfparams:kdf算法所需的参数
mac:用于验证密码的编码
> 公钥 -> 地址。因此地址的生成需要三步:
通过私钥生成公钥(64字节)
通过公钥得到地址(20字节)
私钥的生成
私钥是一组64位的16进制字符,通过私钥我们能够访问一个账户。以太坊的私钥生成是通过secp256k15曲线生成的,secp256k1是一个椭圆曲线算法,比特币使用的也是相同的曲线算法。
通过OpenSSL6我们可以生成一个椭圆曲线私钥:
$ openssl ecparam -name secp256k1 -genkey -noout -----BEGIN EC PRIVATE KEY----- MHQCAQEEICGlTPPQInj0R/jaa7+bjF1twiR3RDLdOChSq98L5FmWoAcGBSuBBAAK oUQDQgAERynScthXq2n4Ahkfp08s/QNogZEtVCfQE/XTvpjsnIeQEZGJIOb+Liyl uF8PIerBE1CjvCs5LLU+fZz+B31+Bg== -----END EC PRIVATE KEY-----
公钥的生成
其实,通过OpenSSL我们可以同时得到私钥和公钥:
$ openssl ecparam -name secp256k1 -genkey -noout | openssl ec -text -noout read EC key Private-Key: (256 bit) priv: 3f:64:bb:20:0a:b5:82:e9:73:03:8a:8b:79:68:62: 41:8b:98:a7:10:00:fb:50:de:c4:4d:0d:06:3d:a2: ed:cd pub: 04:4a:18:c2:c7:40:f4:9a:77:b2:89:e9:27:0c:39: 94:8b:94:10:a1:b0:c9:81:d9:af:06:8c:06:23:93: 63:d7:26:82:fd:b0:22:fe:f6:7f:4f:8a:69:58:2f: 98:3a:b3:94:ab:5f:06:85:4c:25:f3:3d:8e:f1:35: 2f:e7:fe:50:4d ASN1 OID: secp256k1
地址的生成
7,然后取最后的40位16进制字符得到的。我们对上述的公钥做哈希后并取后40位的结果是:0x24602722816b6cad0e143ce9fabf31f6026ec622
。得到的该结果就是一个有效的以太坊地址。
Geth Web3进行验证:
通过以太坊客户端Geth的Web3接口可以对以太坊地址进行有效性验证:
> web3.utils.isAddress('0xc1912fee45d61c87cc5ea59dae31190fffff232d'); > true
通过第三方JS库进行验证:
8是一个JavaScript库能够对多种加密货币的地址进行验证。
var WAValidator = require('wallet-address-validator'); var valid1 = WAValidator.validate('0x24602722816b6cad0e143ce9fabf31f6026ec622', 'ETH'); if(valid1) console.log('This is a valid address'); else console.log('Address INVALID');
[1] Ethereum_Accounts:http://ethdocs.org/en/latest/account-management.html#accounts
[2] Hexadecimal_Format:http://ethdocs.org/en/latest/glossary.html#hexadecimal
[3] EIP55:https://github.com/ethereum/EIPs/issues/55
[4] AES五种加密模式(CBC、ECB、CTR、OCF、CFB):https://www.cnblogs.com/starwolf/p/3365834.html
[5] Secp256k1:https://en.bitcoin.it/wiki/Secp256k1
[6] OpenSSL:https://github.com/openssl/openssl
[7] Keccak-256_Online:https://emn178.github.io/online-tools/keccak_256.html
[8] wallet-address-validator:https://github.com/ognus/wallet-address-validator
罗远航 所有,采用 Attribution-NonCommercial 3.0 License。任何人可以进行转载、分享,但不可在未经允许的情况下用于商业用途;转载请注明出处。感谢配合!
- 点赞
- 收藏
- 关注作者
评论(0)