# EIP 55: 混合大小写校验和地址编码
作者 | 类型 | 分类 | 状态 | 创建时间 |
---|---|---|---|---|
Vitalik Buterin vitalik.buterin@ethereum.org, Alex Van de Sande avsa@ethereum.org | Standards Track | ERC | Final | 2016-01-14 |
# 规范
代码:
from ethereum import utils
def checksum_encode(addr): # Takes a 20-byte binary address as input
o = ''
v = utils.big_endian_to_int(utils.sha3(addr.hex()))
for i, c in enumerate(addr.hex()):
if c in '0123456789':
o += c
else:
o += c.upper() if (v & (2**(255 - 4*i))) else c.lower()
return '0x'+o
def test(addrstr):
assert(addrstr == checksum_encode(bytes.fromhex(addrstr[2:])))
test('0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed')
test('0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359')
test('0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB')
test('0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
在英语中,将地址转换为十六进制,但如果它的第 i
位是字母(即 abcdef 之一)则有:如果小写的十六进制地址的哈希值的第i*4
位为 1,则大写形式打印,否则小写形式打印。
# 原理阐述
优点:
- 向后兼容许多接受混合大小写的十六进制解析器,允许它随着时间的推移轻松引入
- 保持长度为40个字符
- 平均每个地址将有15个校验位,如果输入错误,随机生成的地因抄写错误意外通过检查的净概率为0.0247%。 这比ICAP提高了约50倍,但不如4字节检查代码好。
ICAP: Inter-exchange Client Address Protocal 是与国际银行账号(IBAN)编码部分兼容的以太坊地址编码形式。
# 实现
javascript代码:
const createKeccakHash = require('keccak')
function toChecksumAddress (address) {
address = address.toLowerCase().replace('0x', '')
var hash = createKeccakHash('keccak256').update(address).digest('hex')
var ret = '0x'
for (var i = 0; i < address.length; i++) {
if (parseInt(hash[i], 16) >= 8) {
ret += address[i].toUpperCase()
} else {
ret += address[i]
}
}
return ret
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
> toChecksumAddress('0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359')
'0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359'
1
2
2
请注意,Keccak256哈希的输入是小写十六进制字符串(即编码为ASCII的十六进制地址):
var hash = createKeccakHash('keccak256').update(Buffer.from(address.toLowerCase(), 'ascii')).digest()
1
# 测试用例
# All caps
0x52908400098527886E0F7030069857D2E4169EE7
0x8617E340B3D01FA5F11F306F4090FD50E238070D
# All Lower
0xde709f2102306220921060314715629080e2fb77
0x27b1fdb04752bbc536007a920d24acb045561c26
# Normal
0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed
0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359
0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB
0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 采用情况
Wallet | displays checksummed addresses | rejects invalid mixed-case | rejects too short | rejects too long |
---|---|---|---|---|
Etherwall 2.0.1 | Yes | Yes | Yes | Yes |
Jaxx 1.2.17 | No | Yes | Yes | Yes |
MetaMask 3.7.8 | Yes | Yes | Yes | Yes |
Mist 0.8.10 | Yes | Yes | Yes | Yes |
MyEtherWallet v3.9.4 | Yes | Yes | Yes | Yes |
Parity 1.6.6-beta (UI) | Yes | Yes | Yes | Yes |
Jaxx Liberty 2.0.0 | Yes | Yes | Yes | Yes |
Coinomi 1.10 | Yes | Yes | Yes | Yes |
Trust Wallet | Yes | Yes | Yes | Yes |
# Exchange support for mixed-case address checksums, as of 2017-05-27:
Exchange | displays checksummed deposit addresses | rejects invalid mixed-case | rejects too short | rejects too long |
---|---|---|---|---|
Bitfinex | No | Yes | Yes | Yes |
Coinbase | Yes | No | Yes | Yes |
GDAX | Yes | Yes | Yes | Yes |
Kraken | No | No | Yes | Yes |
Poloniex | No | No | Yes | Yes |
Shapeshift | No | No | Yes | Yes |
# 参考引用
- EIP 55 issue and discussion https://github.com/ethereum/eips/issues/55
- Python example by @Recmo https://github.com/ethereum/eips/issues/55#issuecomment-261521584
- Python implementation in
ethereum-utils
- Ethereumjs-util implementation https://github.com/ethereumjs/ethereumjs-util/blob/75f529458bc7dc84f85fd0446d0fac92d991c262/index.js#L452-L466
- Swift implementation in
EthereumKit
- Kotlin implementation in
KEthereum