开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第17天,点击查看活动详情
一.基础概念
(1)账户(Accounts):
在以太坊中,有两种类型的账户:一种是外部账户(EOAs,Externally Owned Accounts),另一种是合约账户(Contracts Accounts)。当我们提到账户这个术语的时候,我们通常指的是外部账户(EOA),当提到合约账户的时候我们通常称其为“合约”。
(2)以太坊地址(Address):
一个以太坊地址就代表着一个以太坊账户,地址是账户的标识。对于外部账户来说,地址表示的是该账户公钥的后20字节(通常会以0x开头,例如,0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826,该地址使用的是16进制表示法。上述示例中的地址中的字母全部是小写。在EIP55中引入了一种大小写混用的地址表示方法,通过这种表示方法进行表示的地址隐含了一个校验和(checksum)能够验证该地址的有效性
(3) 私钥和公钥
每个账户都由一对钥匙定义,一个私钥(Private Key)和一个公钥(Public Key)。 账户以地址为索引,地址由公钥衍生而来,取公钥的最后20个字节。每对私钥/地址都编码在一个钥匙文件里。该文件是JSON格式的。以太坊的私钥是一串64位16进制字符,如果丢失了私钥也就意味着你的账户丢失了。
(4)查看一个Keystore文件
{
"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文件中的内容,我们可以看到其中包括了私钥加密的相关信息:
- address:该账户的地址
- cipher:加密方法使用的是AES-128-CTR算法4
- ciphertext:加密后的密文
- cipherparams:AES-128-CTR算法加密所需的相关参数
- kdf:秘钥生成函数,用于使用密码对keystore文件进行加密
- kdfparams:kdf算法所需的参数
- mac:用于验证密码的编码
(5) 私钥、公钥和地址是生成顺序
**以太坊使用Secp256k1椭圆曲线得到私钥**

(6)python代码生成公钥,私钥,地址
1)第一种
from eth_keys import keys
from eth_utils import decode_hex
decode_hex(私钥)
priv_key_bytes = decode_hex('0x44b9abf2708d9adeb1722dcc1e61bef14e5611dee710d66f106e356a111bef90')
priv_key = keys.PrivateKey(priv_key_bytes)
pub_key = priv_key.public_key
2)第二种
from eth_keys import keys
# 先创建keys模块下的私钥对象
#self.privatekey为私钥
priv_key = keys.PrivateKey(self.privatekey)
print("priv_key:",priv_key)
# 再解出公钥
self.public_key = priv_key.public_key
print("公钥:",self.public_key)
# 这里的公钥是64字节,是压缩的
print("公钥长度:",len(str(self.public_key)))
# 使用web3.py自带的keccak实现从公钥中得出地址
sha3_pub_key = Web3.keccak(hexstr=str(self.public_key))
print("sha3_pub_key",sha3_pub_key)
# 取后20个字节
print('从公钥生成地址:',Web3.toHex(sha3_pub_key[-20:]))
3)第三种
import binascii
import sha3
from ecdsa import SigningKey, SECP256k1
priv = SigningKey.generate(curve=SECP256k1) # 生成私钥
pub = priv.get_verifying_key() # 生成公钥
keccak = sha3.keccak_256()
keccak.update(pub.to_string()) # keccak_256哈希运算
address = "0x" + keccak.hexdigest()[24:]
priv_key = binascii.hexlify(priv.to_string())
pub_key = binascii.hexlify(pub.to_string())
print("Private key: " + priv_key.decode())
print("Public key: " + pub_key.decode())
print("Address: " + address)
(7)助记词
助记词和种子不是同一个概念,但并非如此,一个叫mnemonic(助记符或助记词),一个叫seed(种子)
seed = wallet.generate_mnemonic()