-
Notifications
You must be signed in to change notification settings - Fork 16
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
Feat/docs updates #36
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, left a few comments :)
README.md
Outdated
It provides an entry function `authEmail` to verify the email-auth message by calling the verifier and the DKIM registry contracts. | ||
<!-- Besides, it supports [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271). --> | ||
After the email-auth message is processed in the `authEmail` function, the `isValidSignature` function of the email-auth contract returns true for the hash of the data in the email-auth message and its email nullifier, a 32-byte data unique to each email. | ||
Its contract Ethereum address is derived from its initial owner address, an address of a controller contract that can define the supported subject templates and the account salt, i.e., the hash of the user's email address and one account code held by the user, through CREATE2. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two questions:
an address of a controller contract that can define the supported subject templates and the account salt
Does the controller contract strictly define the account salt? My mental model was that the account salt was defined by the zkemail spec/protocol
the account salt, i.e., the hash of the user's email address and one account code held by the user, through CREATE2
does the above statement contradict this natspec? https://github.com/zkemail/ether-email-auth/blob/364405b304fc4c153f35acb1816a9bed619e4c31/packages/contracts/src/EmailAccountRecovery.sol#L103
The natspec comment implies to me that the account salt does not include the account code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your comments!
Does the controller contract strictly define the account salt? My mental model was that the account salt was defined by the zkemail spec/protocol
Sorry for the confusion.
The account salt is defined by our spec.
That sentence does not mean that the controller contract that can define the account salt.
The correct structure of the sentence is as follows:
"Its contract Ethereum address is derived from 1) its initial owner address, an address of a controller contract (that can define the supported subject templates) and 3) the account salt, (i.e., the hash of the user's email address and one account code held by the user), through CREATE2."
The natspec comment implies to me that the account salt does not include the account code
That natspec comment describes not the definition of account salt but its abstracted property.
In other words, a developer needs to understand at least that the account salt is different for each pair of the guardian's email address and the wallet address.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Its contract Ethereum address is derived from 1) its initial owner address, an address of a controller contract (that can define the supported subject templates) and 3) the account salt, (i.e., the hash of the user's email address and one account code held by the user), through CREATE2."
Makes perfect sense, cheers
That natspec comment describes not the definition of account salt but its abstracted property.
ok I see, I think as long as the account salt is defined somewhere, then this specific natspec looks good to me
README.md
Outdated
|
||
Your application contract can employ those contracts in the following manner: | ||
1. For a new email user, the application contract deploys (a proxy of) the email-auth contract. Subsequently, the application contract sets the addresses of the verifier and the DKIM registry contracts and some subject templates for your application to the email-auth contract. | ||
1. For a new email user, the application contract deploys (a proxy of) the email-auth contract. Subsequently, the application contract sets the addresses of the verifier and the DKIM registry contracts and some subject templates for your application to the email-auth contract as its controller contract. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for your application to the email-auth contract as its controller contract
The "as its controller contract" part of the sentence doesn't make sense to me. Would something like this make sense:
1. For a new email user, the application contract deploys (a proxy of) the email-auth contract. Subsequently, the application contract sets the addresses of the verifier and the DKIM registry contracts and some subject templates for your application to the email-auth contract as its controller contract. | |
1. For a new email user, the application contract deploys (a proxy of) the email-auth contract. Subsequently, the application contract sets the addresses of the verifier and the DKIM registry contracts and some subject templates for your application to the email-auth contract. The controller contract that has permissions to modify `EmailAuth` instances is also set. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your suggestion!
In that context, the application contract is the same as the controller contract.
How about the following modification?
Subsequently, the application contract sets the addresses of the verifier and the DKIM registry contracts and some subject templates for your application to the email-auth contract. Here, the email-auth contract registers the application contract as a controller contract that has permissions to modify the subject templates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Yeah I like your suggestion
README.md
Outdated
@@ -103,53 +101,53 @@ Our SDK only performs the verification of the email-auth message. | |||
Here, we present a list of security notes that you should check. | |||
- As described in the Subsection of "Invitation Code", for each email user, your application contract must ensure that the value of `isCodeExist` in the first email-auth message is true. | |||
- The application contract can configure multiple subject templates for the same email-auth contract. However, the Relayer can choose any of the configured templates, as long as the message in the Subject matches with the chosen template. For example, if there are two templates "Send {decimals} {string}" and "Send {string}", the message "Send 1.23 ETH" matches with both templates. We recommend defining the subject templates without such ambiguities. | |||
- To protect the privacy of the users' email addresses, you should carefully design not only the contracts but also the Relayer server, which stores the users' account codes. For example, an adversary can breach that privacy by exploiting an API provided by the Relayer such that returns the Ethereum address for the given email address and its stored account code. Additionally, if any Relayer's API returns an error when no account code is stored for the given email address, the adversary can learn which email addresses are registered. | |||
- To protect the privacy of the users' email addresses, you should carefully design not only the contracts but also the Relayer server, which stores the users' account codes. For example, an adversary can breach that privacy by exploiting an API provided by the Relayer that returns the Ethereum address for the given email address and its stored account code. Additionally, if any Relayer's API returns an error when no account code is stored for the given email address, the adversary can learn which email addresses are registered. | |||
|
|||
## Application: Email-based Account Recovery | |||
As a representative example of applications using our SDK, we provide contracts and a Relayer server for email-based account recovery. They assume a life cycle of the account recovery in four phases: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This example is for recovering an ECDSA private key. It might be worth mentioning that email recovery can be used to recover any validation mechanism, so that readers do not think that this is just for ECDSA-based accounts. Something like:
As a representative example of applications using our SDK, we provide contracts and a Relayer server for email-based account recovery. They assume a life cycle of the account recovery in four phases: | |
Email-based account recovery can be used to recover any account type, the following representative example will illustrate how to use our SDK to recover an ECDSA-based smart account . We provide contracts and a production Relayer server for email-based account recovery. They assume a life cycle of the account recovery in four phases: |
README.md
Outdated
3. (Contracts 3/6) You also define how to extract an account address to be recovered from the subject parameters for the templates in `acceptanceSubjectTemplates` and `recoverySubjectTemplates`, respectively. | ||
3. (Contracts 4/6) Before implementing the remaining functions in `EmailAccountRecovery`, you implement a requesting function into the controller that allows the account owner to request a guardian, which is expected to be called by the account owner directly. Our SDK **does not** specify any interface or implementation of this function. For example, the function can simply take as input a new guardian's email-auth contract address computed by CREATE2, and store it as a guardian candidate. If you want to set a timelock for each guardian, the requesting function can additionally take the timelock length as input. | ||
4. (Contracts 5/6) You implement the `acceptGuardian` and `processRecovery` functions into the controller. These two functions are, respectively, called by the controller itself after verifying the email-auth messages for accepting a guardian and processing a recovery. Each of them takes as input the guardian's email-auth contract address, an index of the chosen subject template, the values for the variable parts of the message in the Subject, and the email nullifier. You can assume these arguments are already verified. For example, the `acceptGuardian` function stores the given guardian's address as the confirmed guardian, and the `processRecovery` function stores the given new owner's address or sets a timelock. | ||
5. (Contracts 6/6) You finally implement the `completeRecovery` function into the controller. It should rotate the owner's address in the account contract if some required conditions hold. This function is assumed to be called by the Relayer and can take as input arbitrary bytes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5. (Contracts 6/6) You finally implement the `completeRecovery` function into the controller. It should rotate the owner's address in the account contract if some required conditions hold. This function is assumed to be called by the Relayer and can take as input arbitrary bytes. | |
5. (Contracts 6/6) You finally implement the `completeRecovery` function into the controller. It should rotate the owner's address in the account contract if some required conditions hold. This function can be called by anyone, but is assumed to be called by the Relayer and can take as input arbitrary bytes. |
README.md
Outdated
4. (Contracts 5/6) You implement the `acceptGuardian` and `processRecovery` functions into the controller. These two functions are, respectively, called by the controller itself after verifying the email-auth messages for accepting a guardian and processing a recovery. Each of them takes as input the guardian's email-auth contract address, an index of the chosen subject template, the values for the variable parts of the message in the Subject, and the email nullifier. You can assume these arguments are already verified. For example, the `acceptGuardian` function stores the given guardian's address as the confirmed guardian, and the `processRecovery` function stores the given new owner's address or sets a timelock. | ||
5. (Contracts 6/6) You finally implement the `completeRecovery` function into the controller. It should rotate the owner's address in the account contract if some required conditions hold. This function is assumed to be called by the Relayer and can take as input arbitrary bytes. | ||
6. (Frontend 1/3) Next, you build a frontend for the account recovery. You prepare a page where the account owner configures guardians. It requests the account owner to input the account address (`account_eth_addr`) and the guardian's email address (`guardian_email_addr`), generates a random account code (`account_code`), constructs an expected subject (`subject`) for the subject template whose index is `template_idx` in the output of the `acceptanceSubjectTemplates()` function. It then requests the account owner to call the requesting function in the controller contract. After that, it calls the Relayer's `acceptanceRequest` API with `guardian_email_addr`, `account_code`, `template_idx`, and the address of the controller contract `controller_eth_addr`. | ||
7. (Frontend 2/3) You also prepare a page where the account owner requests guardians to recover the account. It requests the account owner to input the account address (`account_eth_addr`) and the guardian's email address (`guardian_email_addr`), and constructs an expected subject (`subject`) for the subject template whose index is `template_idx` in the output of the `recoverySubjectTemplates()` function. It calls the Relayer's `acceptanceRequest` API with those data and `controller_eth_addr`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It calls the Relayer's
acceptanceRequest
API with those data andcontroller_eth_addr
.
For step 7, should acceptanceRequest
be something like recoveryRequest
(can't remember name so that's just a guess)
packages/contracts/README.md
Outdated
@@ -125,6 +135,9 @@ It provides the following functions. | |||
1. Assert `msg.sender==owner` . | |||
2. Assert `_dkimRegistryAddr!=0`. | |||
3. Update `dkim` to `DKIMRegistry(_dkimRegistryAddr)`. | |||
- `getSubjectTemplate(uint _templateId) public view returns (string[] memory)` | |||
1. Assert that the template for `_templateId` exists, i.e., `subjectTemplates[_templateId].length >0` holds. | |||
2. Return `subjectTemplates[_templateId]`. | |||
- `insertSubjectTemplate(uint _templateId, string[] _subjectTemplate)` | |||
1. Assert `_subjectTemplate.length>0` . | |||
2. Assert `msg.sender==owner`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be controller?
Same for updateSubjectTemplate
, deleteSubjectTemplate
, setTimestampCheckEnabled
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, sorry for forgetting to update them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One part of EmailAccountRecovery
that took me some time to understand was the use of uint templateIdx
in different places. Do you think it would be worth adding a small explanation somewhere in the readme?
…email-auth into feat/docs-updates
No description provided.