Skip to content

Commit

Permalink
feat: add PasskeyBinder
Browse files Browse the repository at this point in the history
  • Loading branch information
zkbenny committed Sep 1, 2024
1 parent 29a8907 commit 353833e
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 7 deletions.
8 changes: 4 additions & 4 deletions l1-contracts/scripts/upgrade-consistency-checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,16 @@ const maxNumberOfHyperchains = 100;
const expectedStoredBatchHashZero = "0x1574fa776dec8da2071e5f20d71840bfcbd82c2bca9ad68680edfedde1710bc4";
const expectedL2BridgeAddress = "0x11f943b2c77b743AB90f4A0Ae7d5A4e7FCA3E102";
const expectedL1LegacyBridge = "0x57891966931Eb4Bb6FB81430E6cE0A03AAbDe063";
const expectedGenesisBatchCommitment = "0x2d00e5f8d77afcebf58a6b82ae56ba967566fe7dfbcb6760319fb0d215d18ffd";
const expectedIndexRepeatedStorageChanges = BigNumber.from(54);
const expectedGenesisBatchCommitment = "0x667177606c5d72ce5988172b151b0a97e6cd67de002f86ec66c3899cd9ce7d4c";
const expectedIndexRepeatedStorageChanges = BigNumber.from(56);
const expectedProtocolVersion = BigNumber.from(2).pow(32).mul(24);

const expectedGenesisRoot = "0xabdb766b18a479a5c783a4b80e12686bc8ea3cc2d8a3050491b701d72370ebb5";
const expectedGenesisRoot = "0x2e86468e2aa39e313daed4f4ea1865ef11876cc700fea35a1695de22af99915b";
const expectedRecursionNodeLevelVkHash = "0xf520cd5b37e74e19fdb369c8d676a04dce8a19457497ac6686d2bb95d94109c8";
const expectedRecursionLeafLevelVkHash = "0xf9664f4324c1400fa5c3822d667f30e873f53f1b8033180cd15fe41c1e2355c6";
const expectedRecursionCircuitsSetVksHash = "0x0000000000000000000000000000000000000000000000000000000000000000";
const expectedBootloaderHash = "0x010008e742608b21bf7eb23c1a9d0602047e3618b464c9b59c0fba3b3d7ab66e";
const expectedDefaultAccountHash = "0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32";
const expectedDefaultAccountHash = "0x01000567eb1d0eac3e32d1a5b5a0ececcbaf7a0b38b3fd7ce1eb8ff8296ef544";

const validatorOne = process.env.ETH_SENDER_SENDER_OPERATOR_COMMIT_ETH_ADDR!;

Expand Down
11 changes: 9 additions & 2 deletions system-contracts/SystemContractsHashes.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@
"contractName": "DefaultAccount",
"bytecodePath": "artifacts-zk/contracts-preprocessed/DefaultAccount.sol/DefaultAccount.json",
"sourceCodePath": "contracts-preprocessed/DefaultAccount.sol",
"bytecodeHash": "0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32",
"sourceCodeHash": "0xa42423712ddaa8f357d26e46825fda80a9a870d0ac7ff52c98884355f1173ec7"
"bytecodeHash": "0x01000567eb1d0eac3e32d1a5b5a0ececcbaf7a0b38b3fd7ce1eb8ff8296ef544",
"sourceCodeHash": "0x1a601a1c617c81daf95a03933b436987a03d6984ed6a49e71310dc706449e2fc"
},
{
"contractName": "EmptyContract",
Expand Down Expand Up @@ -97,6 +97,13 @@
"bytecodeHash": "0x010000e563d4ad7b4822cc19d8f74f2c41ee3d3153379be4b02b27d4498d52b6",
"sourceCodeHash": "0x91847512344ac5026e9fd396189c23ad9e253f22cb6e2fe65805c20c915797d4"
},
{
"contractName": "PasskeyBinder",
"bytecodePath": "artifacts-zk/contracts-preprocessed/PasskeyBinder.sol/PasskeyBinder.json",
"sourceCodePath": "contracts-preprocessed/PasskeyBinder.sol",
"bytecodeHash": "0x010001ddd2d9e5935a6fff10d41e305a9ff33340cdcf15536546332efa3e3c68",
"sourceCodeHash": "0xa331e26de173330a95f7f6eec7a2ad66379d783c996d12eea3d5d6bb9efce6a4"
},
{
"contractName": "PubdataChunkPublisher",
"bytecodePath": "artifacts-zk/contracts-preprocessed/PubdataChunkPublisher.sol/PubdataChunkPublisher.json",
Expand Down
5 changes: 4 additions & 1 deletion system-contracts/contracts/DefaultAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
pragma solidity 0.8.20;

import {IAccount, ACCOUNT_VALIDATION_SUCCESS_MAGIC} from "./interfaces/IAccount.sol";
import {IPasskeyBinder} from "./interfaces/IPasskeyBinder.sol";
import {TransactionHelper, Transaction} from "./libraries/TransactionHelper.sol";
import {SystemContractsCaller} from "./libraries/SystemContractsCaller.sol";
import {SystemContractHelper} from "./libraries/SystemContractHelper.sol";
import {EfficientCall} from "./libraries/EfficientCall.sol";
import {BOOTLOADER_FORMAL_ADDRESS, NONCE_HOLDER_SYSTEM_CONTRACT, DEPLOYER_SYSTEM_CONTRACT, INonceHolder} from "./Constants.sol";
import {BOOTLOADER_FORMAL_ADDRESS, NONCE_HOLDER_SYSTEM_CONTRACT, DEPLOYER_SYSTEM_CONTRACT, INonceHolder, SYSTEM_CONTRACTS_OFFSET} from "./Constants.sol";
import {Utils} from "./libraries/Utils.sol";

/**
Expand All @@ -21,6 +22,8 @@ import {Utils} from "./libraries/Utils.sol";
contract DefaultAccount is IAccount {
using TransactionHelper for *;

IPasskeyBinder public constant PASSKEY_BINDER = IPasskeyBinder(address(SYSTEM_CONTRACTS_OFFSET + 0xff));

/**
* @dev Simulate the behavior of the EOA if the caller is not the bootloader.
* Essentially, for all non-bootloader callers halt the execution with empty return data.
Expand Down
127 changes: 127 additions & 0 deletions system-contracts/contracts/PasskeyBinder.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

contract PasskeyBinder {
//curve prime field modulus
uint256 private constant p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF;
//short weierstrass second coefficient
uint256 private constant b = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B;
//short weierstrass first coefficient
uint256 private constant a = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC;

struct P256PublicKey {
uint256 x;
uint256 y;
}

mapping(bytes32 keyIdHash => P256PublicKey) private authorizedKeys;
mapping(bytes32 keyIdHash => address account) private keyIdHashToAccount;
mapping(address account => string[] keyIds) private accountToKeyIdList;

/// @dev Event emitted when a P256 key is added
event AddedP256Key(bytes32 indexed keyIdHash, string keyId, uint256 x, uint256 y);

/// @dev Event emitted when a P256 key is removed
event RemovedP256Key(bytes32 indexed keyIdHash, uint256 x, uint256 y);

/// @dev Error emitted when a P256 key is not on the curve
error KeyNotOnCurve(uint256 x, uint256 y);
/// @dev Error emitted when an empty key is attempted to be added
error InvalidEmptyKey();
/// @dev Error emitted when a P256 key is already stored and attempted to be added
error KeyAlreadyExists(string keyId);
/// @dev Error emitted when a P256 key is not stored and attempted to be removed
error KeyDoesNotExist(string keyId);
/// @dev Error emitted when a P256 key is not owned by the caller
error DoesNotOwner(string keyId);

function addKey(string calldata _keyId, uint256 _x, uint256 _y) external {
// slither-disable-next-line tx-origin
require(msg.sender == tx.origin, "Not authorized");
_addKey(_keyId, _x, _y);
}

function _addKey(string calldata _keyId, uint256 _x, uint256 _y) internal {
if (!isValidPublicKey(_x, _y)) revert KeyNotOnCurve(_x, _y);
bytes32 keyIdHash_ = keccak256(abi.encodePacked(_keyId));

if (bytes(_keyId).length == 0) revert InvalidEmptyKey();

P256PublicKey storage publicKey_ = authorizedKeys[keyIdHash_];

// update key
if (publicKey_.x != 0 || publicKey_.y != 0) {
revert KeyAlreadyExists(_keyId);
}

authorizedKeys[keyIdHash_] = P256PublicKey(_x, _y);
keyIdHashToAccount[keyIdHash_] = msg.sender;
accountToKeyIdList[msg.sender].push(_keyId);

emit AddedP256Key(keyIdHash_, _keyId, _x, _y);
}

function removeKey(string calldata _keyId) external {
bytes32 keyIdHash_ = keccak256(abi.encodePacked(_keyId));
if (keyIdHashToAccount[keyIdHash_] != msg.sender) revert DoesNotOwner(_keyId);
P256PublicKey memory publicKey_ = authorizedKeys[keyIdHash_];
uint256 x_ = publicKey_.x;
uint256 y_ = publicKey_.y;

if (x_ == 0 && y_ == 0) revert KeyDoesNotExist(_keyId);

delete authorizedKeys[keyIdHash_];
delete keyIdHashToAccount[keyIdHash_];
uint256 length = accountToKeyIdList[msg.sender].length;
for (uint256 i = 0; i < length; i++) {
if (keccak256(abi.encodePacked(accountToKeyIdList[msg.sender][i])) == keyIdHash_) {
accountToKeyIdList[msg.sender][i] = accountToKeyIdList[msg.sender][length - 1];
accountToKeyIdList[msg.sender].pop();
break;
}
}

emit RemovedP256Key(keyIdHash_, x_, y_);
}
/**
* @notice Returns the P256 public key coordinates of a given key ID if it is a signer
* @param keyIdHash The ID Hash of the key to get
* @return x_ The X value of the public key
* @return y_ The Y value of the public key
*/
function getKey(bytes32 keyIdHash) external view returns (uint256 x_, uint256 y_) {
P256PublicKey memory publicKey_ = authorizedKeys[keyIdHash];
x_ = publicKey_.x;
y_ = publicKey_.y;
}

function getKeyIdLength(address _account) external view returns (uint256) {
return accountToKeyIdList[_account].length;
}

function getKeyIdByIndex(address _account, uint256 _index) external view returns (string memory) {
return accountToKeyIdList[_account][_index];
}

function getAccountByKeyIdHash(bytes32 keyIdHash) external view returns (address) {
return keyIdHashToAccount[keyIdHash];
}

function getP256PublicKey(bytes32 keyIdHash) external view returns (P256PublicKey memory) {
return authorizedKeys[keyIdHash];
}

function isValidPublicKey(uint256 x, uint256 y) internal pure returns (bool) {
if (x >= p || y >= p || ((x == 0) && (y == 0))) {
return false;
}
unchecked {
uint256 LHS = mulmod(y, y, p); // y^2
uint256 RHS = addmod(mulmod(mulmod(x, x, p), x, p), mulmod(x, a, p), p); // x^3+ax
RHS = addmod(RHS, b, p); // x^3 + a*x + b

return LHS == RHS;
}
}
}
11 changes: 11 additions & 0 deletions system-contracts/contracts/interfaces/IPasskeyBinder.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

interface IPasskeyBinder {
/// @dev Returns the public key associated with the given keyIdHash.
/// @param keyIdHash The hash of the keyId.
/// @return x_ The x-coordinate of the public key.
/// @return y_ The y-coordinate of the public key.
function getKey(bytes32 keyIdHash) external view returns (uint256 x_, uint256 y_);
}
5 changes: 5 additions & 0 deletions system-contracts/scripts/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@ export const SYSTEM_CONTRACTS: ISystemContracts = {
codeName: "PubdataChunkPublisher",
lang: Language.Solidity,
},
passkeyBinder: {
address: "0x00000000000000000000000000000000000080ff",
codeName: "PasskeyBinder",
lang: Language.Solidity,
},
create2Factory: {
// This is explicitly a non-system-contract address.
// We do not use the same address as create2 factories on EVM, since
Expand Down

0 comments on commit 353833e

Please sign in to comment.