生成钱包

以太坊的钱包是基于椭圆曲线数字签名算法ECDSA保护的。

因此每一个钱包对应的是一个ECDSA的密钥对。

这个密钥对在 go-ethereum 项目的 crypto/crypto.goGenerateKey() 函数生成,
生成后得到一个ECDSA的私钥 (ecdsa.PrivateKey)。

以太坊所采用的椭圆曲线是 secp256k1。由于其特殊构造的特殊性,其优化后的实现比其他曲线性能上可以提高30%,有明显以下两个优点:

  1. 占用很少的带宽和存储资源,密钥的长度很短;
  2. 让所有的用户都可以使用同样的操作完成域运算。

生成钱包私钥代码:

1
2
3
func GenerateKey() (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(S256(), rand.Reader)
}

得到私钥后,可以使用 ecdsa.PrivateKeyPublic() 方法取得公钥 ecdsa.PublicKey

生成一般的钱包地址

以太坊钱包地址长度为20字节,来源于前面我们生成的钱包公钥 ecdsa.PublicKey

简单来说就是计算一下钱包公钥的 Keccak256 哈希值,再取出末尾20字节作为钱包地址(本身 Keccak256 输出32字节)。

生成钱包地址源代码:

1
2
3
4
5
6
7
8
9
10
11
func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
if pub == nil || pub.X == nil || pub.Y == nil {
return nil
}
return elliptic.Marshal(S256(), pub.X, pub.Y)
}

func PubkeyToAddress(p ecdsa.PublicKey) common.Address {
pubBytes := FromECDSAPub(&p)
return common.BytesToAddress(Keccak256(pubBytes[1:])[12:])
}

生成智能合约的地址

智能合约的地址其实与拥有者用户钱包有关。但由于我们不可能直接拿钱包的公钥作为智能合约地址(这样就会与钱包地址冲突),所以就需要在原钱包地址的基础上增加一个唯一的独立数 Nonce
这样就可以确保某个钱包的拥有者可以生成出不同的智能合约地址啦。

注意,智能合约的 Nonce 与生成该智能合约的交易 Tx 的交易 nonce 有关。因为每一笔交易的nonce都是独立的,所以可以智能合约的nonce也是可以视为独立的。

生成智能合约的地址源码:

1
2
3
4
func CreateAddress(b common.Address, nonce uint64) common.Address {
data, _ := rlp.EncodeToBytes([]interface{}{b, nonce})
return common.BytesToAddress(Keccak256(data)[12:])
}

生成智能合约地址使用参考:

1
2
3
4
5
6
// The contract address can be derived from the transaction itself
if transactions[j].To() == nil {
// Deriving the signer is expensive, only do if it's actually needed
from, _ := types.Sender(signer, transactions[j]) // 获取一下发送者的公钥
receipts[j].ContractAddress = crypto.CreateAddress(from, transactions[j].Nonce()) // 直接将Tx的Nonce作为智能合约的Nonce
}

以上是以太坊专题第一部分钱包地址的内容。

除非注明,麦麦小家文章均为原创,转载请以链接形式标明本文地址。

版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)

本文地址:https://blog.micblo.com/2019/02/26/%E4%BB%A5%E5%A4%AA%E5%9D%8A%E4%B8%93%E9%A2%98-%E9%92%B1%E5%8C%85%E5%9C%B0%E5%9D%80/