Skip to content

Commit

Permalink
contract unit test worked
Browse files Browse the repository at this point in the history
  • Loading branch information
SoraSuegami committed Aug 2, 2024
1 parent 4535f5c commit e60a6ca
Show file tree
Hide file tree
Showing 24 changed files with 531 additions and 833 deletions.
16 changes: 1 addition & 15 deletions packages/contracts/src/EmailWalletCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -185,21 +185,7 @@ contract EmailWalletCore is Initializable, UUPSUpgradeable, OwnableUpgradeable {
);

// Verify proof
require(
verifier.verifyEmailOpProof(
emailOp.emailProof.emailDomain,
emailOp.emailProof.dkimPublicKeyHash,
emailOp.emailProof.timestamp,
emailOp.emailProof.emailNullifier,
emailOp.emailProof.maskedSubject,
emailOp.emailProof.accountSalt,
emailOp.emailProof.isCodeExist,
emailOp.emailProof.hasEmailRecipient,
emailOp.emailProof.recipientEmailAddrCommit,
emailOp.emailProof.proof
),
"invalid email proof"
);
require(verifier.verifyEmailProof(emailOp.emailProof), "invalid email proof");
}

/// @notice Handle an EmailOp - the main function relayer should call for each Email
Expand Down
31 changes: 14 additions & 17 deletions packages/contracts/src/handlers/AccountHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,12 @@ contract AccountHandler is Initializable, UUPSUpgradeable, OwnableUpgradeable {
/// @notice Create new account and wallet for a user
/// @param emailProof Proof and instances of the email proof
/// @param psiPoint PSI point of the user under the relayer
function createAccount(EmailProof calldata emailProof, bytes calldata psiPoint) public returns (Wallet wallet) {
/// @param psiProof Proof of the PSI point circuit
function createAccount(
EmailProof calldata emailProof,
bytes calldata psiPoint,
bytes calldata psiProof
) public returns (Wallet wallet) {
require(emailProof.accountSalt != bytes32(0), "invalid wallet salt");
require(
accountSaltOfPSIPoint[psiPoint] == bytes32(0) || accountSaltOfPSIPoint[psiPoint] == emailProof.accountSalt,
Expand All @@ -104,23 +109,15 @@ contract AccountHandler is Initializable, UUPSUpgradeable, OwnableUpgradeable {
require(emailProof.timestamp + emailValidityDuration > block.timestamp, "email expired");
}

require(
verifier.verifyEmailOpProof(
emailProof.emailDomain,
emailProof.dkimPublicKeyHash,
emailProof.timestamp,
emailProof.emailNullifier,
emailProof.maskedSubject,
emailProof.accountSalt,
emailProof.isCodeExist,
emailProof.hasEmailRecipient,
emailProof.recipientEmailAddrCommit,
emailProof.proof
),
"invalid account creation proof"
);
require(verifier.verifyEmailProof(emailProof), "invalid account creation proof");

accountSaltOfPSIPoint[psiPoint] = emailProof.accountSalt;
if (accountSaltOfPSIPoint[psiPoint] == bytes32(0)) {
require(
verifier.verifyPsiPointProof(emailProof.accountSalt, psiPoint, psiProof),
"invalid PSI point proof"
);
accountSaltOfPSIPoint[psiPoint] = emailProof.accountSalt;
}
emailNullifiers[emailProof.emailNullifier] = true;

wallet = _deployWallet(emailProof.accountSalt);
Expand Down
26 changes: 4 additions & 22 deletions packages/contracts/src/interfaces/IVerifier.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "./Types.sol";

interface IVerifier {
// /// @notice Verify the proof to create an account
// /// @notice Verifies email from a user that contains `accountSalt` in the email header
Expand Down Expand Up @@ -29,28 +31,8 @@ interface IVerifier {
/// is DKIM signed by public key whose hash is `dkimPublicKeyHash`,
/// the subject is same as `maskedSubject` with email address masked (if any),
/// and email address in subject is used to derive `recipientEmailAddrCommit`
/// @param emailDomain The domain of the user's email address
/// @param dkimPublicKeyHash The hash of the DKIM public key of `emailDomain`
/// @param emailNullifier The nullifier computed for the email
/// @param timestamp The timestamp of the email
/// @param maskedSubject The subject of the email with (any) email address masked
/// @param accountSalt The accountSalt used to derive user's account address - hash(emailAddress, accountSalt)
/// @param isCodeExist Whether the email contains an invitation code
/// @param hasEmailRecipient Whether the email subject has a recipient (email address)
/// @param recipientEmailAddrCommit The hash of recipeint's email address (from subject) and a randomness
/// @dev `emailAddrPointer`, `dkimPublicKeyHash` should be the values previously stored in the contract
function verifyEmailOpProof(
string memory emailDomain,
bytes32 dkimPublicKeyHash,
uint256 timestamp,
bytes32 emailNullifier,
string memory maskedSubject,
bytes32 accountSalt,
bool isCodeExist,
bool hasEmailRecipient,
bytes32 recipientEmailAddrCommit,
bytes memory proof
) external view returns (bool);
/// @param emailProof The email proof
function verifyEmailProof(EmailProof calldata emailProof) external view returns (bool);

/// @notice Verify the proof to claim and unclaimed to a recipient account
/// @notice This verify that same email address is used in `recipientEmailAddrPointer` and `recipientEmailAddrCommit`
Expand Down
49 changes: 21 additions & 28 deletions packages/contracts/src/verifier/Verifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,45 +59,38 @@ contract AllVerifiers is IVerifier {
// }

/// @inheritdoc IVerifier
function verifyEmailOpProof(
string memory emailDomain,
bytes32 dkimPublicKeyHash,
uint256 timestamp,
bytes32 emailNullifier,
string memory maskedSubject,
bytes32 accountSalt,
bool isCodeExist,
bool hasEmailRecipient,
bytes32 recipientEmailAddrCommit,
bytes memory proof
) external view returns (bool) {
function verifyEmailProof(EmailProof calldata emailProof) external view returns (bool) {
(uint256[2] memory pA, uint256[2][2] memory pB, uint256[2] memory pC) = abi.decode(
proof,
emailProof.proof,
(uint256[2], uint256[2][2], uint256[2])
);

uint256[SUBJECT_FIELDS + DOMAIN_FIELDS + 7] memory pubSignals;

uint256[] memory stringFields;
stringFields = _packBytes2Fields(bytes(emailDomain), DOMAIN_BYTES);
for (uint256 i = 0; i < DOMAIN_FIELDS; i++) {
pubSignals[i] = stringFields[i];
{
uint256[] memory stringFields;
stringFields = _packBytes2Fields(bytes(emailProof.emailDomain), DOMAIN_BYTES);
for (uint256 i = 0; i < DOMAIN_FIELDS; i++) {
pubSignals[i] = stringFields[i];
}
}
delete stringFields;

pubSignals[DOMAIN_FIELDS] = uint256(dkimPublicKeyHash);
pubSignals[DOMAIN_FIELDS + 1] = uint256(emailNullifier);
pubSignals[DOMAIN_FIELDS + 2] = timestamp;
pubSignals[DOMAIN_FIELDS] = uint256(emailProof.dkimPublicKeyHash);
pubSignals[DOMAIN_FIELDS + 1] = uint256(emailProof.emailNullifier);
pubSignals[DOMAIN_FIELDS + 2] = emailProof.timestamp;

stringFields = _packBytes2Fields(bytes(maskedSubject), SUBJECT_BYTES);
for (uint256 i = 0; i < SUBJECT_FIELDS; i++) {
pubSignals[DOMAIN_FIELDS + 3 + i] = stringFields[i];
{
uint256[] memory stringFields;
stringFields = _packBytes2Fields(bytes(emailProof.maskedSubject), SUBJECT_BYTES);
for (uint256 i = 0; i < SUBJECT_FIELDS; i++) {
pubSignals[DOMAIN_FIELDS + 3 + i] = stringFields[i];
}
}

pubSignals[DOMAIN_FIELDS + 3 + SUBJECT_FIELDS] = uint256(accountSalt);
pubSignals[DOMAIN_FIELDS + 3 + SUBJECT_FIELDS + 1] = isCodeExist ? 1 : 0;
pubSignals[DOMAIN_FIELDS + 3 + SUBJECT_FIELDS + 2] = hasEmailRecipient ? 1 : 0;
pubSignals[DOMAIN_FIELDS + 3 + SUBJECT_FIELDS + 3] = uint256(recipientEmailAddrCommit);
pubSignals[DOMAIN_FIELDS + 3 + SUBJECT_FIELDS] = uint256(emailProof.accountSalt);
pubSignals[DOMAIN_FIELDS + 3 + SUBJECT_FIELDS + 1] = emailProof.isCodeExist ? 1 : 0;
pubSignals[DOMAIN_FIELDS + 3 + SUBJECT_FIELDS + 2] = emailProof.hasEmailRecipient ? 1 : 0;
pubSignals[DOMAIN_FIELDS + 3 + SUBJECT_FIELDS + 3] = uint256(emailProof.recipientEmailAddrCommit);
return emailSenderVerifier.verifyProof(pA, pB, pC, pubSignals);
}

Expand Down
113 changes: 62 additions & 51 deletions packages/contracts/test/AccountHandler.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,21 @@ contract AccountTest is EmailWalletCoreTestHelper {
vm.expectEmit(true, true, true, true);

EmailProof memory emailProof = EmailProof({
proof: mockProof,
domain: emailDomain,
emailDomain: emailDomain,
dkimPublicKeyHash: mockDKIMHash,
nullifier: emailNullifier,
timestamp: block.timestamp
timestamp: block.timestamp,
emailNullifier: emailNullifier,
maskedSubject: "",
accountSalt: accountSalt,
isCodeExist: true,
hasEmailRecipient: false,
recipientEmailAddrCommit: bytes32(0),
proof: mockProof
});

emit EmailWalletEvents.AccountCreated(accountSalt, psiPoint);

accountHandler.createAccount(accountSalt, psiPoint, emailProof);
accountHandler.createAccount(emailProof, psiPoint, mockProof);
vm.stopPrank();

Wallet wallet = Wallet(payable(accountHandler.getWalletOfSalt(accountSalt)));
Expand Down Expand Up @@ -90,29 +95,33 @@ contract AccountTest is EmailWalletCoreTestHelper {
bytes32 accountSalt2 = bytes32(uint256(3));

vm.startPrank(relayer);
accountHandler.createAccount(
accountSalt,
psiPoint,
EmailProof({
proof: mockProof,
domain: emailDomain,
dkimPublicKeyHash: mockDKIMHash,
nullifier: emailNullifier,
timestamp: block.timestamp
})
);
EmailProof memory emailProof = EmailProof({
emailDomain: emailDomain,
dkimPublicKeyHash: mockDKIMHash,
timestamp: block.timestamp,
emailNullifier: emailNullifier,
maskedSubject: "",
accountSalt: accountSalt,
isCodeExist: true,
hasEmailRecipient: false,
recipientEmailAddrCommit: bytes32(0),
proof: mockProof
});
accountHandler.createAccount(emailProof, psiPoint, mockProof);
vm.expectRevert("PSI point exists for another wallet salt");
accountHandler.createAccount(
accountSalt2,
psiPoint,
EmailProof({
proof: mockProof,
domain: emailDomain,
dkimPublicKeyHash: mockDKIMHash,
nullifier: emailNullifier,
timestamp: block.timestamp
})
);
emailProof = EmailProof({
emailDomain: emailDomain,
dkimPublicKeyHash: mockDKIMHash,
timestamp: block.timestamp,
emailNullifier: emailNullifier,
maskedSubject: "",
accountSalt: accountSalt2,
isCodeExist: true,
hasEmailRecipient: false,
recipientEmailAddrCommit: bytes32(0),
proof: mockProof
});
accountHandler.createAccount(emailProof, psiPoint, mockProof);
vm.stopPrank();
}

Expand All @@ -133,19 +142,19 @@ contract AccountTest is EmailWalletCoreTestHelper {
address predictedAddr = accountHandler.getWalletOfSalt(accountSalt);

vm.startPrank(relayer);
address walletAddr = address(
accountHandler.createAccount(
accountSalt,
psiPoint,
EmailProof({
proof: mockProof,
domain: emailDomain,
dkimPublicKeyHash: mockDKIMHash,
nullifier: emailNullifier,
timestamp: block.timestamp
})
)
);
EmailProof memory emailProof = EmailProof({
emailDomain: emailDomain,
dkimPublicKeyHash: mockDKIMHash,
timestamp: block.timestamp,
emailNullifier: emailNullifier,
maskedSubject: "",
accountSalt: accountSalt,
isCodeExist: true,
hasEmailRecipient: false,
recipientEmailAddrCommit: bytes32(0),
proof: mockProof
});
address walletAddr = address(accountHandler.createAccount(emailProof, psiPoint, mockProof));
vm.stopPrank();

assertEq(walletAddr, predictedAddr);
Expand All @@ -157,17 +166,19 @@ contract AccountTest is EmailWalletCoreTestHelper {

vm.startPrank(relayer);
vm.expectRevert("wallet already deployed");
accountHandler.createAccount(
accountSalt,
psiPoint,
EmailProof({
proof: mockProof,
domain: emailDomain,
dkimPublicKeyHash: mockDKIMHash,
nullifier: emailNullifier,
timestamp: block.timestamp
})
);
EmailProof memory emailProof = EmailProof({
emailDomain: emailDomain,
dkimPublicKeyHash: mockDKIMHash,
timestamp: block.timestamp,
emailNullifier: emailNullifier,
maskedSubject: "",
accountSalt: accountSalt,
isCodeExist: true,
hasEmailRecipient: false,
recipientEmailAddrCommit: bytes32(0),
proof: mockProof
});
accountHandler.createAccount(emailProof, psiPoint, mockProof);
vm.stopPrank();
}

Expand Down
4 changes: 2 additions & 2 deletions packages/contracts/test/EmailWalletCore.cmd.dkim.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ contract DKIMRegistryCommandTest is EmailWalletCoreTestHelper {
EmailOp memory emailOp = _getBaseEmailOp();
emailOp.command = Commands.DKIM;
emailOp.newDkimRegistry = dkimRegistryAddr;
emailOp.maskedSubject = subject;
emailOp.emailProof.maskedSubject = subject;

vm.startPrank(relayer);
(bool success, , , ) = core.handleEmailOp(emailOp);
Expand All @@ -46,7 +46,7 @@ contract DKIMRegistryCommandTest is EmailWalletCoreTestHelper {
EmailOp memory emailOp = _getBaseEmailOp();
emailOp.command = Commands.DKIM;
emailOp.newDkimRegistry = dkimRegistryAddr;
emailOp.maskedSubject = subject;
emailOp.emailProof.maskedSubject = subject;

vm.startPrank(relayer);
(bool success, , , ) = core.handleEmailOp(emailOp);
Expand Down
Loading

0 comments on commit e60a6ca

Please sign in to comment.