# 如何创建一个 Ethereum 钱包地址 **Published by:** [iiiyu](https://paragraph.com/@iiiyu/) **Published on:** 2022-08-03 **URL:** https://paragraph.com/@iiiyu/ethereum ## Content Bitcoin 和 Ethereum 的账户体系 Bitcoin 和 Ethereum 的账户体系是不同的思想,导致整个交易体系的结构有区别。因此他们对应地址会有不同。本次先略过 Bitcoin,仔细说明 Ethereum。 Bitcoin 采用的是 Unspent Transaction Output。 Ethereum 使用的就是比较容易理解的普通账户体系。 什么是区块链钱包地址 简单的说区块链本质上是一个账本,账本上记录着一条一条的转账记录。每一条转账记录的基本信息有三要素: 从哪 到哪 多少钱 在区块链的世界里面,钱包地址就是转账记录里面从这里转到那里的标识。 有了这个钱包地址,我们也就可以把这个地址所有交易记录找出来,相加后就能得到该地址的当前余额。 拥有这个钱包地址的操作权限(私钥)就是进入区块链世界的门票。 简单解释一个区块链钱包地址是如何得来的 不同于当下的互联网世界的账号体系,一个区块链的钱包地址并不是注册得来。 而是通过使用密钥进过一系列复杂的加密算法得来。 生成钱包地址的加密算法是公开且固定的。意味这任何人可以在任何时候用任何设备任何编程语言实现该方法后生成钱包地址。无需联网。 每一个符合条件的唯一密钥对应唯一一个钱包地址。 密钥是操作钱包的唯一凭证。 密钥丢失不可找回。 基于这些不太常见的情景,我举例几个有趣的例子。 我可以简单的获取成千上万的钱包地址,他们全部都是可以被操作的地址。只不过这些钱包地址里面没有任何的转账记录。 当向一个合法的钱包地址转账的时候,并不会也不需要校验这个地址是否可被操作。如果这个地址是一个错误地址,转账会成功,并且可查该钱包余额和记录。只是没有人拥有该钱包地址的私钥即钱包的操作权限。 理论上是存在这样的可能性,要是我不小心使用了一个密钥生成的地址是一个有余额的地址。那我就等于获得了该钱包地址的操作权限可以获取余额。 就算我有一个 1000 个 ETH 余额的钱包地址,但是我不小心把密钥丢了。那这 1000 个 ETH 就再也找不回了。 Ethereum 钱包地址 Ethereum 有两种账号类型 外部账户(Externally-owned) - 由有这密钥的拥有者控制 合约账户(Contract) - 由部署在 Ethereum 里面的代码控制 两种账号都拥有 接受,持有发送 ETH 和 tokens 可以跟已经部署的智能合约交互 两种账号的地址格式: 外部账户(Externally-owned) : 表示的是该账户公钥经过 Keccak-256 哈希算法后的最后 20 字节再加上 0x 开头变为 42 个字符十六进制字符串。例如:0x5e97870f263700f46aa00d967821199b9bc5a120 合约账户(Contract): 由 0x 开头的 42 个字符十六进制字符串。例如:0x06012c8cf97bead5deae237070f9587f8e7a266d Ethereum 钱包地址生成原理 私钥 -> 公钥 -> 地址。因此地址的生成需要三步: 生成一个随机的私钥(64 个 16 进制字符, (256 bits / 32 bytes)) 通过 Elliptic Curve Digital Signature Algorithm 用私钥生成公钥(128 个 16 进制字符,64 bytes) 通过 Keccak-256 的哈希函数用公钥得到一个 64 个字符长度的字符串,然后取最后 40 个字符作为地址(40 个 16 进制字符,20 bytes) 命令行生成方式 先安装一下 sha3sum 获取 keccak-256sum https://github.com/maandree/sha3sum // on macOS brew install sha3sum # Generate the private and public keys openssl ecparam -name secp256k1 -genkey -noout | openssl ec -text -noout > key # Extract the public key and remove the EC prefix 0x04 cat key | grep pub -A 5 | tail -n +2 | tr -d '\n[:space:]:' | sed 's/^04//' > pub # Extract the private key and remove the leading zero byte cat key | grep priv -A 3 | tail -n +2 | tr -d '\n[:space:]:' | sed 's/^00//' > priv # Generate the hash and take the address part cat pub | keccak-256sum -x -l | tr -d ' -' | tail -c 41 | awk '{print "0x"$1}'> address # display your address cat address Go 程序生成方式 package main import ( "crypto/ecdsa" "fmt" "log" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" ) func main() { privateKey, err := crypto.GenerateKey() if err != nil { log.Fatal(err) } privateKeyBytes := crypto.FromECDSA(privateKey) fmt.Println("SAVE BUT DO NOT SHARE THIS (Private Key):", hexutil.Encode(privateKeyBytes)) publicKey := privateKey.Public() publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) if !ok { log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey") } publicKeyBytes := crypto.FromECDSAPub(publicKeyECDSA) fmt.Println("Public Key:", hexutil.Encode(publicKeyBytes)) address := crypto.PubkeyToAddress(*publicKeyECDSA).Hex() fmt.Println("Address:", address) } 至此,我们就有两种简单的办法可以离线生成了 Ethereum 的钱包地址,并且拥有密钥。 基于这个简单的原理,我们稍后可以简单的做一些有趣的小程序了。 Referrals 如有更新请参考Blog地址 https://iiiyu.com/2022/07/27/how-to-generate-a-new-ethereum-address-chinese-version/ 什么是比特币地址&三种地址格式对比 Generate Ethereum Private key, Public key, and Address using Bash and OpenSSL How to generate a new Ethereum address in Go 【Ethereum 基础】:账户、地址、私钥和公钥 從地址格式探討 Bitcoin 和 Ethereum 的差異 ## Publication Information - [iiiyu](https://paragraph.com/@iiiyu/): Publication homepage - [All Posts](https://paragraph.com/@iiiyu/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@iiiyu): Subscribe to updates - [Twitter](https://twitter.com/iiiyu_eth): Follow on Twitter