基本概念:
以太坊地址是用于在以太坊网络上接收和发送以太币(ETH)以及执行智能合约的标识符。
主要特点:
长度和格式:
- 以太坊地址通常是42个字符长,以“0x”开头,后面跟随40个十六进制字符(0-9, a-f)。
- 例如:
0x742d35Cc6634C0532925a3b844Bc454e4438f44e
生成方式:
- 以太坊地址是通过公钥生成的。具体来说,公钥经过椭圆曲线数字签名算法(ECDSA)生成,然后通过Keccak-256哈希函数处理,取最后20个字节作为地址。
大小写不敏感:
- 以太坊地址在比较时是大小写不敏感的,这意味着
0x742d35Cc6634C0532925a3b844Bc454e4438f44e
和0x742D35cC6634c0532925A3B844bC454E4438F44E
被视为相同的地址。
一个容易混淆的点:
在讨论以太坊地址的长度时,“字符”和“字节”并不是同一个意思。
字符:
- 以太坊地址通常是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
评论前必须登录!
注册