Skip to content
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

Merged
merged 12 commits into from
Jul 15, 2024
Merged

Feat/docs updates #36

merged 12 commits into from
Jul 15, 2024

Conversation

JohnGuilding
Copy link
Collaborator

No description provided.

Copy link
Collaborator Author

@JohnGuilding JohnGuilding left a 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.
Copy link
Collaborator Author

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

Copy link
Contributor

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.

Copy link
Collaborator Author

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.
Copy link
Collaborator Author

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:

Suggested change
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.

Copy link
Contributor

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. 

Copy link
Collaborator Author

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:
Copy link
Collaborator Author

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:

Suggested change
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.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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`.
Copy link
Collaborator Author

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 and controller_eth_addr.

For step 7, should acceptanceRequest be something like recoveryRequest (can't remember name so that's just a guess)

@@ -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`.
Copy link
Collaborator Author

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

Copy link
Contributor

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.

Copy link
Collaborator Author

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?

@SoraSuegami SoraSuegami merged commit d4e2d61 into main Jul 15, 2024
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants