Skip to content

Allow multiple templateIds in SignerZKEmail #168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions contracts/mocks/account/AccountZKEmailMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ contract AccountZKEmailMock is Account, SignerZKEmail, ERC7739, ERC7821, ERC721H
bytes32 accountSalt_,
IDKIMRegistry registry_,
IVerifier verifier_,
uint256 templateId_
bytes32[] memory templateIds_
) EIP712("AccountZKEmailMock", "1") {
_setAccountSalt(accountSalt_);
_setDKIMRegistry(registry_);
_setVerifier(verifier_);
_setTemplateId(templateId_);
_addTemplateIds(templateIds_);
}

/// @inheritdoc ERC7821
Expand Down
45 changes: 34 additions & 11 deletions contracts/utils/cryptography/signers/SignerZKEmail.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {IVerifier} from "@zk-email/email-tx-builder/src/interfaces/IVerifier.sol
import {EmailAuthMsg} from "@zk-email/email-tx-builder/src/interfaces/IEmailTypes.sol";
import {AbstractSigner} from "./AbstractSigner.sol";
import {ZKEmailUtils} from "../ZKEmailUtils.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

/**
* @dev Implementation of {AbstractSigner} using https://docs.zk.email[ZKEmail] signatures.
Expand All @@ -23,7 +24,7 @@ import {ZKEmailUtils} from "../ZKEmailUtils.sol";
* * {accountSalt} - A unique identifier derived from the user's email address and account code.
* * {DKIMRegistry} - An instance of the DKIM registry contract for domain verification.
* * {verifier} - An instance of the Verifier contract for zero-knowledge proof validation.
* * {templateId} - The template ID of the sign hash command, defining the expected format.
* * {templateIds} - The template IDs of the sign hash command, defining the expected format.
*
* Example of usage:
*
Expand All @@ -33,13 +34,13 @@ import {ZKEmailUtils} from "../ZKEmailUtils.sol";
* bytes32 accountSalt,
* IDKIMRegistry registry,
* IVerifier verifier,
* uint256 templateId
* bytes32[] templateIds
* ) public initializer {
* // Will revert if the signer is already initialized
* _setAccountSalt(accountSalt);
* _setDKIMRegistry(registry);
* _setVerifier(verifier);
* _setTemplateId(templateId);
* _addTemplateIds(templateIds);
* }
* }
* ```
Expand All @@ -50,11 +51,18 @@ import {ZKEmailUtils} from "../ZKEmailUtils.sol";
*/
abstract contract SignerZKEmail is AbstractSigner {
using ZKEmailUtils for EmailAuthMsg;
using EnumerableSet for EnumerableSet.Bytes32Set;

bytes32 private _accountSalt;
IDKIMRegistry private _registry;
IVerifier private _verifier;
uint256 private _templateId;
EnumerableSet.Bytes32Set private _templateIds;

/// @dev Emitted when a template ID is added.
event TemplateIdAdded(bytes32 indexed templateId);

/// @dev Emitted when a template ID is removed.
event TemplateIdRemoved(bytes32 indexed templateId);

/// @dev Proof verification error.
error InvalidEmailProof(ZKEmailUtils.EmailProofError err);
Expand Down Expand Up @@ -94,9 +102,15 @@ abstract contract SignerZKEmail is AbstractSigner {
return _verifier;
}

/// @dev The command template of the sign hash command.
function templateId() public view virtual returns (uint256) {
return _templateId;
/**
* @dev Command templates enabled for this signer.
*
* WARNING: This operation copies the entire templateIds set to memory, which can be expensive. This is designed
* for view accessors queried without gas fees. Using it in state-changing functions may become uncallable
* if the templateIds set grows too large.
*/
function templateIds() public view virtual returns (bytes32[] memory) {
return _templateIds.values();
}

/// @dev Set the {accountSalt}.
Expand All @@ -114,9 +128,18 @@ abstract contract SignerZKEmail is AbstractSigner {
_verifier = verifier_;
}

/// @dev Set the command's {templateId}.
function _setTemplateId(uint256 templateId_) internal virtual {
_templateId = templateId_;
/// @dev Adds the `_templateIds` to the command's {templateIds}.
function _addTemplateIds(bytes32[] memory templateIds_) internal virtual {
for (uint256 i = 0; i < templateIds_.length; i++) {
if (_templateIds.add(templateIds_[i])) emit TemplateIdAdded(templateIds_[i]);
}
}

/// @dev Removes the `_templateIds` from the command's {templateIds}.
function _removeTemplateIds(bytes32[] memory templateIds_) internal virtual {
for (uint256 i = 0; i < templateIds_.length; i++) {
if (_templateIds.remove(templateIds_[i])) emit TemplateIdRemoved(templateIds_[i]);
}
}

/**
Expand Down Expand Up @@ -153,7 +176,7 @@ abstract contract SignerZKEmail is AbstractSigner {
if (signature.length < 512) return false;
EmailAuthMsg memory emailAuthMsg = abi.decode(signature, (EmailAuthMsg));
return (abi.decode(emailAuthMsg.commandParams[0], (bytes32)) == hash &&
emailAuthMsg.templateId == templateId() &&
_templateIds.contains(bytes32(emailAuthMsg.templateId)) &&
emailAuthMsg.proof.accountSalt == accountSalt() &&
emailAuthMsg.isValidZKEmail(DKIMRegistry(), verifier()) == ZKEmailUtils.EmailProofError.NoError);
}
Expand Down
Loading