ERC-5564: 隐身地址
私有的、非交互式的交易
Authors | Toni Wahrstätter (@nerolation), Matt Solomon (@mds1), Ben DiFrancesco (@apbendi), Vitalik Buterin (@vbuterin) |
---|---|
Created | 2022-08-13 |
Table of Contents
摘要
本规范建立了一种与隐身地址交互的标准方法,该地址允许交易或转账的发送者非交互式地生成仅由其接收者才能访问的私有帐户。此外,本规范使开发人员能够基于本 ERC 中概述的基础实现创建隐身地址协议,利用部署在 0x55649E01B5Df198D18D95b5cc5051630cfD45564
的单例合约来发出接收者所需的必要信息。除了基本实现之外,本 ERC 还概述了密码方案的第一个实现,特别是 SECP256k1 曲线。
动机
非交互式隐身地址生成的标准化,通过允许接收者在接收资产时保持私有性,有可能显着提高以太坊网络和其他 EVM 兼容链的隐私能力。这是通过发送者基于仅发送者和接收者知道的共享密钥生成隐身地址来实现的。只有接收者才能访问存储在其隐身地址中的资金,因为他们是必要私钥的唯一拥有者。因此,观察者无法将接收者的隐身地址与其身份相关联,从而保护了接收者的隐私,并将发送者作为唯一知悉此信息的当事方。通过提供与多种密码方案兼容的单个合约形式的基础实现,接收者可以获得一个集中的监控位置,确保他们不会忽略任何传入的交易。
规范
本文档中的关键字“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY”和“OPTIONAL”应按照 RFC 2119 中的描述进行解释。
定义:
- “隐身元地址”是一组一个或两个公钥,可用于计算给定接收者的隐身地址。
- “消费密钥”是可以用来消费发送到隐身地址的资金的私钥。“消费公钥”是对应的公钥。
- “查看密钥”是可以用来确定发送到隐身地址的资金是否属于控制相应消费密钥的接收者的私钥。“查看公钥”是对应的公钥。
不同的隐身地址方案将具有不同的预期隐身元地址长度。使用长度为 n
字节的公钥的方案必须将隐身元地址定义如下:
- 长度为
n
的隐身元地址对消费公钥和查看公钥使用相同的隐身元地址。 - 长度为
2n
的隐身元地址使用前n
个字节作为消费公钥,最后n
个字节作为查看公钥。
给定接收者的隐身元地址,发送者必须能够通过调用具有以下签名的方法来生成接收者的隐身地址:
/// @notice 从隐身元地址生成隐身地址。
/// @param stealthMetaAddress 接收者的隐身元地址。
/// @return stealthAddress 接收者的隐身地址。
/// @return ephemeralPubKey 用于生成隐身地址的临时公钥。
/// @return viewTag 从共享密钥派生的查看标签。
function generateStealthAddress(bytes memory stealthMetaAddress)
external
view
returns (address stealthAddress, bytes memory ephemeralPubKey, bytes1 viewTag);
接收者必须能够通过调用具有以下签名的方法来检查隐身地址是否属于他们:
/// @notice 如果发送到隐身地址的资金属于控制
/// 相应消费密钥的接收者,则返回 true。
/// @param stealthAddress 接收者的隐身地址。
/// @param ephemeralPubKey 用于生成隐身地址的临时公钥。
/// @param viewingKey 接收者的查看私钥。
/// @param spendingPubKey 接收者的消费公钥。
/// @return 如果发送到隐身地址的资金属于接收者,则为 True。
function checkStealthAddress(
address stealthAddress,
bytes memory ephemeralPubKey,
bytes memory viewingKey,
bytes memory spendingPubKey
) external view returns (bool);
接收者必须能够通过调用具有以下签名的方法来计算隐身地址的私钥:
/// @notice 计算隐身地址的隐身私钥。
/// @param stealthAddress 预期的隐身地址。
/// @param ephemeralPubKey 用于生成隐身地址的临时公钥。
/// @param viewingKey 接收者的查看私钥。
/// @param spendingKey 接收者的消费私钥。
/// @return stealthKey 与隐身地址对应的隐身私钥。
/// @dev 隐身地址输入不是严格必要的,但包含它是为了该方法
/// 可以验证隐身私钥是否已正确生成。
function computeStealthKey(
address stealthAddress,
bytes memory ephemeralPubKey,
bytes memory viewingKey,
bytes memory spendingKey
) external view returns (bytes memory);
这些方法的实现是特定于方案的。新的隐身地址方案的规范必须指定这些方法中的每一种的实现。此外,尽管这些函数接口是在 Solidity 中指定的,但它们不一定需要在 Solidity 中实现,但任何符合本规范的库或 SDK 必须使用兼容的函数接口来实现这些方法。
一个 256 位整数 (schemeId
) 用于标识隐身地址方案。从 schemeId 到其规范的映射必须在提议标准化新隐身地址方案的 ERC 中声明。 建议 schemeId
选择为单调递增的整数以简化操作,但可以选择任意的或有意义的 schemeId
。 本 ERC 引入了 schemeId 1
,其具有以下扩展:
-
1
是该方案的整数标识符, -
viewTags
必须包含在公告事件中,用于减少接收者的解析时间。 - SECP256k1 是用于将隐身元地址(即消费公钥和查看公钥)编码为
bytes
数组以及将其从bytes
解码为该方案的本机密钥类型的算法。 - SECP256k1 与查看标签将在
generateStealthAddress
、checkStealthAddress
和computeStealthKey
方法中使用。
本规范还定义了一个单例 ERC5564Announcer
合约,该合约在将某些内容发送到隐身地址时发出事件以进行公告。 这必须是一个单例合约,每个链一个实例。 该合约的规定如下:
/// @notice 用于在将某些内容发送到隐身地址时进行公告的接口。
contract IERC5564Announcer {
/// @dev 在将某些内容发送到隐身地址时发出。
/// @dev 有关参数的文档,请参阅 `announce` 方法。
event Announcement (
uint256 indexed schemeId,
address indexed stealthAddress,
address indexed caller,
bytes ephemeralPubKey,
bytes metadata
);
/// @dev 由集成者调用以发出 `Announcement` 事件。
/// @param schemeId 指定应用的隐身地址方案的整数。
/// @param stealthAddress 接收者计算出的隐身地址。
/// @param ephemeralPubKey 发送者使用的临时公钥。
/// @param metadata 任意字段,必须在第一个字节中包含查看标签。
/// 除了查看标签之外,发送者可以随意使用元数据,
/// 但建议采用以下准则:
/// 元数据的第一个字节必须是查看标签。
/// - 在发送/与区块链的本机令牌(参见 ETH)交互时,元数据的结构应如下所示:
/// - 字节 1 必须是查看标签,如上所述。
/// - 字节 2-5 是 `0xeeeeeeee`
/// - 字节 6-25 是地址 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE。
/// - 字节 26-57 是发送的 ETH 数量。
/// - 在与 ERC-20/ERC-721/etc. 令牌交互时,元数据的结构应如下所示:
/// - 字节 1 必须是查看标签,如上所述。
/// - 字节 2-5 是函数标识符。当函数选择器(例如
/// 函数签名的 Keccak-256 哈希的前(最左侧,大端中的高位)四个字节,如 Solidity 和 Vyper 所使用的)可用时,
/// 必须使用它。
/// - 字节 6-25 是令牌合约地址。
/// - 字节 26-57 是发送的/交互的令牌数量(对于同质化令牌),或者
/// 非同质化令牌的令牌 ID。
function announce (
uint256 schemeId,
address stealthAddress,
bytes memory ephemeralPubKey,
bytes memory metadata
)
external
{
emit Announcement(schemeId, stealthAddress, msg.sender, ephemeralPubKey, metadata);
}
}
隐身元地址格式
隐身元地址的新地址格式通过添加 st:
(隐身)前缀来扩展链特定的地址格式。
因此,以太坊上的隐身元地址具有以下格式:
st:eth:0x<spendingPubKey><viewingPubKey>
隐身元地址可以由用户管理和/或在公开可用的 Registry
合约中注册,如 ERC-6538 中所述。这为用户提供了一个中心位置来识别与其他人关联的隐身元地址,同时使接收者能够表达他们通过隐身地址进行互动的意愿。
值得注意的是,地址格式仅用于区分隐身地址和标准地址,因为在前对隐身元地址执行任何计算之前,会删除该前缀。
SECP256k1 与查看标签的初始实现
本 ERC 通过 IERC5564Announcer
合约提供了一个不与任何特定密码系统绑定的基础。此外,它还引入了利用 SECP256k1 椭圆曲线和查看标签的隐身地址方案的第一个实现。SECP256k1 椭圆曲线定义为方程 $y^2 = x^3 + 7 \pmod{p}$,其中 $p = 2^{256} - 2^{32} - 977$。
以下参考分为三个部分:
-
隐身地址生成
-
解析公告
-
stealth 私钥推导
定义:
- $G$ 表示曲线的生成器点。
生成 - 从隐身元地址生成隐身地址:
-
接收者可以访问私钥 $p_{spend}$、$p_{view}$,从中派生出公钥 $P_{spend}$ 和 $P_{view}$。
-
接收者已发布一个隐身元地址,该地址由公钥 $P_{spend}$ 和 $P_{view}$ 组成。
-
发送者将隐身元地址传递给
generateStealthAddress
函数。 -
generateStealthAddress
函数执行以下计算:- 生成一个随机的 32 字节熵临时私钥 $p_{ephemeral}$。
- 从 $p_{ephemeral}$ 派生临时公钥 $P_{ephemeral}$。
- 从隐身元地址解析消费和查看公钥 $P_{spend}$ 和 $P_{view}$。
- 共享密钥 $s$ 计算为 $s = p_{ephemeral} \cdot P_{view}$。
- 密钥被哈希 $s_{h} = \textrm{h}(s)$。
- 通过获取最高有效字节 $s_{h}[0]$ 来提取查看标签 $v$,
- 将哈希的共享密钥与生成器点相乘 $S_h = s_h \cdot G$。
- 接收者的隐身公钥计算为 $P_{stealth} = P_{spend} + S_h$。
- 接收者的隐身地址 $a_{stealth}$ 计算为 $\textrm{pubkeyToAddress}(P_{stealth})$。
- 该函数返回隐身地址 $a_{stealth}$、临时公钥 $P_{ephemeral}$ 和查看标签 $v$。
解析 - 找到自己的隐身地址:
-
用户可以访问查看私钥 $p_{view}$ 和消费公钥 $P_{spend}$。
-
用户可以访问一组
Announcement
事件,并将checkStealthAddress
函数应用于每个事件。 -
checkStealthAddress
函数执行以下计算:- 通过将查看私钥与公告的临时公钥相乘来计算共享密钥 $s$,即 $s = p_{view}$ * $P_{ephemeral}$。
- 密钥被哈希 $s_{h} = h(s)$。
- 通过获取最高有效字节 $s_{h}[0]$ 来提取查看标签 $v$,并可以将其与给定的查看标签进行比较。如果查看标签不匹配,则此
Announcement
不适用于用户,可以跳过剩余步骤。如果查看标签匹配,则继续。 - 将哈希的共享密钥与生成器点相乘 $S_h = s_h \cdot G$。
- 隐身公钥计算为 $P_{stealth} = P_{spend} + S_h$。
- 派生的隐身地址 $a_{stealth}$ 计算为 $\textrm{pubkeyToAddress}(P_{stealth})$。
- 如果公告的隐身地址与派生的隐身地址匹配,则返回
true
,否则返回false
。
私钥推导 - 从哈希的共享密钥和消费私钥生成隐身地址私钥。
-
用户可以访问查看私钥 $p_{view}$ 和消费私钥 $p_{spend}$。
-
用户可以访问
checkStealthAddress
函数返回true
的一组Announcement
事件。 -
computeStealthKey
函数执行以下计算:- 通过将查看私钥与公告的临时公钥相乘来计算共享密钥 $s$,即 $s = p_{view}$ * $P_{ephemeral}$。
- 密钥被哈希 $s_{h} = h(s)$。
- 隐身私钥计算为 $p_{stealth} = p_{spend} + s_h$。
解析注意事项
通常,隐身地址交易的接收者必须执行以下操作来检查他是否是特定交易的接收者:
-
2x ecMUL,
-
2x HASH,
-
1x ecADD,
引入查看标签方法是为了将解析时间减少大约 6 倍。用户只需对每个已解析的公告执行 1x ecMUL 和 1x HASH(跳过 1x ecMUL、1x ecADD 和 1x HASH)。1 字节查看标签长度基于可靠地过滤不匹配公告所需的最大空间。使用 1 字节 viewTag
,用户在哈希共享密钥 $h(s)$ 后跳过剩余计算的概率为 $255/256$。这意味着用户几乎可以肯定地跳过任何不涉及他们的公告的上述三个操作。由于查看标签泄露了共享密钥的一个字节,因此安全裕度从 128 位降低到 124 位。值得注意的是,这仅影响隐私,而不影响隐身地址的安全生成。
理由
本 ERC 源于对隐私保护方式的需求,以转移所有权而不披露有关接收者身份的任何信息。令牌所有权可能会暴露敏感的个人信息。虽然个人可能希望向特定组织或国家/地区捐款,但他们可能希望不同时披露自己与接收者之间的联系。标准化隐身地址生成代表了迈向不可链接交互的重要一步,因为这种增强隐私的解决方案需要标准才能实现广泛采用。因此,至关重要的是专注于开发用于实施相关解决方案的通用方法。
隐身地址规范标准化了一个用于生成和定位隐身地址的协议,从而有助于在无需与接收者进行事先交互的情况下转移资产。这使接收者无需与区块链交互和查询账户余额即可验证是否收到转账。重要的是,隐身地址使令牌转账接收者可以在保持隐私的同时验证收据,因为只有接收者才能将自己识别为转账的接收者。
作者认识到链上和链下效率之间的权衡。虽然结合类似 Monero 的查看标签机制使接收者可以更有效地解析公告,但它增加了公告事件的复杂性。
接收者的地址和 viewTag
必须包含在公告事件中,允许用户快速验证所有权,而无需查询链以获取正账户余额。
向后兼容性
本 ERC 完全向后兼容。
部署方法
ERC5564Announcer
合约部署在 0x55649E01B5Df198D18D95b5cc5051630cfD45564
,使用 CREATE2
通过确定性部署器 0x4e59b44847b379578588920ca78fbf26c0b4956c
,盐值为 0xd0103a290d760f027c9ca72675f5121d725397fb2f618f05b6c44958b25b4447
。
参考实现
您可以在此处找到 ERC5564Announcer
合约的实现,并在此处找到接口 IERC5564Announcer.sol
。
安全考虑
DoS 对策
存在潜在的拒绝服务 (DoS) 攻击向量,这些向量无法通过网络交易费用来缓解。隐身传输发送者会导致接收者的外部性,因为解析公告事件会消耗计算资源,而这些资源无法通过 gas 来补偿。因此,垃圾邮件公告事件可能会对用户体验造成损害,因为它可能导致更长的解析时间。
我们认为进行此类攻击的动机很低,因为无法获得任何经济利益
但是,为了解决潜在的垃圾邮件问题,解析提供商可能会采取自己的反 DoS 攻击方法。这些方法可能包括在向用户提供公告时忽略垃圾邮件用户,或者在排序公告时降低他们的优先级。索引的 caller
关键字可以帮助解析提供商有效地过滤已知的垃圾邮件发送者。
此外,解析提供商有几种选择来对抗垃圾邮件,例如引入质押机制或要求发送者在包含其 Announcement
之前支付“通行费”。此外,质押机制可能允许用户质押不可削减的 ETH 数量(类似于 ERC-4337),以帮助缓解通过 女巫攻击 潜在的垃圾邮件,并使解析提供商能够更有效地过滤垃圾邮件。
引入由发送用户支付的“通行费”将简单地对每笔隐身地址交易收取费用,从而使垃圾邮件在经济上没有吸引力。
接收者的交易成本
隐身地址钱包的资金代表一个已知问题,可能会破坏隐私。为充分利用隐私改进,为隐身地址提供资金的钱包不得与隐身地址所有者有任何物理连接。
因此,发送者可以将少量 ETH 附加到每笔隐身地址交易中,从而赞助接收者的后续交易。
版权
版权及相关权利通过 CC0 放弃。
Citation
Please cite this document as:
Toni Wahrstätter (@nerolation), Matt Solomon (@mds1), Ben DiFrancesco (@apbendi), Vitalik Buterin (@vbuterin), "ERC-5564: 隐身地址," Ethereum Improvement Proposals, no. 5564, August 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-5564.