ENS 域名处理

ENS 只使用固定长度的256位加密哈希来代替可读的域名。为了从域名派生哈希的同时仍然保留其层次性,使用了名为 Namehash 的算法。例如,“alice.eth” 的 Namehash 为 0x787192fc5378cc32aa956ddfdedbf26b24e8d78e40109add0eea2c1a012c3dec ,这是域名在 ENS 内部的唯一表示方式。

在使用 Namehash 进行哈希之前,首先使用 UTS-46 标准对域名进行规范化,确保域名中的字母与大小写无关,并禁止使用无效字符。任何对域名进行哈希和解析的操作都必须首先对其进行规范化,以确保所有用户获得 ENS 的一致性。

规范化域名

在使用 Namehash 将域名转换为哈希节点之前,必须首先对域名进行规范化和有效性检查(比如将 fOO.eth 规范为 _foo.eth_)并屏蔽包含下划线等禁止字符的域名。更为关键的是,所有应用程序都必须遵循相同的规范化和验证规则集,否则相同的字符输入到不同系统上可能会被解析为两个不同的 ENS 域名。

使用ENS和处理可读域名的应用程序在进行规范化和验证时必须遵循 UTS46 。处理过程应该通过设置 UseSTD3ASCIIRules=true 采用非过渡规则。

eth-ens-namehash 这一 Javascript 库会执行这里描述的规范化和哈希。DApp 开发者指南中涉及的所有 ENS 库 都会执行规范化和哈希。

对域名进行哈希

Namehash 是一个递归过程,可以为任何有效的域名生成唯一的哈希。从任意一个域名的 Namehash 开始(比如 “alice.eth” 的 Namehash)可以推导出任意子域名的 Namehash(比如 “iam.alice.eth” 的 Namehash),而且推导过程中不需要知道或处理 “alice.eth” 这个可读的原始域名。正是这个特性使得 ENS 能够成为一个层次性的系统,且不必在内部处理可读的文本字符串。

术语

  • 域名(domain)- ENS 标识符的完整且可读的形式,比如 iam.alice.eth
  • 标签(label)- 域名的独立组成部分 - 比如:iamaliceeth
  • 标签哈希(label hash)- 单个标签经过 keccak256 函数计算后的输出值,比如:keccak256(‘eth’) = 0x4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0
  • 节点(node)- namehash 函数的输出值,用作 ENS 域名的唯一性标识。

算法

首先,按点(“.”)分隔将域名划分为标签。所以,“vitalik.wallet.eth” 变成了列表[“vitalik”, “wallet”, “eth”]。

然后按递归的方式定义 namehash 函数如下:

namehash([]) = 0x0000000000000000000000000000000000000000000000000000000000000000
namehash([label, …]) = keccak256(namehash(…), keccak256(label))

下面是用 Python 实现 namehash 的示例。

def namehash(name):
if name == '':
return '\0' * 32
else:
label, _, remainder = name.partition('.')
return sha3(namehash(remainder) + sha3(label))

Namehash 在 EIP137 中有详细的说明。

不明确域名的处理

由于 unicode 中有大量的字符,而且所表示的脚本种类繁多,因此不可避免地会出现不同的 unicode 字符,这些字符在常用字体中是相似的,甚至是相同的。这一点可能会被用来欺骗用户,让用户以为他们正在访问某个站点或资源,而实际上他们正在访问是另一个站点或资源。即所谓的 “同形攻击” 。

向用户显示域名的客户端和其他软件应该针对这些攻击采取对策,比如突出显示有问题的字符,或者向用户显示混合脚本的警告。Chromium 的 IDN 策略 对于呈现 IDN 名称时的客户端行为具备一定的参考价值。

转载本站内容请注明出处和链接。咨询 ENS 问题请前往 问答区,其他问题请联系 团队成员