ERC-5630: 加密/解密的新方法
定义了使用以太坊钱包进行加密和解密的规范。
Authors | Firn Protocol (@firnprotocol), Fried L. Trout, Weiji Guo (@weijiguo) |
---|---|
Created | 2022-09-07 |
Discussion Link | https://ethereum-magicians.org/t/eip-5630-encryption-and-decryption/10761 |
摘要
本 EIP 提出了一种使用以太坊密钥进行加密和解密的新方法。本 EIP 仅 使用 secp256k1
曲线,并提出了两个新的 RPC 方法:eth_getEncryptionPublicKey
和 eth_performECDH
。这两种方法结合使用,允许用户接收加密并执行解密(分别)。我们要求钱包_仅_执行核心 ECDH 操作,将 ECIES 操作留给实现者(但我们建议采用 ECIES 的标准化版本)。相比之下,先前的 EIP 在两个_不同_的曲线(即 secp256k1
和 ec25519
)上,在签名和加密中使用了相同的密钥,并硬编码了特定版本的 ECIES。
动机
我们讨论几个具有启发性的例子。一个关键的动机是在以太坊上进行直接到地址的加密。使用我们的 EIP,可以直接向链上某个期望的接收者发送加密消息,而无需事先与该接收者建立直接通道。(请注意,在本 EIP 中,我们_仅_标准化加密程序——即密文的生成——而_不是_链上消息应该如何准确发送。在实践中,理想情况下,将为此目的建立智能合约基础设施;如果没有,加密者可以使用每个标准转账中可用的原始 data
字段。)
我们讨论第二种例子。在某种常见的模式设计中,dApp 代表用户生成一个新的密钥。如果 dApp 可以将此密钥加密到用户控制的公钥(并且至关重要的是,该公钥的私钥位于用户的 HD 钱包层级结构中),然后将生成的密文发布到安全存储(例如,链上),而不是强制用户独立存储、保护和备份后者的密钥,这将非常有意义。这种设计模式允许 dApp/用户将_新的_密钥的安全性引导到用户现有 HD 钱包助记词的安全性上,用户已经费心保护和存储了该助记词。与强制用户直接存储和管理新密钥相比,这代表了更低的 UX 负担(这可能而且经常会导致资金损失)。我们注意到,上述设计模式目前被各种 dApp(例如,Tornado Cash)使用。
规范
我们在此描述我们的方法;我们在下面的原理部分将我们的方法与之前的 EIP 进行比较。在全文中,我们参考了 Daniel R. L. Brown 的 SEC 1:椭圆曲线密码学。
我们使用 secp256k1
曲线进行签名和加密。
对于加密,我们使用 ECIES。我们指定钱包_仅_执行敏感的 ECDH 操作。这使实现者可以随意选择自己的 ECIES 变体。
我们建议将所有二进制数据序列化为 0x
前缀的十六进制字符串,或从 0x
前缀的十六进制字符串进行序列化。此外,我们使用 0x
前缀的十六进制字符串来指定私钥和公钥,并以压缩形式表示公钥。我们以通常的方式表示以太坊帐户(0x
前缀的 20 字节十六进制字符串)。具体来说,为了序列化和反序列化椭圆曲线点,实现者必须使用以下标准:
- 要序列化一个点:使用 [SEC 1, §2.3.3],使用点压缩。
-
要反序列化一个点:使用 [SEC 1, §2.3.3],同时_要求_点压缩;也就是说:
- 输入字节字符串的长度必须为 ⌈log₂q / 8⌉ + 1 =
33
。 - 第一个字节必须是
0x02
或0x03
。 - 剩余 32 个字节表示的整数(如 [SEC 1, §2.3.8] 中所述)必须位于 {0, …, p - 1} 中,并且在 Weierstrass 表达式 X^3 + 7(模 p)下必须产生二次剩余。
- 输入字节字符串的长度必须为 ⌈log₂q / 8⌉ + 1 =
对于实际上实现 ECIES 的应用级实现者,我们建议以下变体。除非他们有理由不这样做,否则实现者应该使用以下标准化选择:
- KDF
ANSI-X9.63-KDF
,其中哈希函数使用SHA-512
, - HMAC
HMAC–SHA-256–256 with 32 octet or 256 bit keys
, - 对称加密方案
AES–256 in CBC mode
。
我们建议对 ECIES 密文使用二进制_连接的_序列化模式,用于加密和解密,其中椭圆曲线点也是_压缩的_。
因此,在请求中:
request({
method: 'eth_getEncryptionPublicKey',
params: [account]
})
其中 account
是一个标准的 20 字节、0x
前缀的十六进制编码的以太坊账户,客户端应按如下方式操作:
- 找到与以太坊账户
account
对应的密钥签名密钥sk
,否则,如果不存在,则返回错误。 - 计算与
sk
对应的secp256k1
公钥。 - 按照 [SEC 1, §2.3.3],以压缩的、
0x
前缀的十六进制编码形式返回该公钥。
在请求中
request({
method: 'eth_performECDH',
params: [account, ephemeralKey]
})
其中 account
如上所述,ephemeralKey
是一个如上编码的椭圆曲线点:
- 找到与 Ethereum 账户
account
对应的私钥sk
,否则,如果不存在,则返回错误。 - 使用 [SEC 1, §2.3.3] 将
ephemeralKey
反序列化为椭圆曲线点(在此处需要压缩),如果反序列化失败,则抛出错误。 - 按照 [SEC 1, §3.3.1] 计算椭圆曲线迪菲-赫尔曼密钥。
- 使用 [SEC 1, §2.3.5] 返回生成的字段元素作为 0x 前缀的、十六进制编码的 32 字节字符串。
测试向量在下面给出。
加密到智能合约
鉴于账户抽象 EIP-4337 以及智能合约钱包的出现,我们还指定了一种加密到合约的方法。 更准确地说,我们指定了一种合约_声明_它希望如何构建对其的加密的方法。这应该被视为 EIP-1271 的类似物,但用于加密,而不是签名。
我们的规范如下。
pragma solidity ^0.8.0;
contract ERC5630 {
/**
* @dev 应该使用提供的随机性返回所提供明文的加密。
* @param plaintext 要加密的明文
* @param randomness 加密期间要使用的熵
*/
function encryptTo(bytes memory plaintext, bytes32 randomness)
public
view
returns (bytes memory ciphertext);
}
每个合约都可以根据需要实现 encryptTo
。除非有充分的理由不这样做,否则它应该使用我们上面提出的 ECIES 变体。
原理
对于同时调用 secp256k1
曲线上的签名和 ec25519
曲线上的加密,并且在_两种情况下都使用相同的密钥_的方案,没有安全证明。尽管没有已知的攻击,但不希望使用以这种方式缺乏证明的方案。
相反,我们建议在签名和加密中重用相同的密钥,但在_两者中使用相同的曲线_。这种设置已经在先前的工作中得到研究;参见,例如,Degabriele、Lehmann、Paterson、Smart 和 Strefler,《关于 EMV 中加密和签名的联合安全性》,2011 年。该工作发现这种联合方案在通用组模型中是安全的。
我们注意到,这种联合方案(即在同一曲线上使用 ECDSA 和 ECIES)正被 EMV 支付实时用于生产中。
我们现在讨论我们的方法的一些其他方面。
链上公钥发现。 我们的提案有一个重要的特性,即 当_某个账户至少签署了一笔交易_时,就可以构建_到_该账户的加密。
事实上,可以直接从代表该账户的任何签名中恢复账户的 secp256k1
公钥。
ECDH 与 ECIES。 我们指定钱包_仅_执行敏感的 ECDH 操作,并让应用级实现者执行 ECIES 的其余步骤。这有两个明显的优点:
- 灵活性。 它允许实现者选择 ECIES 的任意变体,而无需更新钱包的功能。
- 带宽。 我们的方法要求客户端和钱包之间仅交换小消息(大约 32 字节)。在所涉及的明文和密文很大,并且客户端和钱包通过互联网连接分隔的情况下,这可能很重要。
扭曲攻击。 Christian Lundkvist 的一篇 GitHub 帖子警告了 secp256k1
曲线上的 “扭曲攻击”。这些攻击不适用于此 EIP,原因有很多_不同的_原因,我们将其列出:
- 仅适用于经典 ECDH,不适用于 ECIES。 这种攻击仅适用于经典 ECDH(即,双方都使用持久的、经过身份验证的公钥),而不适用于 ECIES(其中一方,即加密者,使用临时密钥)。事实上,它仅适用于攻击者可以诱使受害者将攻击者提供的点按一个敏感标量进行指数运算,然后将结果发回给攻击者的情况。但是这种模式仅发生在经典的迪菲-赫尔曼中,而从不发生在 ECIES 中。事实上,在 ECIES 中,我们回想一下,唯一的敏感迪菲-赫尔曼操作发生在解密期间,但在这种情况下,受害者(即解密者)从不将生成的 DH 点发回给攻击者(而是,受害者仅在本地使用它来尝试 AES 解密)。在_加密_期间,指数运算由加密者完成,加密者根本没有密钥(当然,指数运算是由一个临时的标量完成的),因此攻击者不会从这里学到任何东西。
- 仅适用于未压缩的点。 事实上,我们在本 EIP 中使用压缩的点。当使用压缩点时,每个 33 字节的字符串_必定_要么解析为正确曲线上的点,要么没有合理的解释。没有 “不在曲线上的点” 这样的东西(特别是,它可以不被察觉地通过)。
- 仅当您未能检查一个点是否在曲线上时才适用。 但无论如何这都不适用于我们,因为我们使用压缩点(见上文)。我们还要求执行所有验证。
向后兼容性
我们的 eth_performECDH
方法是新的,因此不会引发任何向后兼容性问题。
先前的提案提出了一个 eth_getEncryptionPublicKey
方法(以及一个与此 EIP 无关 的eth_decrypt
方法)。我们的提案覆盖了 eth_getEncryptionPublicKey
先前的行为。
这不太可能成为一个问题,因为加密密钥只需要在加密时新检索;另一方面,_新的_密文将使用我们的新方法生成。
(特别地,我们的修改不会影响使用旧 EIP 生成的密文被 eth_decrypt
的能力。)
无论如何,之前的 EIP 从未标准化,并且_据我们所知_,在当今的_任何_生产代码中都没有以非弃用的方式实现。
测试用例
密钥 签名密钥
0x439047a312c8502d7dd276540e89fe6639d39da1d8466f79be390579d7eaa3b2
以太坊地址为 0x72682F2A3c160947696ac3c9CC48d290aa89549c
,具有 secp256k1
公钥
0x03ff5763a2d3113229f2eda8305fae5cc1729e89037532a42df357437532770010
因此,请求:
request({
method: 'eth_getEncryptionPublicKey',
params: ["0x72682F2A3c160947696ac3c9CC48d290aa89549c"]
})
应该返回:
"0x03ff5763a2d3113229f2eda8305fae5cc1729e89037532a42df357437532770010"
如果加密者使用上述 ECIES 变体,在上述公钥下加密一条消息——例如,I use Firn Protocol to gain privacy on Ethereum.
——他可以获得,例如:
"0x036f06f9355b0e3f7d2971da61834513d5870413d28a16d7d68ce05dc78744daf850e6c2af8fb38e3e31d679deac82bd12148332fa0e34aecb31981bd4fe8f7ac1b74866ce65cbe848ee7a9d39093e0de0bd8523a615af8d6a83bbd8541bf174f47b1ea2bd57396b4a950a0a2eb77af09e36bd5832b8841848a8b302bd816c41ce"
在获得此密文后,解密者将提取相关的临时公钥,即:
"0x036f06f9355b0e3f7d2971da61834513d5870413d28a16d7d68ce05dc78744daf8"
并提交请求:
request({
method: 'eth_performECDH',
params: [
"0x72682F2A3c160947696ac3c9CC48d290aa89549c",
"0x036f06f9355b0e3f7d2971da61834513d5870413d28a16d7d68ce05dc78744daf8"
]
})
这将返回迪菲-赫尔曼密钥:
"0x4ad782e7409702101abe6d0279f242a2c545c46dd50a6704a4b9e3ae2730522e"
在继续使用上述 ECIES 变体后,解密者将获得字符串 I use Firn Protocol to gain privacy on Ethereum.
。
安全考虑
我们的提案使用高度标准化的算法,并遵循所有最佳实践。
版权
通过 CC0 放弃版权及相关权利。
Citation
Please cite this document as:
Firn Protocol (@firnprotocol), Fried L. Trout, Weiji Guo (@weijiguo), "ERC-5630: 加密/解密的新方法 [DRAFT]," Ethereum Improvement Proposals, no. 5630, September 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-5630.