主页 > 以太坊imtoken > 从源码解析以太坊地址的生成过程

从源码解析以太坊地址的生成过程

以太坊imtoken 2023-05-14 06:49:15

1.获取以太坊钱包地址

你可以通过以太坊命令行客户端geth轻松获取一个以太坊地址,如下:

[work@host]$ geth account newINFO [05-22|10:17:57] 最大对等点数 ETH=25 LES=0 total=25你的新账户被密码锁定了。 请给个密码。 不要忘记这个密码。 密码:重复密码:地址:{07a78fc0fb8c175d8e09e942086985d2835b6849}

地址0x07a78fc0fb8c175d8e09e942086985d2835b6849是新生成的以太坊地址。

2、地址生成与解析

下面跟踪geth的源码: 分析其地址生成过程。 geth用于命令行解析,运行geth account new时的入口在cmd/geth/main.go:

func init() {// 初始化 CLI 应用程序并启动 Gethapp.Action = geth...app.Commands = []cli.Command{...// See accountcmd.go:accountCommand,...}... }

账户相关的命令在cmd/geth/accountcmd.go,新建账户的命令是:

var (accountCommand = cli.Command{Name: "account",Usage: "Manage accounts", 类别: "ACCOUNT COMMANDS", 描述: ``,Subcommands: []cli.Command{...{Name: "new" ,用法:“创建新帐户”,操作:utils.MigrateFlags(accountCreate),标志:[]cli.Flag{utils.DataDirFlag以太坊地址生成算法,utils.KeyStoreDirFlag,utils.PasswordFileFlag,utils.LightKDFFlag,},描述:``, },...},})

但是当创建一个新帐户时,accountCreate 将被调用:

// accountCreate 在 CLI flags.func accountCreate(ctx *cli.Context) error { // (1) 获取配置 cfg := gethConfig{Node: defaultNodeConfig()} // 加载配置文件.if 文件 := ctx.GlobalString(configFileFlag.Name); file != "" {if err := loadConfig(file, &cfg); err != nil {utils.Fatalf("%v", err)}}utils .SetNodeConfig(ctx, &cfg.Node)scryptN, scryptP, keydir, err := cfg.Node.AccountConfig()if err != nil { utils.Fatalf("Failed to read configuration: %v", err)} // (2) 分析用户密码 password := getPassPhrase("您的新账户被密码锁定,请提供密码,不要忘记这个密码.", true, 0, utils.MakePasswordList(ctx)) // (3) 生成地址address, err := keystore.StoreKey(keydir, password, scryptN, scryptP)if err != nil {utils.Fatalf("Failed创建账户:%v", err)}fmt.Printf("Address: { %x}\n", address)return nil}

分为三个步骤:

获取配置,解析用户密码,生成地址

第三步生成地址调用keystore.StoreKey(accounts/keystore/keystore_passphrase.go):

// StoreKey 生成一个密钥,用 'auth' 加密并存储在给定的目录中, scryptN, scryptP}, crand.Reader, auth) 返回 a.Address, err}

这里直接调用storeNewKey(accounts/keystore/key.go)创建一个新账户:

func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, accounts.Account, error) {// 创建一个新的账户密钥,err := newKey(rand)if err != nil {return nil, accounts .Account{}, err}a := accounts.Account{地址: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: ks.JoinPath(keyFileName(key.Address))}}if err := ks .StoreKey(a.URL.Path, key, auth); err != nil {zeroKey(key.PrivateKey)return nil, a, err}return key, a, err}func newKey(rand io.Reader) (* Key, error) {// (1) 生成公钥和私钥privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand)if err != nil {return nil, err}// (2) 通过从公钥计算地址并构建自定义Key return newKeyFromECDSA(privateKeyECDSA ), 无}

如您所见,当 newKey 创建新帐户时,

私钥由secp256k1曲线生成,由随机的256位组成。 椭圆曲线数字签名算法(ECDSA)用于将私钥映射为公钥。 一个私钥只能映射到一个公钥。 然后从公钥计算出地址,构建自定义Key

第三步的代码如下:

func newKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) *Key {id := uuid.NewRandom()key := &Key{Id:id,Address: crypto.PubkeyToAddress(privateKeyECDSA.PublicKey),PrivateKey: privateKeyECDSA,}返回密钥}

从公钥计算出的地址由 crypto.PubkeyToAddress (crypto/crypto.go) 完成:

func PubkeyToAddress(p ecdsa.PublicKey) common.Address {pubBytes := FromECDSAPub(&p) return common.BytesToAddress(Keccak256(pubBytes[1:])[12:])}// Keccak256计算并返回输入的Keccak256哈希data.func Keccak256(data ...[]byte) []byte {d := sha3.NewKeccak256()for _, b := range data {d.Write(b)}return d.Sum(nil)}

可以看到公钥通过Keccak-256单向哈希函数变成了256bit,然后用160bit作为地址。 本质上,它将 256 位私钥映射到 160 位公共地址。 这意味着一个帐户可以拥有多个私钥。

三、总结

一般来说,以太坊地址的生成过程如下: 1. 私钥由secp256k1曲线生成以太坊地址生成算法,由随机的256位组成。 2. 使用椭圆曲线数字签名算法 (ECDSA) 将私钥映射到公钥。 3、公钥通过Keccak-256单向哈希函数变成256bit,然后取160bit作为地址