CIP-37: 引入一种新的地址格式帮助用户区分 Conflux 和以太坊的地址

327 阅读10分钟

英文原文:github.com/Conflux-Cha…

简要概括

本 CIP 引入了一种新的地址格式,帮助用户区分 Conflux 和以太坊的地址。

摘要

除了目前 Conflux 使用的包含类型前缀的十六进制地址,我们引入了一种新的 base32 编码地址(base32-encoded address)格式。这种新格式的地址直接由十六进制地址中衍生而来,包含一个容易辨认的前缀(如"cfx")和一个校验和。使用 base32 校验编码(base32check)能帮我们检测并避免输入错误,让我们简单分辨 Conflux 与其他链上的地址,减轻资产损失的风险。

新地址格式例如:cfx:00d2z01m2g4p77n6mddvtaw2k43622daamm1867uk6.

目标

目前的 Conflux 和以太坊地址非常相似,很多情况下它们是可以互相兼容的,例如,一些以太坊上的地址(0x1开头地址)在 Conflux 上也是有效的,,Conflux地址在以太坊上有1/16的概率可行,(有资产丢失的可能)。这就引起了许多用户不小心将以太坊上的资产转移到一个 Conflux 地址中,产生丢失资产的情况,尤其是在进行跨链操作时。与以太坊不兼容的新的地址类型可以被 Metamask 这样的工具检测出来,从而避免将错误的交易提交至网络。

规范

(本章节部分内容参考自比特币现金 Bitcoin Cash 规范。)

本章节定义的转换是在以下两种地址类型之间的转换:

  • Conflux 十六进制地址:有效的20字节的类型前缀 Conflux 十六进制地址,如0x106d49f8505410eb4e671d51f7d96d2c87807b09。由公钥产生这种地址的方式在协议规范的公式(1)中有定义,这个地址的字符串可以选择性地使用大小写混合校验和地址编码EIP-55)。

  • Conflux base32 地址:网络前缀 Conflux base32 校验和地址。这种地址由网络前缀(network-prefix)、冒号(":")和 base32 编码负载组成。网络前缀表明该地址在哪个网络上有效,base32 编码负载(payload)表示地址的指向目标,包含一个校验和,如cfx:0086ujfsa1a11uuecwen3xytdmp8f03v140ypk3mxc。同时,该地址中也可以选择在网络前缀和负载之间以 key.value 的形式包含一个键值对(key value pairs)列表,用冒号分开,如cfx:type.user:0086ujfsa1a11uuecwen3xytdmp8f03v140ypk3mxc

编码

输入值:addr(20字节的 Conflux 十六进制地址),网络 ID network-id(4字节)

输出值:Conflux base32 地址

  1. 网络前缀(Network-prefix):
    match network-id:
        case 1029: "cfx"
        case 1:    "cfxtest"
        case n:    "net[n]"

有效网络前缀示例:"cfx""cfxtest""net17"

无效网络前缀示例:"bch""conflux""net1""net1029"

  1. 【可选】地址类型:
    match addr[0] & 0xf0
        case b00000000: "type.builtin"
        case b00010000: "type.user"
        case b10000000: "type.contract"

可以用"type.null"实现空地址(0x0000000000000000000000000000000000000000)。

  1. 版本字节: 版本字节的最高位被保留,并且必须为0,接下来的4位表示地址类型,最末3位表示哈希大小。
类型位含义版本字节值
0Conflux0

新功能增加时,可能会添加更多类型。

大小位后3位哈希大小
0160
1192
2224
3256
4320
5384
6448
7512

在版本域中编码哈希大小,我们就可以确保能够检查地址长度是否正确。

  1. base-32 编码地址: 要创建负载,首先要把版本字节(version-type)和地址(addr)结合起来,得到一个21字节的数组,然后从左到右编码,将每一个5位序列号映射为对应的 ASCII 字母(对照表见下方)。在右边用零位填充,补充结尾处未满的位数。这种情况下,21字节的负载+2位零位填充就形成了一个34字节的base32编码字符串。

我们使用的字母有:abcdefghjkmnprstuvwxyz0123456789(移除了oilq )。

0x00 => a    0x08 => j    0x10 => u    0x18 => 2
0x01 => b    0x09 => k    0x11 => v    0x19 => 3
0x02 => c    0x0a => m    0x12 => w    0x1a => 4
0x03 => d    0x0b => n    0x13 => x    0x1b => 5
0x04 => e    0x0c => p    0x14 => y    0x1c => 6
0x05 => f    0x0d => r    0x15 => z    0x1d => 7
0x06 => g    0x0e => s    0x16 => 0    0x1e => 8
0x07 => h    0x0f => t    0x17 => 1    0x1f => 9
  1. 计算校验和:我们采用比特币现金的校验和算法,定义如下:
uint64_t PolyMod(const data &v) {
    uint64_t c = 1;
    for (uint8_t d : v) {
        uint8_t c0 = c >> 35;
        c = ((c & 0x07ffffffff) << 5) ^ d;

        if (c0 & 0x01) c ^= 0x98f2bc8e61;
        if (c0 & 0x02) c ^= 0x79b76d99e2;
        if (c0 & 0x04) c ^= 0xf33e5fb3c4;
        if (c0 & 0x08) c ^= 0xae2eabe2a8;
        if (c0 & 0x10) c ^= 0x1e4f43e470;
    }

    return c ^ 1;
}

校验和根据以下数据计算而来:

  • 前缀每一个字母的后5位,如“cfx”变为 0x03, 0x06, 0x18, ...
  • 0作为分隔符(5个零位)。
  • 5位为一部分组成的负载,如果必要的话,负载用零位填充到右边,补充结尾处未满的位数。
  • 八个0作为校验和的模板

请注意,可选域(如address-type)不包含在校验和计算之中。

PolyMod 返回的40位数值被分为8个5位数值(最低位优先),随后,负载和校验和根据base32 字母表编码。

  1. 把以下几个部分结合起来得到最终地址:网络前缀([network-prefix])、":"、负载([payload])和校验和([checksum])
  • 可选项地址类型也可以包含在内:网络前缀([network-prefix])、":"、地址类型([address-type])、":"、负载([payload])和校验和([checksum])

解码

输入值:Conflux base32 地址

输出值:Conflux 十六进制地址(20字节)和网络 ID (4字节)

  1. 将地址当作一个 ASCII 字符串处理,如果是大小写混合,则拒绝。将地址转变为小写,用":"隔开。如果生成的数组少于2个项目,拒绝。将第一个项目当作network-prefix-raw(原始网络前缀),最后一个项目当作payload-raw(原始负载),中间的项目为可选键值对。

  2. 分析网络 ID:

    match network-prefix-raw
        case "cfx":     1029
        case "cfxtest": 1
        case "net1029": reject
        case "net1":    reject
        case "net[n]":  n if n fits into 4 bytes
        otherwise:      reject
  1. 使用对照表将 base32 格式的payload-raw转变为字节,验证校验和。 如果payload-raw包含任何为验证的字母(不在对照表中),则拒绝。

验证 base32 格式地址,PolyMod 函数的输入数据(整数列表)包含以下几个部分:

  • 前缀每个字的后5位。
  • 零位分隔符(5个零位)。
  • 负载的每一个 base32 字符都被映射为对应的数字。

如果 PolyMod 返回非零,则表明地址损坏,拒绝。

  1. payload-raw转变为一个8位数组,分割成版本字节(version-byte)和地址字节(addr-bytes)。

  2. 验证版本字节(version-byte)中的类型和大小位,未知版本会被拒绝。

  3. 验证可选域:

  • 如果可选域包含type.*:根据以上规范验证地址类型(address-type)。
  • 忽略未知可选域(非type.*的可选域)

返回(addr-bytes, network-id)

*(请注意:Conflux 节点需要证实network-id并非它们的本地网络 ID,并且拒绝不符合的地址,这项检查并不包含在规范之内。)

示例

encode(0x106d49f8505410eb4e671d51f7d96d2c87807b09, 1029, true)

1. network-prefix: 1029 => "cfx"
2. address-type: "type.user"
3. version-byte: 0x00
4. payload: [0x00, 0x10, 0x6d, 0x49, 0xf8, 0x50, 0x54, 0x10, 0xeb, 0x4e, 0x67, 0x1d, 0x51, 0xf7, 0xd9, 0x6d, 0x2c, 0x87, 0x80, 0x7b, 0x09]
   5-bit parts: [0x00, 0x00, 0x08, 0x06, 0x1a, 0x12, 0x0f, 0x18, 0x0a, 0x01, 0x0a, 0x01, 0x01, 0x1a, 0x1a, 0x0e, 0x0c, 0x1c, 0x0e, 0x15, 0x03, 0x1d, 0x1e, 0x19, 0x0d, 0x14, 0x16, 0x08, 0x0f, 0x00, 0x03, 0x1b, 0x01, 0x04]
   base32-encoded: "0086ujfsa1a11uuecwen3xytdmp8f03v14"
5. checksum input: [0x03, 0x06, 0x18, 0x00, 0x00, 0x00, 0x08, 0x06, 0x1a, 0x12, 0x0f, 0x18, 0x0a, 0x01, 0x0a, 0x01, 0x01, 0x1a, 0x1a, 0x0e, 0x0c, 0x1c, 0x0e, 0x15, 0x03, 0x1d, 0x1e, 0x19, 0x0d, 0x14, 0x16, 0x08, 0x0f, 0x00, 0x03, 0x1b, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
   checksum output: 32970494892
   checksum string: "0ypk3mxc"
6. concatenated result: "cfx:type.user:0086ujfsa1a11uuecwen3xytdmp8f03v140ypk3mxc"

原理

网络前缀:我们选择一个容易辨认的网络前缀(cfx),这样用户可以简单地分辨出 Conflux 地址以及其他链的地址。我们也对 Conflux 链上的不同地址做了区分(如主网 vs 测试网)。这样,用户就不会在主网上意外提交测试网或私有链交易了。

地址类型:Conflux 十六进制地址有一个很好的特点,用户可以直接分辨出一个地址是外部地址(0x1)还是合约地址(0x8)。当这个信息是用 base32 编码地址表示时,就没有那么明显了。为了保留这个特点,我们在 base32 地址中包含了一个可选的可读地址类型。

版本字节:版本字节被保留,这样 Conflux 地址就可以被现有的 bch-base32 实现处理。目前还没有用到版本字节,在未来的拓展中会保留。版本字节在解码过程中进行验证,就可以避免用户使用同一个 Conflux 地址生成多个(可用的)base32 地址别名。

用点(.)作为键值分隔符:可选参数中,我们采用key.value的格式而不是更直白的key=value格式,因为这种方式使用了字母模式,在二维码中能更加高效地编码。

向后兼容性

十六进制地址和 base32 地址编码的底层字节序列是相同的,因此它们从共识和交易签名层面上看是相等的(如合约地址衍生)。

这次变更需要更新 Conflux 生态系统中的多个工具(钱包、IDE、SDK等)和 DApp 来解释 base32 地址。

测试案例

encode(0x85d80245dc02f5a89589e1f19c5c718e405b56cd, mainnet) = cfx:022xg0j5vg1fba4nh7gz372we6740puptms36cm58c
encode(0x85d80245dc02f5a89589e1f19c5c718e405b56cd, testnet) = cfxtest:022xg0j5vg1fba4nh7gz372we6740puptmj8nwjfc6
encode(0x85d80245dc02f5a89589e1f19c5c718e405b56cd, testnet) = cfxtest:type.contract:022xg0j5vg1fba4nh7gz372we6740puptmj8nwjfc6

encode(0x1a2f80341409639ea6a35bbcab8299066109aa55, mainnet) = cfx:00d2z01m2g4p77n6mddvtaw2k43622daamm1867uk6
encode(0x1a2f80341409639ea6a35bbcab8299066109aa55, testnet) = cfxtest:00d2z01m2g4p77n6mddvtaw2k43622daamyavp1grc
encode(0x1a2f80341409639ea6a35bbcab8299066109aa55, testnet) = cfxtest:type.user:00d2z01m2g4p77n6mddvtaw2k43622daamyavp1grc

encode(0x19c742cec42b9e4eff3b84cdedcde2f58a36f44f, mainnet) = cfx:00cwegpesgntwkrz7e2cvvedwbusmdrm9wdsdks47x
encode(0x19c742cec42b9e4eff3b84cdedcde2f58a36f44f, testnet) = cfxtest:00cwegpesgntwkrz7e2cvvedwbusmdrm9w7ky3ye3r
encode(0x19c742cec42b9e4eff3b84cdedcde2f58a36f44f, testnet) = cfxtest:type.user:00cwegpesgntwkrz7e2cvvedwbusmdrm9w7ky3ye3r

encode(0x84980a94d94f54ac335109393c08c866a21b1b0e, mainnet) = cfx:0229g2mmv57n9b1ka44kjf08t1ka46sv1s1vpcf0wh
encode(0x84980a94d94f54ac335109393c08c866a21b1b0e, testnet) = cfxtest:0229g2mmv57n9b1ka44kjf08t1ka46sv1sbg5w9asv
encode(0x84980a94d94f54ac335109393c08c866a21b1b0e, testnet) = cfxtest:type.contract:0229g2mmv57n9b1ka44kjf08t1ka46sv1sbg5w9asv

encode(0x1cdf3969a428a750b89b33cf93c96560e2bd17d1, mainnet) = cfx:00edyeb9mgmaem5skctwz4y9cnge5f8ru42rbphk8r
encode(0x1cdf3969a428a750b89b33cf93c96560e2bd17d1, testnet) = cfxtest:00edyeb9mgmaem5skctwz4y9cnge5f8ru48ws6rtcx
encode(0x1cdf3969a428a750b89b33cf93c96560e2bd17d1, testnet) = cfxtest:type.user:00edyeb9mgmaem5skctwz4y9cnge5f8ru48ws6rtcx

encode(0x0888000000000000000000000000000000000002, mainnet) = cfx:0048g00000000000000000000000000008djg2z8b1
encode(0x0888000000000000000000000000000000000002, testnet) = cfxtest:0048g000000000000000000000000000087t3jt2fb
encode(0x0888000000000000000000000000000000000002, testnet) = cfxtest:type.builtin:0048g000000000000000000000000000087t3jt2fb

更多测试案例请移步 conflux-chain#2034 查看。

实现

本地址结构已经在 conflux-chain#2034 中得到实现。

安全考虑

此提案不涉及明显的安全问题。

参考内容

比特币现金(Bitcoin Cash)规范 [链接]

EIPs #77:更安全的以太坊地址格式 [链接]

版权

版权及其他权力豁免参见 CC0