以太坊地址格式
以太坊地址是十六进制数字,从公钥的Keccak-256哈希的最后20个字节导出的标识符。
与在所有客户端的用户界面中编码的比特币地址不同,它们包含内置校验和来防止输入错误的地址,以太坊地址以原始十六进制形式呈现,没有任何校验和。
该决定背后的基本原理是,以太坊地址最终会隐藏在系统高层的抽象(如名称服务)之后,并且必要时应在较高层添加校验和。
回想起来,这种设计选择导致了一些问题,包括由于输入错误地址和输入验证错误而导致的资金损失。以太坊名称服务的开发速度低于最初的预期,诸如ICAP之类的替代编码被钱包开发商采用得非常缓慢。
互换客户端地址协议 Inter Exchange Client Address Protocol (ICAP)
_互换客户端地址协议(ICAP)_是一种部分与国际银行帐号(IBAN)编码兼容的以太坊地址编码,为以太坊地址提供多功能,校验和互操作编码。ICAP地址可以编码以太坊地址或通过以太坊名称注册表注册的常用名称。
阅读以太坊Wiki上的ICAP:https://github.com/ethereum/wiki/wiki/ICAP:-Inter-exchange-Client-Address-Protocol
IBAN是识别银行账号的国际标准,主要用于电汇。它在欧洲单一欧元支付区(SEPA)及其以后被广泛采用。IBAN是一项集中和严格监管的服务。ICAP是以太坊地址的分散但兼容的实现。
一个IBAN由含国家代码,校验和和银行账户标识符(特定国家)的34个字母数字字符(不区分大小写)组成。
ICAP使用相同的结构,通过引入代表“Ethereum”的非标准国家代码“XE”,后面跟着两个字符的校验和以及3个可能的账户标识符变体:
Direct
最多30个字母数字字符big-endian base-36整数,表示以太坊地址的最低有效位。由于此编码适合小于155位,因此它仅适用于以一个或多个零字节开头的以太坊地址。就字段长度和校验和而言,它的优点是它与IBAN兼容。示例:XE60HAMICDXSV5QXVJA7TJW47Q9CHWKJD(33个字符长)
Baasic
与“Direct”编码相同,只是长度为31个字符。这使它可以编码任何以太坊地址,但使其与IBAN字段验证不兼容。示例:XE18CHDJBPLTBCJ03FE9O2NS0BPOJVQCU2P(35个字符长)
Indrect
编码通过名称注册表提供程序解析为以太坊地址的标识符。使用由_asset identifier_(例如ETH),名称服务(例如XREG)和9个字符的名称(例如KITTYCATS)组成的16个字母数字字符,这是一个人类可读的名称。示例:XE## ETHXREGKITTYCATS(20个字符长),其中“##”应由两个计算校验和字符替换。
我们可以使用 helpeth 命令行工具来创建ICAP地址。让我们尝试使用我们的示例私钥(前缀为0x并作为参数传递给helpeth):
$ helpeth keyDetails -p 0xf8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315
Address: 0x001d3f1ef827552ae1114027bd3ecf1f086ba0f9
ICAP: XE60 HAMI CDXS V5QX VJA7 TJW4 7Q9C HWKJ D
Public key: 0x6e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0
helpeth 命令为我们构建了一个十六进制以太坊地址以及一个ICAP地址。我们示例密钥的ICAP地址是:
XE60HAMICDXSV5QXVJA7TJW47Q9CHWKJD
由于我们的示例以太坊地址恰好以零字节开始,因此可以使用IBAN格式中有效的“Direct”ICAP编码方法进行编码。因为它是33个字符长。
如果我们的地址不是从零开始,那么它将被编码为“Basic”编码,这将是35个字符长并且作为IBAN格式无效。
Tip | 以零字节开始的任何以太坊地址的概率是1/256。为了生成这样一个类型,在我们找到一个作为IBAN兼容的“Direct”编码之前,它将平均用256个不同的随机私钥进行256次尝试ICAP地址。 |
不幸的是,现在,只有几个钱包支持ICAP。
使用大写校验和的十六进制编码 (EIP-55)
由于ICAP或名称服务部署缓慢,因此提出了一个新的标准,以太坊改进建议55(EIP-55)。你可以阅读详细信息:
https://github.com/Ethereum/EIPs/blob/master/EIPS/eip-55.md
通过修改十六进制地址的大小写,EIP-55为以太坊地址提供了向后兼容的校验和。这个想法是,以太坊地址不区分大小写,所有钱包都应该接受以大写字母或小写字母表示的以太坊地址,在解释上没有任何区别。
通过修改地址中字母字符的大小写,我们可以传达一个校验和,可以用来保护地址完整性,防止输入或读取错误。不支持EIP-55校验和的钱包简单地忽略地址包含混合大写的事实。但那些支持它的人可以验证它并以99.986%的准确度检测错误。
混合大小写编码很微妙,最初你可能不会注意到它。我们的示例地址是:
0x001d3f1ef827552ae1114027bd3ecf1f086ba0f9
使用 EIP-55 混合大小写校验和,它变为:
0x001d3F1ef827552Ae1114027BD3ECF1f086bA0F9
你能看出区别吗?一些来自十六进制编码字母表的字母(AF)字符现在是大写字母,而另一些则是小写字母。除非你仔细观察,否则你甚至可能没有注意到其中的差异。
EIP-55实施起来相当简单。我们采用小写十六进制地址的Keccak-256哈希。这个哈希作为地址的数字指纹,给我们一个方便的校验和。输入(地址)中的任何小改动都会导致哈希结果(校验和)发生很大变化,从而使我们能够有效地检测错误。然后我们的地址的哈希被编码为地址本身的大写字母。让我们一步步分解它:
- 计算小写地址的哈希,不带 0x 前缀::
Keccak256("001d3f1ef827552ae1114027bd3ecf1f086ba0f9")
23a69c1653e4ebbb619b0b2cb8a9bad49892a8b9695d9a19d8f673ca991deae1
- 如果哈希的相应十六进制数字大于或等于 0x8,则将每个字母地址字符大写。如果我们排列地址和哈希,这将更容易显示:
Address: 001d3f1ef827552ae1114027bd3ecf1f086ba0f9
Hash : 23a69c1653e4ebbb619b0b2cb8a9bad49892a8b9...
我们的地址在第四个位置包含一个字母 d。哈希的第四个字符是 6,小于+8+。所以,我们保持 d 小写。我们地址中的下一个字母字符是 f,位于第六位。十六进制哈希的第六个字符是 c,它大于+8 。因此,我们在地址中大写 +F,等等。正如你所看到的,我们只使用哈希的前20个字节(40个十六进制字符)作为校验和,因为我们只有20个字节(40个十六进制字符)能正确地大写。
检查自己产生的混合大写地址,看看你是否可以知道在地址哈希中哪些字符被大写和它们对应的字符:
Address: 001d3F1ef827552Ae1114027BD3ECF1f086bA0F9
Hash : 23a69c1653e4ebbb619b0b2cb8a9bad49892a8b9...
在EIP-55编码地址中检测错误
现在,我们来看看EIP-55地址如何帮助我们发现错误。假设我们已经打印出ETHER-E编码的以太坊地址:
0x001d3F1ef827552Ae1114027BD3ECF1f086bA0F9
现在,让我们在阅读该地址时犯一个基本错误。最后一个字符之前的字符是大写字母“F”。对于这个例子,我们假设我们误解为大写“E”。我们在钱包中输入(不正确的地址):
0x001d3F1ef827552Ae1114027BD3ECF1f086bA0E9
幸运的是,我们的钱包符合EIP-55标准!它注意到混合大写字母并试图验证地址。它将其转换为小写,并计算校验和哈希值:
Keccak256("001d3f1ef827552ae1114027bd3ecf1f086ba0e9")
5429b5d9460122fb4b11af9cb88b7bb76d8928862e0a57d46dd18dd8e08a6927
如你所见,即使地址只改变了一个字符(事实上,“e”和“f”只相隔1位),地址的哈希值已经根本改变了。这是哈希函数的特性,使它们对校验和非常有用!
现在,让我们排列这两个并检查大小写:
001d3F1ef827552Ae1114027BD3ECF1f086bA0E9
5429b5d9460122fb4b11af9cb88b7bb76d892886...
这都是错的!几个字母字符不正确地大写。请记住,大写是_正确的_校验和的编码。
我们输入的地址的大小写与刚刚计算的校验和不匹配,这意味着地址中的内容发生了变化,并且引入了错误。