本文档介绍了OpenZeppelin社区合约库中的实用工具合约和库,包括用于签名验证、处理新数据类型和安全使用底层原语的工具。
| 在 https://docs.openzeppelin.com/community-contracts/utils 上查看此文档效果更佳 |
包含实用函数的各种合约和库,你可以使用它们来提高安全性、处理新的数据类型或安全地使用底层原语。
AbstractSigner: 用于智能合约中内部签名验证的抽象合约。
ERC7739: 一个抽象合约,用于验证来自 ERC7739Utils 的重散列方案的签名。
ERC7739Utils: 实用工具库,实现了防御性的重散列机制,以防止基于 ERC-7739 的智能合约签名的重放。
ERC7913Utils: 实用工具库,实现了 ERC-7913 签名验证,并回退到 ERC-1271 和 ECDSA。
SignerECDSA, SignerP256, SignerRSA: 具有特定签名验证算法的 AbstractSigner 的实现。
SignerERC7702: AbstractSigner 的实现,该实现使用合约自身的地址作为签名者来验证签名,这对于遵循 EIP-7702 的委托帐户非常有用。
SignerERC7913, MultiSignerERC7913, MultiSignerERC7913Weighted: AbstractSigner 的实现,该实现基于 ERC-7913 验证签名。 包括一个简单和加权的多重签名方案。
ERC7913P256Verifier, ERC7913RSAVerifier: 可用于 P256 和 RSA 密钥的现成的 ERC-7913 签名验证器
SignerZKEmail: AbstractSigner 的实现,它通过零知识证明启用基于电子邮件的身份验证。
ZKEmailUtils: ZKEmail 签名验证实用工具库,通过零知识证明启用基于电子邮件的身份验证。
EnumerableSetExtended 和 EnumerableMapExtended: EnumerableSet 和 EnumerableMap 库的扩展,具有更多类型,包括非值类型。
Masks: 用于处理 bytes32 掩码的库。
ERC7739import "@openzeppelin/community-contracts/utils/cryptography/ERC7739.sol";
验证签名,将消息哈希包装在嵌套的 EIP712 类型中。 请参阅 ERC7739Utils。
将签名链接到 EIP-712 域名分隔符是一种安全措施,可防止跨不同 EIP-712 域的签名重放(例如,多个合约的单个链下所有者)。
此合约需要实现 {_rawSignatureValidation} 函数,该函数传递包装的消息哈希, 它可能是类型化的数据或个人签名嵌套类型。
| EIP-712 使用<br>ShortStrings 来优化 gas 成本,适用于<br>短字符串(最多 31 个字符)。 请注意,长度超过此值的字符串将使用存储,这<br>可能会限制签名者在 ERC-4337 验证阶段内的使用能力(由于<br>ERC-7562 存储访问规则)。 |
函数
isValidSignature(hash, signature)EIP712
_domainSeparatorV4()
_hashTypedDataV4(structHash)
eip712Domain()
_EIP712Name()
_EIP712Version()
AbstractSigner
_rawSignatureValidation(hash, signature)事件
IERC5267
EIP712DomainChanged()isValidSignature(bytes32 hash, bytes signature) → bytes4 result public尝试在嵌套的 EIP-712 类型中验证签名。
嵌套的 EIP-712 类型可能以 2 种不同的方式呈现:
作为嵌套的 EIP-712 类型化数据
作为个人签名(智能合约的 eth_personalSign 的 EIP-712 模拟)
ERC7739Utilsimport "@openzeppelin/community-contracts/utils/cryptography/ERC7739Utils.sol";
用于处理 ERC-7739 类型化数据签名的实用工具 特定于 EIP-712 域名。
该库提供方法来包装、解包和操作具有防御性的类型化数据签名 重散列机制,包括应用程序的 EIP-712 并使用 EIP-712 嵌套方法保留已签名内容的可读性。
智能合约域可以通过两种方式验证类型化数据结构的签名:
作为验证类型化数据签名的应用程序。 请参阅 typedDataSignStructHash。
作为验证原始消息签名的智能合约。 请参阅 personalSignStructHash。
智能合约钱包的提供商需要将此签名作为返回<br>调用 personal_sign 或 eth_signTypedData 的结果,这可能不受期望返回值为 129 字节 API 客户端的支持,或者专门针对 ECDSA 签名的 r,s,v 参数,例如为 EIP-712 指定的参数。 |
函数
encodeTypedDataSig(signature, appSeparator, contentsHash, contentsDescr)
decodeTypedDataSig(encodedSignature)
personalSignStructHash(contents)
typedDataSignStructHash(contentsName, contentsType, contentsHash, domainBytes)
typedDataSignStructHash(contentsDescr, contentsHash, domainBytes)
typedDataSignTypehash(contentsName, contentsType)
decodeContentsDescr(contentsDescr)
encodeTypedDataSig(bytes signature, bytes32 appSeparator, bytes32 contentsHash, string contentsDescr) → bytes internal将给定 EIP-712 类型的签名嵌套到应用程序域名的嵌套签名中。
decodeTypedDataSig 的对应方,用于提取原始签名和嵌套组件。
decodeTypedDataSig(bytes encodedSignature) → bytes signature, bytes32 appSeparator, bytes32 contentsHash, string contentsDescr internal将嵌套签名解析为其组件。
构造如下:
signature ‖ APP_DOMAIN_SEPARATOR ‖ contentsHash ‖ contentsDescr ‖ uint16(contentsDescr.length)
signature 是 (ERC-7739) 嵌套结构哈希的签名。 此签名间接签署原始“内容”哈希(来自应用程序)和帐户的域名分隔符。
APP_DOMAIN_SEPARATOR 是请求签名验证(通过 ERC-1271)的应用程序智能合约的 EIP-712 {EIP712-_domainSeparatorV4}。
contentsHash 是底层数据结构或消息的哈希。
contentsDescr 是嵌套签名的 EIP-712 类型的“内容”部分的描述符。
| 如果输入格式无效,则此函数返回空,而不是恢复。<br>数据。 |
personalSignStructHash(bytes32 contents) → bytes32 internal将 ERC-191 摘要嵌套到 PersonalSign EIP-712 结构中,并返回相应的结构哈希。
此结构哈希必须与域名分隔符组合,使用 {MessageHashUtils-toTypedDataHash} 之前
进行验证/恢复。
这用于在智能合约的上下文中模拟 personal_sign RPC 方法。
typedDataSignStructHash(string contentsName, string contentsType, bytes32 contentsHash, bytes domainBytes) → bytes32 result internal将 EIP-712 哈希(contents)嵌套到 TypedDataSign EIP-712 结构中,并返回相应的结构
哈希。 此结构哈希必须与域名分隔符组合,使用 {MessageHashUtils-toTypedDataHash}
在被验证/恢复之前。
typedDataSignStructHash(string contentsDescr, bytes32 contentsHash, bytes domainBytes) → bytes32 result internal{typedDataSignStructHash-string-string-bytes32-bytes} 的变体,它接受内容描述符
并从中解码 contentsName 和 contentsType。
typedDataSignTypehash(string contentsName, string contentsType) → bytes32 internal计算给定类型(和类型名称)的 TypedDataSign 结构的 EIP-712 类型哈希。
decodeContentsDescr(string contentsDescr) → string contentsName, string contentsType internal从 ERC-7739 内容类型描述中解析类型名称。 支持隐式和显式 模式。
按照 ERC-7739 规范,如果 contentsName 为空或包含以下任何字节,则认为它无效
, )\x00
如果 contentsType 无效,则返回空字符串。 否则,返回字符串具有非零
长度。
ZKEmailUtilsimport "@openzeppelin/community-contracts/utils/cryptography/ZKEmailUtils.sol";
用于 ZKEmail 签名验证实用工具的库。
ZKEmail 是一种协议,它通过使用零知识证明启用智能合约的基于电子邮件的身份验证和授权。 它允许用户证明电子邮件地址的所有权,而无需透露电子邮件内容或私钥。
验证过程涉及几个关键组件:
A DKIMRegistry(DomainKeys Identified Mail)验证
机制,以确保电子邮件是从有效的域发送的。 由 IDKIMRegistry 接口定义。
A 命令模板 验证 机制,以确保电子邮件命令与预期格式和参数匹配。
A 零知识证明 验证
机制,以确保电子邮件实际上已发送和接收,而不会泄露其内容。 由 IVerifier 接口定义。
函数
isValidZKEmail(emailAuthMsg, dkimregistry, verifier)
isValidZKEmail(emailAuthMsg, dkimregistry, verifier, template)
isValidZKEmail(emailAuthMsg, dkimregistry, verifier, template, stringCase)
isValidZKEmail(struct EmailAuthMsg emailAuthMsg, contract IDKIMRegistry dkimregistry, contract IVerifier verifier) → enum ZKEmailUtils.EmailProofError internalisValidZKEmail 的变体,它验证 ["signHash", "{uint}"] 命令模板。
isValidZKEmail(struct EmailAuthMsg emailAuthMsg, contract IDKIMRegistry dkimregistry, contract IVerifier verifier, string[] template) → enum ZKEmailUtils.EmailProofError internal验证 ZKEmail 身份验证消息。
此函数采用电子邮件身份验证消息、DKIM 注册表合约和验证器合约
作为输入。 它执行多个验证检查并返回一个元组,其中包含一个布尔成功标志
和一个 EmailProofError(如果验证失败)。 如果所有验证都通过,则返回 {EmailProofError.NoError},
或 false 以及指示哪个验证检查失败的特定 EmailProofError。
尝试验证所有可能的字符串 Case 值的命令。 |
isValidZKEmail(struct EmailAuthMsg emailAuthMsg, contract IDKIMRegistry dkimregistry, contract IVerifier verifier, string[] template, enum ZKEmailUtils.Case stringCase) → enum ZKEmailUtils.EmailProofError internalisValidZKEmail 的变体,它使用特定的字符串 Case 验证模板。
对于具有以太坊地址匹配器(即 {ethAddr})的模板非常有用,这些匹配器区分大小写(例如,["someCommand", "{address}"])。
AbstractSignerimport "@openzeppelin/community-contracts/utils/cryptography/AbstractSigner.sol";
用于签名验证的抽象合约。
开发人员必须实现 _rawSignatureValidation 并将其用作最低级别的签名验证机制。
函数
_rawSignatureValidation(hash, signature)_rawSignatureValidation(bytes32 hash, bytes signature) → bool internal签名验证算法。
| 实现签名验证算法是一项对安全敏感的操作,因为它涉及<br>加密验证。 在部署之前彻底审查和测试非常重要。 考虑<br>使用签名验证库之一(ECDSA,<br>P256 或 RSA)。 |
SignerECDSAimport "@openzeppelin/community-contracts/utils/cryptography/SignerECDSA.sol";
使用 ECDSA 签名实现的 AbstractSigner。
对于 Account 用法,提供了 _setSigner 函数来设置 signer 地址。
这样做对于工厂来说更容易,工厂很可能使用此合约的可初始化克隆。
用法示例:
contract MyAccountECDSA is Account, SignerECDSA, Initializable {
function initialize(address signerAddr) public initializer {
_setSigner(signerAddr);
}
}
在构造期间(如果单独使用)未能调用 _setSigner 或在初始化期间(如果用作克隆)可能会使签名者要么抢先交易,要么无法使用。 |
函数
_setSigner(signerAddr)
signer()
_rawSignatureValidation(hash, signature)
_setSigner(address signerAddr) internal使用本地签名者的地址设置签名者。 此函数应在构造期间 或通过初始化程序调用。
signer() → address public返回签名者的地址。
_rawSignatureValidation(bytes32 hash, bytes signature) → bool internal签名验证算法。
| 实现签名验证算法是一项对安全敏感的操作,因为它涉及<br>加密验证。 在部署之前彻底审查和测试非常重要。 考虑<br>使用签名验证库之一(ECDSA,<br>P256 或 RSA)。 |
SignerERC7913import "@openzeppelin/community-contracts/utils/cryptography/SignerERC7913.sol";
使用 ERC-7913 签名验证实现的 AbstractSigner。
对于 Account 用法,提供了一个 _setSigner 函数来设置 ERC-7913 格式的 signer。
这样做对于工厂来说更容易,工厂很可能使用此合约的可初始化克隆。
签名者是一个 bytes 对象,它连接验证器地址和密钥:verifier || key。
用法示例:
contract MyAccountERC7913 is Account, SignerERC7913, Initializable {
function initialize(bytes memory signer_) public initializer {
_setSigner(signer_);
}
}
在构造期间(如果单独使用)未能调用 _setSigner 或在初始化期间(如果用作克隆)可能会使签名者要么抢先交易,要么无法使用。 |
函数
signer()
_setSigner(signer_)
_rawSignatureValidation(hash, signature)
signer() → bytes public返回 ERC-7913 签名者(即 verifier || key)。
_setSigner(bytes signer_) internal使用 ERC-7913 格式的签名者设置签名者(即 verifier || key)。
_rawSignatureValidation(bytes32 hash, bytes signature) → bool internal使用ERC7913Utils.isValidSignatureNow 验证 hash 的签名,hash的验证器为 signer。
MultiSignerERC7913import "@openzeppelin/community-contracts/utils/cryptography/MultiSignerERC7913.sol";
使用基于阈值的签名验证系统实现的 AbstractSigner ,该系统使用多个 ERC-7913 签名者。
此合约允许管理一组授权签名者,并且需要最少数量的签名(阈值)才能批准操作。 它使用 ERC-7913 格式的签名者,这些签名者连接验证器地址和密钥:verifier || key。
用法示例:
contract MyMultiSignerAccount is Account, MultiSignerERC7913, Initializable {
constructor() EIP712("MyMultiSignerAccount", "1") {}
function initialize(bytes[] memory signers, uint256 threshold) public initializer {
_addSigners(signers);
_setThreshold(threshold);
}
function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf {
_addSigners(signers);
}
function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf {
_removeSigners(signers);
}
function setThreshold(uint256 threshold) public onlyEntryPointOrSelf {
_setThreshold(threshold);
}
}
| 在构造期间(如果单独使用)或在初始化期间(如果用作克隆)未能正确初始化签名者和阈值可能会使合约抢先交易或无法使用。 |
函数
signers()
isSigner(signer)
threshold()
_signers()
_addSigners(newSigners)
_removeSigners(oldSigners)
_setThreshold(newThreshold)
_validateReachableThreshold()
_rawSignatureValidation(hash, signature)
_validateSignatures(hash, signingSigners, signatures)
_validateThreshold(validatingSigners)
事件
ERC7913SignersAdded(signers)
ERC7913SignersRemoved(signers)
ERC7913ThresholdSet(threshold)
错误
MultiSignerERC7913AlreadyExists(signer)
MultiSignerERC7913NonexistentSigner(signer)
MultiSignerERC7913InvalidSigner(signer)
MultiSignerERC7913UnreachableThreshold(signers, threshold)
signers() → bytes[] public返回授权签名者的集合。 对于内部使用,首选 _signers。
| 此操作将整个签名者集合复制到内存,这可能非常昂贵。 这是为在没有 gas 费用的情况下查询的视图访问器设计的。 如果签名者集合变得太大,在状态更改函数中使用它可能会变得不可调用。 |
isSigner(bytes signer) → bool public返回 signer 是否为授权签名者。
threshold() → uint256 public返回批准多重签名操作所需的最少签名者数量。
_signers() → struct EnumerableSetExtended.BytesSet internal返回授权签名者的集合。
_addSigners(bytes[] newSigners) internal将 newSigners 添加到那些被允许代表此合约签名的人员。
没有访问控制的内部版本。
要求:
每个 newSigners 的长度必须至少为 20 个字节。 如果不是,则使用 MultiSignerERC7913InvalidSigner 恢复。
不得授权每个 newSigners。 请参阅 isSigner。 如果是,则使用 MultiSignerERC7913AlreadyExists 恢复。
_removeSigners(bytes[] oldSigners) internal从授权签名者中删除 oldSigners。 没有访问控制的内部版本。
要求:
必须授权每个 oldSigners。 请参阅 isSigner。 否则,将引发 MultiSignerERC7913NonexistentSigner。
有关阈值验证,请参阅 _validateReachableThreshold。
_setThreshold(uint256 newThreshold) internal设置批准多重签名操作所需的签名的 threshold。
没有访问控制的内部版本。
要求:
_validateReachableThreshold。_validateReachableThreshold() internal验证当前阈值是否可达。
要求:
signers 的长度必须 >= 到 threshold。 如果不是,则引发 MultiSignerERC7913UnreachableThreshold。_rawSignatureValidation(bytes32 hash, bytes signature) → bool internal解码、验证签名并检查签名者是否已授权。
有关更多详细信息,请参阅 _validateSignatures 和 _validateThreshold。
签名编码示例:
// Encode signers (verifier || key)
// **编码签名者 (验证器 || 密钥)**
bytes memory signer1 = abi.encodePacked(verifier1, key1);
bytes memory signer2 = abi.encodePacked(verifier2, key2);
// Order signers by their id
// **按 id 对签名者进行排序**
if (keccak256(signer1) > keccak256(signer2)) {
(signer1, signer2) = (signer2, signer1);
(signature1, signature2) = (signature2, signature1);
}
// Assign ordered signers and signatures
// **分配排序后的签名者和签名**
bytes[] memory signers = new bytes[](2);
bytes[] memory signatures = new bytes[](2);
signers[0] = signer1;
signatures[0] = signature1;
signers[1] = signer2;
signatures[1] = signature2;
// Encode the multi signature
// **编码多重签名**
bytes memory signature = abi.encode(signers, signatures);
要求:
signature 必须编码为 abi.encode(signers, signatures)。_validateSignatures(bytes32 hash, bytes[] signingSigners, bytes[] signatures) → bool valid internal使用签名者及其相应的签名验证签名。 返回签名者是否已授权以及签名对于给定哈希是否有效。
为了简单起见,此合约假定签名者按其 keccak256 哈希排序,以避免在遍历签名者时重复(即 keccak256(signer1) < keccak256(signer2))。 如果签名者未排序,则该函数将返回 false。 |
要求:
signatures 数组必须至少与 signingSigners 数组一样大。 否则会发生 panic。_validateThreshold(bytes[] validatingSigners) → bool internal验证签名者数量是否满足 threshold 要求。
假定签名者已被验证。 有关更多详细信息,请参阅 _validateSignatures。
ERC7913SignersAdded(bytes[] indexed signers) event添加签名者时发出。
ERC7913SignersRemoved(bytes[] indexed signers) event删除签名者时发出。
ERC7913ThresholdSet(uint256 threshold) event更新阈值时发出。
MultiSignerERC7913AlreadyExists(bytes signer) errorsigner 已存在。
MultiSignerERC7913NonexistentSigner(bytes signer) errorsigner 不存在。
MultiSignerERC7913InvalidSigner(bytes signer) errorsigner 的长度小于 20 个字节。
MultiSignerERC7913UnreachableThreshold(uint256 signers, uint256 threshold) error给定 signers 的数量,threshold 不可达。
MultiSignerERC7913Weightedimport "@openzeppelin/community-contracts/utils/cryptography/MultiSignerERC7913Weighted.sol";
MultiSignerERC7913 的扩展,支持加权签名。
此合约允许为每个签名者分配不同的权重,从而实现更灵活的治理方案。 例如,某些签名者可能比其他签名者具有更高的权重,从而允许加权投票或优先授权。
用法示例:
contract MyWeightedMultiSignerAccount is Account, MultiSignerERC7913Weighted, Initializable {
constructor() EIP712("MyWeightedMultiSignerAccount", "1") {}
function initialize(bytes[] memory signers, uint256[] memory weights, uint256 threshold)- 每个签名者必须存在于授权签名者集合中。如果不存在,则会通过 [`MultiSignerERC7913NonexistentSigner`](https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#MultiSignerERC7913-MultiSignerERC7913NonexistentSigner-bytes-) 回退。
- 每个权重必须大于 0。 如果不大于 0,则会通过 [`MultiSignerERC7913WeightedInvalidWeight`](https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#MultiSignerERC7913Weighted-MultiSignerERC7913WeightedInvalidWeight-bytes-uint256-) 回退。
- 有关阈值验证,请参阅 [`_validateReachableThreshold`](https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#MultiSignerERC7913Weighted-_validateReachableThreshold--)。
为每个签名者发出 [`ERC7913SignerWeightChanged`](https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#MultiSignerERC7913Weighted-ERC7913SignerWeightChanged-bytes-uint256-)。
##### `_addSigners(bytes[] newSigners)` internal
将 `newSigners` 添加到允许代表此合约签名的签名者中。
没有访问控制的内部版本。
要求:
- 每个 `newSigners` 的长度必须至少为 20 字节。如果不是,则会通过 [`MultiSignerERC7913InvalidSigner`](https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#MultiSignerERC7913-MultiSignerERC7913InvalidSigner-bytes-) 回退。
- 每个 `newSigners` 都不能被授权。请参阅 [`isSigner`](https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#MultiSignerERC7913-isSigner-bytes-)。 如果是,则会通过 [`MultiSignerERC7913AlreadyExists`](https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#MultiSignerERC7913-MultiSignerERC7913AlreadyExists-bytes-) 回退。
##### `_removeSigners(bytes[] oldSigners)` internal
请参阅 [`MultiSignerERC7913._removeSigners`](https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#MultiSignerERC7913-_removeSigners-bytes---)。
为每个删除的签名者发出 [`ERC7913SignerWeightChanged`](https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#MultiSignerERC7913Weighted-ERC7913SignerWeightChanged-bytes-uint256-)。
##### `_validateReachableThreshold()` internal
设置多重签名操作的阈值。没有访问控制的内部版本。
要求:
- [`totalWeight`](https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#MultiSignerERC7913Weighted-totalWeight--) 必须 `>=` [`threshold`](https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#MultiSignerERC7913-threshold--)。如果不是,则会抛出 [`MultiSignerERC7913UnreachableThreshold`](https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#MultiSignerERC7913-MultiSignerERC7913UnreachableThreshold-uint256-uint256-)。
| | |
| --- | --- |
| | 此函数有意不调用 `super._validateReachableThreshold`,因为基本实现<br>假定每个签名者的权重为 1,这是此加权实现的一个子集。请考虑多个<br>此函数的实现可能存在于合约中,因此重要的副作用可能会丢失<br>取决于线性化顺序。 |
##### `_validateThreshold(bytes[] signers) → bool` internal
验证签名者的总权重是否满足阈值要求。
| | |
| --- | --- |
| | 此函数有意不调用 `super. _validateThreshold`,因为基本实现<br>假定每个签名者的权重为 1,这是此加权实现的一个子集。请考虑多个<br>此函数的实现可能存在于合约中,因此重要的副作用可能会丢失<br>取决于线性化顺序。 |
##### `_weightSigners(bytes[] signers) → uint256` internal
计算一组签名者的总权重。 对于所有签名者权重,请使用[`totalWeight`](https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#MultiSignerERC7913Weighted-totalWeight--)。
##### `ERC7913SignerWeightChanged(bytes indexed signer, uint256 weight)` event
当签名者的权重更改时发出。
##### `MultiSignerERC7913WeightedInvalidWeight(bytes signer, uint256 weight)` error
当签名者的权重无效时抛出。
##### `MultiSignerERC7913WeightedMismatchedLength()` error
当阈值不可达时抛出。
#### `SignerP256`
```solidity hljs
import "@openzeppelin/community-contracts/utils/cryptography/SignerP256.sol";
使用
P256 签名实现的 AbstractSigner。
对于 Account 用法,提供了一个 _setSigner 函数来设置 signer 公钥。
对于工厂来说,这样做更容易,工厂很可能使用此合约的可初始化克隆。
用法示例:
contract MyAccountP256 is Account, SignerP256, Initializable {
function initialize(bytes32 qx, bytes32 qy) public initializer {
_setSigner(qx, qy);
}
}
未能在构建期间(如果单独使用)调用 _setSigner 或者在初始化期间(如果用作克隆)<br>可能会使签名者容易被抢跑或无法使用。 |
函数
_setSigner(qx, qy)
signer()
_rawSignatureValidation(hash, signature)
错误
SignerP256InvalidPublicKey(qx, qy)_setSigner(bytes32 qx, bytes32 qy) internal使用 P256 公钥设置签名者。此函数应在构建期间 或通过初始化程序调用。
signer() → bytes32 qx, bytes32 qy public返回签名者的 P256 公钥。
_rawSignatureValidation(bytes32 hash, bytes signature) → bool internal签名验证算法。
| 实现签名验证算法是一项对安全性敏感的操作,因为它涉及<br>加密验证。在部署之前,务必彻底审查和测试。考虑<br>使用其中一个签名验证库(ECDSA,<br>P256 或 RSA)。 |
SignerP256InvalidPublicKey(bytes32 qx, bytes32 qy) errorSignerERC7702import "@openzeppelin/community-contracts/utils/cryptography/SignerERC7702.sol";
EOA 实现的 AbstractSigner的实现。对 ERC-7702 账户很有用。
函数
_rawSignatureValidation(hash, signature)_rawSignatureValidation(bytes32 hash, bytes signature) → bool internal使用 EOA 的地址(即 address(this))验证签名。
SignerRSAimport "@openzeppelin/community-contracts/utils/cryptography/SignerRSA.sol";
使用
RSA 签名实现的 AbstractSigner。
对于 Account 用法,提供了一个 _setSigner 函数来设置 signer 公钥。
对于工厂来说,这样做更容易,工厂很可能使用此合约的可初始化克隆。
用法示例:
contract MyAccountRSA is Account, SignerRSA, Initializable {
function initialize(bytes memory e, bytes memory n) public initializer {
_setSigner(e, n);
}
}
未能在构建期间(如果单独使用)调用 _setSigner 或者在初始化期间(如果用作克隆)<br>可能会使签名者容易被抢跑或无法使用。 |
函数
_setSigner(e, n)
signer()
_rawSignatureValidation(hash, signature)
_setSigner(bytes e, bytes n) internal使用 RSA 公钥设置签名者。此函数应在构建期间 或通过初始化程序调用。
signer() → bytes e, bytes n public返回签名者的 RSA 公钥。
_rawSignatureValidation(bytes32 hash, bytes signature) → bool internal请参阅 AbstractSigner._rawSignatureValidation。 通过调用
RSA.pkcs1Sha256 验证 PKCSv1.5 签名。
按照 RFC8017(第 8.2.2 节)中概述的 RSASSA-PKCS1-V1_5-VERIFY 过程,提供的 hash 用作 M(消息),并按照 RFC 的第 9.2 节(步骤 1)的 EMSA-PKCS1-v1_5<br>编码使用 SHA256 重新哈希。 |
SignerZKEmailimport "@openzeppelin/community-contracts/utils/cryptography/SignerZKEmail.sol";
使用 ZKEmail 签名实现的 AbstractSigner。
ZKEmail 通过电子邮件消息实现安全身份验证和授权,利用来自 DKIMRegistry 的 DKIM 签名和由 verifier 启用的零知识证明
合约,该合约可确保电子邮件的真实性,而不会泄露敏感信息。DKIM
注册表被信任可以正确更新 DKIM 密钥,但用户可以覆盖此行为并
设置自己的密钥。此合约实现了在智能合约中验证基于电子邮件的
签名的核心功能。
开发人员必须在合约初始化期间设置以下组件:
accountSalt - 从用户的电子邮件地址和账户代码派生的唯一标识符。
DKIMRegistry - 用于域验证的 DKIM 注册表合约的实例。
verifier - 用于零知识证明验证的 Verifier 合约的实例。
templateId - sign hash 命令的模板 ID,用于定义预期的格式。
用法示例:
contract MyAccountZKEmail is Account, SignerZKEmail, Initializable {
function initialize(
bytes32 accountSalt,
IDKIMRegistry registry,
IVerifier verifier,
uint256 templateId
) public initializer {
// Will revert if the signer is already initialized
_setAccountSalt(accountSalt);
_setDKIMRegistry(registry);
_setVerifier(verifier);
_setTemplateId(templateId);
}
}
避免调用 _setAccountSalt,_setDKIMRegistry,_setVerifier 和 _setTemplateId<br>在构建期间(如果单独使用)或初始化期间(如果用作克隆)可能会<br>使签名者容易被抢跑或无法使用。 |
函数
accountSalt()
DKIMRegistry()
verifier()
templateId()
_setAccountSalt(accountSalt_)
_setDKIMRegistry(registry_)
_setVerifier(verifier_)
_setTemplateId(templateId_)
_rawSignatureValidation(hash, signature)
错误
InvalidEmailProof(err)accountSalt() → bytes32 public此合约所有者的唯一标识符,定义为电子邮件地址和账户代码的哈希值。
账户代码是 BN254 曲线的有限标量域中的一个随机整数。 它是用于从电子邮件地址派生用户的以太坊地址的 CREATE2 盐的私有随机性, 即 userEtherAddr := CREATE2(hash(userEmailAddr, accountCode))。
账户盐用于:
隐私:只要不向攻击者泄露随机生成的账户代码,就可以在链上实现电子邮件地址隐私。
安全:提供了一个不易被猜测或强力破解的唯一标识符,因为它派生自 电子邮件地址和随机账户代码。
确定性地址生成:允许创建基于电子邮件地址的确定性地址, 允许用户仅使用其电子邮件恢复其账户。
DKIMRegistry() → contract IDKIMRegistry publicDKIM 注册表合约的实例。 请参阅DKIM 验证。
verifier() → contract IVerifier publicVerifier 合约的实例。 请参阅 ZK 证明。
templateId() → uint256 publicsign hash 命令的命令模板。
_setAccountSalt(bytes32 accountSalt_) internal设置 accountSalt。
_setDKIMRegistry(contract IDKIMRegistry registry_) internal设置 DKIMRegistry 合约地址。
_setVerifier(contract IVerifier verifier_) internal设置 verifier 合约地址。
_setTemplateId(uint256 templateId_) internal设置命令的 templateId。
_rawSignatureValidation(bytes32 hash, bytes signature) → bool internal请参阅 AbstractSigner._rawSignatureValidation。通过以下方式验证原始签名:
从签名中解码电子邮件身份验证消息
验证哈希是否与命令参数匹配
检查模板 ID 是否匹配
验证账户盐
验证电子邮件证明
InvalidEmailProof(enum ZKEmailUtils.EmailProofError err) error证明验证错误。
ERC7913Utilsimport "@openzeppelin/community-contracts/utils/cryptography/ERC7913Utils.sol";
提供常用 ERC-7913 实用函数的库。
此库扩展了 SignatureChecker 的功能,以支持对没有自己的以太坊地址的密钥进行签名验证, 如 ERC-1271 中所示。
请参阅 ERC-7913。
函数
isValidSignatureNow(signer, hash, signature)
areValidSignaturesNow(hash, signers, signatures)
isValidSignatureNow(bytes signer, bytes32 hash, bytes signature) → bool internal验证给定签名者和哈希的签名。
签名者是一个 bytes 对象,它是地址与可选密钥的串联:
verifier || key。签名者的长度必须至少为 20 字节。
验证按如下方式完成:
- 如果 signer.length < 20:验证失败
– 如果 signer.length == 20:验证使用 {SignatureChecker} 完成
– 否则:验证使用 {IERC7913SignatureVerifier} 完成
areValidSignaturesNow(bytes32 hash, bytes[] signers, bytes[] signatures) → bool internal使用一组 signers 验证给定哈希的多个 signatures。
签名者必须按其 keccak256 哈希排序,以确保没有重复并优化
验证过程。如果签名者未正确排序,则该函数将返回 false。
要求:
signatures 数组的长度必须至少为 signers 数组的长度。ERC7913P256Verifierimport "@openzeppelin/community-contracts/utils/cryptography/ERC7913P256Verifier.sol";
支持 P256 (secp256r1) 密钥的 ERC-7913 签名验证器。
函数
verify(key, hash, signature)verify(bytes key, bytes32 hash, bytes signature) → bytes4 public验证 signature 作为 key 对 hash 的有效签名。
如果签名有效,则必须返回字节 4 魔术值 IERC7913SignatureVerifier.verify.selector。 如果签名无效,则应返回 0xffffffff 或回退。 如果密钥为空,则应返回 0xffffffff 或回退
ERC7913RSAVerifierimport "@openzeppelin/community-contracts/utils/cryptography/ERC7913RSAVerifier.sol";
支持 RSA 密钥的 ERC-7913 签名验证器。
函数
verify(key, hash, signature)verify(bytes key, bytes32 hash, bytes signature) → bytes4 public验证 signature 作为 key 对 hash 的有效签名。
如果签名有效,则必须返回字节 4 魔术值 IERC7913SignatureVerifier.verify.selector。 如果签名无效,则应返回 0xffffffff 或回退。 如果密钥为空,则应返回 0xffffffff 或回退
EnumerableSetExtendedimport "@openzeppelin/community-contracts/utils/structs/EnumerableSetExtended.sol";
用于管理非值类型的 集合 的库。
集合具有以下属性:
在恒定时间内(O(1))添加、删除和检查元素是否存在。
在 O(n) 中进行元素枚举。 不保证排序。
在 O(n) 中清除set (删除所有元素)。
contract Example {
// Add the library methods
using EnumerableSetExtended for EnumerableSetExtended.StringSet;
// Declare a set state variable
EnumerableSetExtended.StringSet private mySet;
}
支持 string ( StringSet)、bytes ( BytesSet) 和
bytes32[2] ( Bytes32x2Set) 类型的集合。
| 尝试从存储中删除此类结构可能会导致数据损坏,从而使结构<br>无法使用。<br>有关更多信息,请参阅 ethereum/solidity#11843。<br>为了清除 EnumerableSet,你可以逐个删除所有元素,或者使用<br>EnumerableSet 数组创建一个新的实例。 |
| 这是 openzeppelin/contracts/utils/struct/EnumerableSet.sol 的扩展。 |
函数
add(self, value)
remove(self, value)
clear(set)
contains(self, value)
length(self)
at(self, index)
values(self)
add(self, value)
remove(self, value)
clear(set)
contains(self, value)
length(self)
at(self, index)
values(self)
add(self, value)
remove(self, value)
clear(self)
contains(self, value)
length(self)
at(self, index)
values(self)
add(struct EnumerableSetExtended.StringSet self, string value) → bool internal将值添加到集合。 O(1)。
如果该值已添加到集合中,即如果该值尚不存在,则返回 true。
remove(struct EnumerableSetExtended.StringSet self, string value) → bool internal从集合中删除一个值。 O(1)。
如果该值已从集合中删除,即如果该值存在,则返回 true。
clear(struct EnumerableSetExtended.StringSet set) internal从集合中删除所有值。 复杂度为O(n)。
| 开发人员应记住,此函数具有无限成本,并且如果集合增长到清除它消耗太多 gas 而无法放入块中的程度,则使用它可能会使<br>函数无法调用。 |
contains(struct EnumerableSetExtended.StringSet self, string value) → bool internal如果该值在集合中,则返回 true。 O(1)。
length(struct EnumerableSetExtended.StringSet self) → uint256 internal返回集合中的值的数量。 O(1)。
at(struct EnumerableSetExtended.StringSet self, uint256 index) → string internal返回存储在集合中位置 index 的值。 O(1)。
请注意,不能保证数组中值的排序,并且当添加或删除更多值时,排序可能会更改。
要求:
index 必须严格小于 length。values(struct EnumerableSetExtended.StringSet self) → string[] internal在数组中返回整个集合
| 此操作会将整个存储复制到内存,这可能会非常昂贵。 这旨在<br>主要由没有任何 gas 费用的查询视图访问器使用。 开发人员应记住,<br>此函数具有无限成本,并且如果集合增长到复制到内存消耗太多 gas 而无法放入块中的程度,则将其用作更改状态函数的一部分可能会使函数无法调用。 |
add(struct EnumerableSetExtended.BytesSet self, bytes value) → bool internal将值添加到集合。 O(1)。
如果该值已添加到集合中,即如果该值尚不存在,则返回 true。
remove(struct EnumerableSetExtended.BytesSet self, bytes value) → bool internal从集合中删除一个值。 O(1)。
如果该值已从集合中删除,即如果该值存在,则返回 true。
clear(struct EnumerableSetExtended.BytesSet set) internal从集合中删除所有值。 复杂度为O(n)。
| 开发人员应记住,此函数具有无限成本,并且如果集合增长到清除它消耗太多 gas 而无法放入块中的程度,则使用它可能会使<br>函数无法调用。 |
contains(struct EnumerableSetExtended.BytesSet self, bytes value) → bool internal如果该值在集合中,则返回 true。 O(1)。
length(struct EnumerableSetExtended.BytesSet self) → uint256 internal返回集合中的值的数量。 O(1)。
at(struct EnumerableSetExtended.BytesSet self, uint256 index) → bytes internal返回存储在集合中位置 index 的值。 O(1)。
请注意,不能保证数组中值的排序,并且当添加或删除更多值时,排序可能会更改。
要求:
index 必须严格小于 length。values(struct EnumerableSetExtended.BytesSet self) → bytes[] internal在数组中返回整个集合
| 此操作会将整个存储复制到内存,这可能会非常昂贵。 这旨在<br>主要由没有任何 gas 费用的查询视图访问器使用。 开发人员应记住,<br>此函数具有无限成本,并且如果集合增长到复制到内存消耗太多 gas 而无法放入块中的程度,则将其用作更改状态函数的一部分可能会使函数无法调用。 |
add(struct EnumerableSetExtended.Bytes32x2Set self, bytes32[2] value) → bool internal将值添加到集合。 O(1)。
如果该值已添加到集合中,即如果该值尚不存在,则返回 true。
remove(struct EnumerableSetExtended.Bytes32x2Set self, bytes32[2] value) → bool internal从集合中删除一个值。 O(1)。
如果该值已从集合中删除,即如果该值存在,则返回 true。
clear(struct EnumerableSetExtended.Bytes32x2Set self) internal从集合中删除所有值。 复杂度为O(n)。
| 开发人员应记住,此函数具有无限成本,并且如果集合增长到清除它消耗太多 gas 而无法放入块中的程度,则使用它可能会使<br>函数无法调用。 |
contains(struct EnumerableSetExtended.Bytes32x2Set self, bytes32[2] value) → bool internal如果该值在集合中,则返回 true。 O(1)。
length(struct EnumerableSetExtended.Bytes32x2Set self) → uint256 internal返回集合中的值的数量。 O(1)。
at(struct EnumerableSetExtended.Bytes32x2Set self, uint256 index) → bytes32[2] internal返回存储在集合中位置 index 的值。 O(1)。
请注意,不能保证数组中值的排序,并且当添加或删除更多值时,排序可能会更改。
要求:
index 必须严格小于 length。values(struct EnumerableSetExtended.Bytes32x2Set self) → bytes32[2][] internal在数组中返回整个集合
| 此操作会将整个存储复制到内存,这可能会非常昂贵。 这旨在<br>主要由没有任何 gas 费用的查询视图访问器使用。 开发人员应记住,<br>此函数具有无限成本,并且如果集合增长到复制到内存消耗太多 gas 而无法放入块中的程度,则将其用作更改状态函数的一部分可能会使函数无法调用。 |
EnumerableMapExtendedimport "@openzeppelin/community-contracts/utils/structs/EnumerableMapExtended.sol";
用于管理Solidity 的
mapping
类型的可枚举变体,其中非值类型作为键的库。
Map 具有以下属性:
在恒定时间 (O(1)) 内添加、删除和检查条目是否存在。
在 O(n) 中枚举条目。 不保证排序。
Map 可以在 O(n) 中清除(删除所有条目)。
contract Example {
// Add the library methods
using EnumerableMapExtended for EnumerableMapExtended.BytesToUintMap;
// Declare a set state variable
EnumerableMapExtended.BytesToUintMap private myMap;
}
支持以下 map 类型:
bytes → uint256 ( BytesToUintMap)
string → string ( StringToStringMap)
| 尝试从存储中删除此类结构可能会导致数据损坏,从而使结构<br>无法使用。<br>有关更多信息,请<br>有序地清理 EnumerableMap,你可以逐个删除所有元素,也可以使用<br>EnumerableMap 数组创建一个新的实例。 |
| openzeppelin/contracts/utils/struct/EnumerableMap.sol 的扩展。 |
函数
set(map, key, value)
remove(map, key)
clear(map)
contains(map, key)
length(map)
at(map, index)
tryGet(map, key)
get(map, key)
keys(map)
set(map, key, value)
remove(map, key)
clear(map)
contains(map, key)
length(map)
at(map, index)
tryGet(map, key)
get(map, key)
keys(map)
错误
EnumerableMapNonexistentBytesKey(key)
EnumerableMapNonexistentStringKey(key)
set(struct EnumerableMapExtended.BytesToUintMap map, bytes key, uint256 value) → bool internal将键值对添加到 map,或更新现有 键的值。 O(1)。
如果该键已添加到 map 中,即如果该键尚不存在,则返回 true。
remove(struct EnumerableMapExtended.BytesToUintMap map, bytes key) → bool internal从 map 中删除一个键值对。 O(1)。
如果该键已从 map 中删除,即如果该键存在,则返回 true。
clear(struct EnumerableMapExtended.BytesToUintMap map) internal从 map 中删除所有条目。 复杂度为O(n)。
| 开发人员应记住,此函数具有无限成本,并且如果该 map 增长到清除它消耗太多 gas 而无法放入块中的程度,则使用它可能会使<br>函数无法调用。 |
contains(struct EnumerableMapExtended.BytesToUintMap map, bytes key) → bool internal如果该键在 map 中,则返回 true。 O(1)。
length(struct EnumerableMapExtended.BytesToUintMap map) → uint256 internal返回 map 中键值对的数量。 O(1)。
at(struct EnumerableMapExtended.BytesToUintMap map, uint256 index) → bytes key, uint256 value internal返回存储在 map 中位置 index 的键值 |
||
|---|---|---|
| 开发者应记住,此函数具有无限制的成本,如果 map 增长到清除它会消耗太多 gas 以至于无法放入一个区块的点,使用它可能会使该函数无法调用。 |
contains(struct EnumerableMapExtended.StringToStringMap map, string key) → bool internal如果键在 map 中,则返回 true。 O(1)。
length(struct EnumerableMapExtended.StringToStringMap map) → uint256 internal返回 map 中键值对的数量。 O(1)。
at(struct EnumerableMapExtended.StringToStringMap map, uint256 index) → string key, string value internal返回存储在 map 中位置 index 的键值对。 O(1)。
请注意,不能保证数组中条目的排序,并且在添加或删除更多条目时可能会更改。
要求:
index 必须严格小于 length.tryGet(struct EnumerableMapExtended.StringToStringMap map, string key) → bool exists, string value internal尝试返回与 key 关联的值。 O(1)。
如果 key 不在 map 中,则不会恢复。
get(struct EnumerableMapExtended.StringToStringMap map, string key) → string value internal返回与 key 关联的值。 O(1)。
要求:
key 必须在 map 中。keys(struct EnumerableMapExtended.StringToStringMap map) → string[] internal返回包含所有键的数组
| 此操作会将整个存储复制到内存,这可能会非常昂贵。这主要设计为由没有任何 gas 费用的 view 访问器使用。开发者应记住,此函数具有无限制的成本,如果 map 增长到复制到内存会消耗太多 gas 以至于无法放入一个区块的点,将其用作状态更改函数的一部分可能会使该函数无法调用。 |
EnumerableMapNonexistentBytesKey(bytes key) error查询不存在的 map 键。
EnumerableMapNonexistentStringKey(string key) error查询不存在的 map 键。
Masksimport "@openzeppelin/community-contracts/utils/Masks.sol";
用于处理位掩码的库
函数
toMask(group)
toMask(groups)
get(self, group)
isEmpty(self)
complement(m1)
union(m1, m2)
intersection(m1, m2)
difference(m1, m2)
symmetricDifference(m1, m2)
toMask(uint8 group) → Masks.Mask internal返回一个新掩码,其中 group 索引处的位设置为 1。
toMask(uint8[] groups) → Masks.Mask internal返回一个新掩码,其中 groups 索引处的位设置为 1。
get(Masks.Mask self, uint8 group) → bool internal获取 group 索引处掩码的值
isEmpty(Masks.Mask self) → bool internal掩码是否为 bytes32(0)
complement(Masks.Mask m1) → Masks.Mask internal反转掩码的位
union(Masks.Mask m1, Masks.Mask m2) → Masks.Mask internal对两个掩码执行按位 OR 运算
intersection(Masks.Mask m1, Masks.Mask m2) → Masks.Mask internal对两个掩码执行按位 AND 运算
difference(Masks.Mask m1, Masks.Mask m2) → Masks.Mask internal对两个掩码执行按位差分运算 (m1 - m2)
symmetricDifference(Masks.Mask m1, Masks.Mask m2) → Masks.Mask internal返回两个掩码的对称差 (∆),也称为异或并集或异或 (XOR)
- 原文链接: docs.openzeppelin.com/co...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!