详解以太坊地址生成实战

  • Louis
  • 更新于 2024-10-19 21:22
  • 阅读 817

基本概念:以太坊地址是用于在以太坊网络上接收和发送以太币(ETH)以及执行智能合约的标识符。主要特点:长度和格式:以太坊地址通常是42个字符长,以“0x”开头,后面跟随40个十六进制字符(0-9,a-f)

基本概念:

以太坊地址是用于在以太坊网络上接收和发送以太币(ETH)以及执行智能合约的标识符。

主要特点:

长度和格式:

  • 以太坊地址通常是42个字符长,以“0x”开头,后面跟随40个十六进制字符(0-9, a-f)。
  • 例如:0x742d35Cc6634C0532925a3b844Bc454e4438f44e

生成方式:

  • 以太坊地址是通过公钥生成的。具体来说,公钥经过椭圆曲线数字签名算法(ECDSA)生成,然后通过Keccak-256哈希函数处理,取最后20个字节作为地址。

大小写不敏感:

  • 以太坊地址在比较时是大小写不敏感的,这意味着0x742d35Cc6634C0532925a3b844Bc454e4438f44e0x742D35cC6634c0532925A3B844bC454E4438F44E被视为相同的地址。

一个容易混淆的点:

在讨论以太坊地址的长度时,“字符”和“字节”并不是同一个意思。

字符

  • 以太坊地址通常是42个字符长,这里的“字符”指的是十六进制字符。每个字符代表一个十六进制数字(0-9, a-f)。
  • 例如,地址 0x742d35Cc6634C0532925a3b844Bc454e4438f44e 中的每个字符都是一个十六进制字符。

字节

  • 字节是计算机存储和传输数据的基本单位,每个字节由8个二进制位组成,可以表示0到255之间的数值。
  • 在以太坊地址的上下文中,地址实际上是由20个字节组成的。每个字节可以表示0到255之间的数值,或者用两个十六进制字符表示。

因此,以太坊地址的42个字符实际上对应20个字节。具体来说:

  • 地址的前缀“0x”是用来标识这是一个十六进制数,不算在字节数内。
  • 剩下的40个字符(每个字符代表4个二进制位)总共有 160 个二进制位,8 个二进制位对应一个字节,所以总共对应20个字节。

以太坊地址生成的步骤:

有了前面的基础铺垫,我们来看看生成以太坊地址的步骤,主要包括公钥生成、哈希处理和地址格式化:

1. 生成私钥

  • 私钥是一个256位的随机数,通常表示为一个64个字符长的十六进制字符串。
  • 例如:0x56f7572f1df6e5df159ae3f8880d87b2b31b760d5b259a015e00f2eb9c91f51e

2. 从私钥生成公钥

  • 使用椭圆曲线数字签名算法(ECDSA)的secp256k1曲线,从私钥生成公钥。
  • 公钥是一个65字节(520位)的数字,通常表示为一个130个字符长的十六进制字符串,前缀为0x04
  • 例如:0x049a7df67f79246283fdc93af76d4f8cdd62c4886e8cd870944e817dd9620b01df355b40c9a99da1498434b1a3de3ff98f6f0f3b962d7d67e37c1b3710a3c8d166

3. 从公钥生成地址

  • 步骤1:去掉公钥的前缀0x04,得到一个64字节(512位)的数字。
  • 步骤2:对这个64字节的数字进行Keccak-256哈希处理。

<!---->

    • Keccak-256是一种哈希函数,输出一个32字节(256位)的哈希值。
    • 例如:0xa3f20717a250c2b0b729b7e5beca956cb2cf50e4c808034f295034f54c4f43e9

<!---->

  • 步骤3:取哈希值的最后20个字节(160位)作为以太坊地址。

<!---->

    • 例如:0x742d35Cc6634C0532925a3b844Bc454e4438f44e

4. 格式化地址

  • 以太坊地址通常以0x开头,后面跟随40个十六进制字符。
  • 例如:0x742d35Cc6634C0532925a3b844Bc454e4438f44e

5. 可选:校验和地址

  • 为了提高安全性,以太坊地址可以使用校验和机制。
  • 校验和地址在生成时会根据特定的算法将某些字符转换为大写,以帮助用户识别输入错误。
  • 例如:0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed

基于 Bip32 和 Bip39 生成以太坊地址:

我们可以借助一些社区好用的库,比如 @ethereumjs/wallet 来简化我们实现。

import { hdkey } from '@ethereumjs/wallet';

export function createEthAddress(
  seedHex: string,
  addressIndex: string
): { privateKey: string; publicKey: string; address: string } {
  const seed = Buffer.from(seedHex, 'hex');
  const path = `m/44'/60'/0'/0/${addressIndex}`;
  const hdNode = hdkey.EthereumHDKey.fromMasterSeed(seed);
  const derivedNode = hdNode.derivePath(path);

  return {
    privateKey: derivedNode.getWallet().getPrivateKeyString(),
    publicKey: derivedNode.getWallet().getPublicKeyString(),
    address: derivedNode.getWallet().getAddressString()
  };
}

相关测试函数:

import { mnemonicToSeedSync } from 'bip39';

const mnemonic =
      'lounge face pattern cinnamon shrug average spend rapid field cheese wrist weather';
const seed = mnemonicToSeedSync(mnemonic);
const account = createEthAddress(seed.toString('hex'), '0');
const { privateKey, address } = account;
console.log('privateKey', privateKey);
console.log('address', address); // 0x349a04e26abb45310427cee5a25ebdb84869c52e
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Louis
Louis
web3 developer,技术交流或者有工作机会可加VX: magicalLouis