From 26d66f1bc33b41c62c3b5a080211e50ae0200dbf Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Wed, 29 Jan 2025 12:16:09 -0300 Subject: [PATCH 01/13] Add OidcKeyRegistry contract --- src/OidcKeyRegistry.sol | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/OidcKeyRegistry.sol diff --git a/src/OidcKeyRegistry.sol b/src/OidcKeyRegistry.sol new file mode 100644 index 00000000..e8243520 --- /dev/null +++ b/src/OidcKeyRegistry.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; + +contract OidcKeyRegistry is UUPSUpgradeable, OwnableUpgradeable { + uint8 public constant MAX_KEYS = 5; + + // keccak256(iss) => keys + mapping(bytes32 => bytes32[MAX_KEYS]) public OIDCKeys; + // keccak256(iss) => index + mapping(bytes32 => uint8) public keyIndexes; + + function initialize(address owner) public initializer { + __Ownable_init(owner); + __UUPSUpgradeable_init(); + } + + function hashIssuer(string memory iss) public pure returns (bytes32) { + return keccak256(abi.encodePacked(iss)); + } + + function setKey(bytes32 iss, bytes32 key) public onlyOwner { + uint8 index = keyIndexes[iss]; + uint8 nextIndex = (index + 1) % MAX_KEYS; + OIDCKeys[iss][nextIndex] = key; + keyIndexes[iss] = nextIndex; + } + + function getLatestKey(bytes32 iss) public view returns (bytes32) { + return OIDCKeys[iss][keyIndexes[iss]]; + } + + function _authorizeUpgrade( + address newImplementation + ) internal override onlyOwner {} +} From 96dd4f785c85491e5ae8a7600d32359138e27d37 Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Wed, 29 Jan 2025 13:40:40 -0300 Subject: [PATCH 02/13] Add OidcKeyRegistry deploy script --- scripts/deploy.ts | 5 +++++ src/OidcKeyRegistry.sol | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/deploy.ts b/scripts/deploy.ts index 28c7b6de..eb472604 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -11,6 +11,7 @@ const ACCOUNT_IMPL_NAME = "SsoAccount"; const FACTORY_NAME = "AAFactory"; const PAYMASTER_NAME = "ExampleAuthServerPaymaster"; const BEACON_NAME = "SsoBeacon"; +const OIDC_KEY_REGISTRY_NAME = "OidcKeyRegistry"; async function deploy(name: string, deployer: Wallet, proxy: boolean, args?: any[], initArgs?: any): Promise { // eslint-disable-next-line @typescript-eslint/no-require-imports @@ -84,6 +85,7 @@ task("deploy", "Deploys ZKsync SSO contracts") const guardianInterface = new ethers.Interface((await hre.artifacts.readArtifact(GUARDIAN_RECOVERY_NAME)).abi); const recovery = await deploy(GUARDIAN_RECOVERY_NAME, deployer, !cmd.noProxy, [webauth], guardianInterface.encodeFunctionData("initialize", [webauth])); const paymaster = await deploy(PAYMASTER_NAME, deployer, false, [factory, sessions, recovery]); + await deploy(OIDC_KEY_REGISTRY_NAME, deployer, !cmd.noProxy); await fundPaymaster(paymaster, cmd.fund); } else { @@ -107,6 +109,9 @@ task("deploy", "Deploys ZKsync SSO contracts") } args = [cmd.factory, cmd.sessions]; } + if (cmd.only == OIDC_KEY_REGISTRY_NAME) { + args = []; + } const deployedContract = await deploy(cmd.only, deployer, false, args); if (cmd.only == PAYMASTER_NAME) { diff --git a/src/OidcKeyRegistry.sol b/src/OidcKeyRegistry.sol index e8243520..fea2c0ec 100644 --- a/src/OidcKeyRegistry.sol +++ b/src/OidcKeyRegistry.sol @@ -12,8 +12,8 @@ contract OidcKeyRegistry is UUPSUpgradeable, OwnableUpgradeable { // keccak256(iss) => index mapping(bytes32 => uint8) public keyIndexes; - function initialize(address owner) public initializer { - __Ownable_init(owner); + function initialize() public initializer { + __Ownable_init(); __UUPSUpgradeable_init(); } From 8de13151b68a8efac2ad4c33caba428a90b60d79 Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Thu, 30 Jan 2025 08:31:15 -0300 Subject: [PATCH 03/13] Add inititalize to OidcKeyRegistry deploy step --- scripts/deploy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/deploy.ts b/scripts/deploy.ts index eb472604..41695bbe 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -85,7 +85,8 @@ task("deploy", "Deploys ZKsync SSO contracts") const guardianInterface = new ethers.Interface((await hre.artifacts.readArtifact(GUARDIAN_RECOVERY_NAME)).abi); const recovery = await deploy(GUARDIAN_RECOVERY_NAME, deployer, !cmd.noProxy, [webauth], guardianInterface.encodeFunctionData("initialize", [webauth])); const paymaster = await deploy(PAYMASTER_NAME, deployer, false, [factory, sessions, recovery]); - await deploy(OIDC_KEY_REGISTRY_NAME, deployer, !cmd.noProxy); + const oidcKeyRegistryInterface = new ethers.Interface((await hre.artifacts.readArtifact(OIDC_KEY_REGISTRY_NAME)).abi); + await deploy(OIDC_KEY_REGISTRY_NAME, deployer, !cmd.noProxy, [], oidcKeyRegistryInterface.encodeFunctionData("initialize", [])); await fundPaymaster(paymaster, cmd.fund); } else { From 7c6ec52ecad766b45b2807ab38bde380d56e0049 Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Thu, 30 Jan 2025 08:34:29 -0300 Subject: [PATCH 04/13] Update variable names --- src/OidcKeyRegistry.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/OidcKeyRegistry.sol b/src/OidcKeyRegistry.sol index fea2c0ec..652f5884 100644 --- a/src/OidcKeyRegistry.sol +++ b/src/OidcKeyRegistry.sol @@ -21,15 +21,15 @@ contract OidcKeyRegistry is UUPSUpgradeable, OwnableUpgradeable { return keccak256(abi.encodePacked(iss)); } - function setKey(bytes32 iss, bytes32 key) public onlyOwner { - uint8 index = keyIndexes[iss]; + function setKey(bytes32 issHash, bytes32 key) public onlyOwner { + uint8 index = keyIndexes[issHash]; uint8 nextIndex = (index + 1) % MAX_KEYS; - OIDCKeys[iss][nextIndex] = key; - keyIndexes[iss] = nextIndex; + OIDCKeys[issHash][nextIndex] = key; + keyIndexes[issHash] = nextIndex; } - function getLatestKey(bytes32 iss) public view returns (bytes32) { - return OIDCKeys[iss][keyIndexes[iss]]; + function getLatestKey(bytes32 issHash) public view returns (bytes32) { + return OIDCKeys[issHash][keyIndexes[issHash]]; } function _authorizeUpgrade( From 0fc107acd4e6f188a2fda14f5e92c89ba009aabf Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Thu, 30 Jan 2025 09:37:47 -0300 Subject: [PATCH 05/13] Remove UUPSUpgradeable from contract --- src/OidcKeyRegistry.sol | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/OidcKeyRegistry.sol b/src/OidcKeyRegistry.sol index 652f5884..4afdcac8 100644 --- a/src/OidcKeyRegistry.sol +++ b/src/OidcKeyRegistry.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.24; -import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; -contract OidcKeyRegistry is UUPSUpgradeable, OwnableUpgradeable { +contract OidcKeyRegistry is Initializable, OwnableUpgradeable { uint8 public constant MAX_KEYS = 5; // keccak256(iss) => keys @@ -12,9 +12,12 @@ contract OidcKeyRegistry is UUPSUpgradeable, OwnableUpgradeable { // keccak256(iss) => index mapping(bytes32 => uint8) public keyIndexes; + constructor () { + initialize(); + } + function initialize() public initializer { __Ownable_init(); - __UUPSUpgradeable_init(); } function hashIssuer(string memory iss) public pure returns (bytes32) { @@ -31,8 +34,4 @@ contract OidcKeyRegistry is UUPSUpgradeable, OwnableUpgradeable { function getLatestKey(bytes32 issHash) public view returns (bytes32) { return OIDCKeys[issHash][keyIndexes[issHash]]; } - - function _authorizeUpgrade( - address newImplementation - ) internal override onlyOwner {} } From d153f1cc0781752572cc33c902d52acebe0e0f72 Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Thu, 30 Jan 2025 14:18:44 -0300 Subject: [PATCH 06/13] Add isValidKey --- src/OidcKeyRegistry.sol | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/OidcKeyRegistry.sol b/src/OidcKeyRegistry.sol index 4afdcac8..0a3eceab 100644 --- a/src/OidcKeyRegistry.sol +++ b/src/OidcKeyRegistry.sol @@ -34,4 +34,13 @@ contract OidcKeyRegistry is Initializable, OwnableUpgradeable { function getLatestKey(bytes32 issHash) public view returns (bytes32) { return OIDCKeys[issHash][keyIndexes[issHash]]; } + + function isValidKey(bytes32 issHash, bytes32 key) public view returns (bool) { + for (uint8 i = 0; i < MAX_KEYS; i++) { + if (OIDCKeys[issHash][i] == key) { + return true; + } + } + return false; + } } From 4a5172cda22d9e3779b634c21b497808f410fe62 Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Fri, 31 Jan 2025 07:57:10 -0300 Subject: [PATCH 07/13] Add setKeys --- src/OidcKeyRegistry.sol | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/OidcKeyRegistry.sol b/src/OidcKeyRegistry.sol index 0a3eceab..9658169b 100644 --- a/src/OidcKeyRegistry.sol +++ b/src/OidcKeyRegistry.sol @@ -31,6 +31,12 @@ contract OidcKeyRegistry is Initializable, OwnableUpgradeable { keyIndexes[issHash] = nextIndex; } + function setKeys(bytes32 issHash, bytes32[] memory keys) public onlyOwner { + for (uint8 i = 0; i < keys.length; i++) { + setKey(issHash, keys[i]); + } + } + function getLatestKey(bytes32 issHash) public view returns (bytes32) { return OIDCKeys[issHash][keyIndexes[issHash]]; } From 05e50afe06e9645d88d2907468856648c6911d2e Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Fri, 31 Jan 2025 09:49:08 -0300 Subject: [PATCH 08/13] Add Key struct --- src/OidcKeyRegistry.sol | 84 ++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/src/OidcKeyRegistry.sol b/src/OidcKeyRegistry.sol index 9658169b..72434e22 100644 --- a/src/OidcKeyRegistry.sol +++ b/src/OidcKeyRegistry.sol @@ -5,48 +5,62 @@ import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; contract OidcKeyRegistry is Initializable, OwnableUpgradeable { - uint8 public constant MAX_KEYS = 5; + uint8 public constant MAX_KEYS = 5; - // keccak256(iss) => keys - mapping(bytes32 => bytes32[MAX_KEYS]) public OIDCKeys; - // keccak256(iss) => index - mapping(bytes32 => uint8) public keyIndexes; + struct Key { + string n; // RSA modulus + string e; // RSA exponent + } - constructor () { - initialize(); - } + mapping(bytes32 => Key[MAX_KEYS]) public OIDCKeys; // Stores up to MAX_KEYS per issuer + mapping(bytes32 => uint8) public keyIndexes; // Tracks the latest key index for each issuer - function initialize() public initializer { - __Ownable_init(); - } + constructor() { + initialize(); + } - function hashIssuer(string memory iss) public pure returns (bytes32) { - return keccak256(abi.encodePacked(iss)); - } + function initialize() public initializer { + __Ownable_init(); + } - function setKey(bytes32 issHash, bytes32 key) public onlyOwner { - uint8 index = keyIndexes[issHash]; - uint8 nextIndex = (index + 1) % MAX_KEYS; - OIDCKeys[issHash][nextIndex] = key; - keyIndexes[issHash] = nextIndex; - } + function hashIssuer(string memory iss) public pure returns (bytes32) { + return keccak256(abi.encodePacked(iss)); + } - function setKeys(bytes32 issHash, bytes32[] memory keys) public onlyOwner { - for (uint8 i = 0; i < keys.length; i++) { - setKey(issHash, keys[i]); - } - } + function setKey(bytes32 issHash, Key memory key) public onlyOwner { + uint8 index = keyIndexes[issHash]; + uint8 nextIndex = (index + 1) % MAX_KEYS; // Circular buffer + OIDCKeys[issHash][nextIndex] = key; + keyIndexes[issHash] = nextIndex; + } - function getLatestKey(bytes32 issHash) public view returns (bytes32) { - return OIDCKeys[issHash][keyIndexes[issHash]]; + function setKeys(bytes32 issHash, Key[] memory keys) public onlyOwner { + for (uint8 i = 0; i < keys.length; i++) { + setKey(issHash, keys[i]); } + } - function isValidKey(bytes32 issHash, bytes32 key) public view returns (bool) { - for (uint8 i = 0; i < MAX_KEYS; i++) { - if (OIDCKeys[issHash][i] == key) { - return true; - } - } - return false; + function getLatestKey(bytes32 issHash) public view returns (Key memory) { + return OIDCKeys[issHash][keyIndexes[issHash]]; + } + + function isValidKey(bytes32 issHash, Key memory key) public view returns (bool) { + Key[MAX_KEYS] storage keys = OIDCKeys[issHash]; + + bytes32 keyNHash = keccak256(abi.encodePacked(key.n)); + bytes32 keyEHash = keccak256(abi.encodePacked(key.e)); + + for (uint8 i = 0; i < MAX_KEYS; i++) { + Key storage storedKey = keys[i]; + + if ( + keccak256(abi.encodePacked(storedKey.n)) == keyNHash && + keccak256(abi.encodePacked(storedKey.e)) == keyEHash + ) { + return true; + } } -} + + return false; + } +} \ No newline at end of file From 4159e30da8cb1f0c59a9d8eaa9767a8d472a915e Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Fri, 31 Jan 2025 09:57:06 -0300 Subject: [PATCH 09/13] Use bytes instead of string --- src/OidcKeyRegistry.sol | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/OidcKeyRegistry.sol b/src/OidcKeyRegistry.sol index 72434e22..97c366fe 100644 --- a/src/OidcKeyRegistry.sol +++ b/src/OidcKeyRegistry.sol @@ -8,8 +8,9 @@ contract OidcKeyRegistry is Initializable, OwnableUpgradeable { uint8 public constant MAX_KEYS = 5; struct Key { - string n; // RSA modulus - string e; // RSA exponent + bytes32 kid; // Key ID + bytes n; // RSA modulus + bytes e; // RSA exponent } mapping(bytes32 => Key[MAX_KEYS]) public OIDCKeys; // Stores up to MAX_KEYS per issuer @@ -47,16 +48,10 @@ contract OidcKeyRegistry is Initializable, OwnableUpgradeable { function isValidKey(bytes32 issHash, Key memory key) public view returns (bool) { Key[MAX_KEYS] storage keys = OIDCKeys[issHash]; - bytes32 keyNHash = keccak256(abi.encodePacked(key.n)); - bytes32 keyEHash = keccak256(abi.encodePacked(key.e)); - for (uint8 i = 0; i < MAX_KEYS; i++) { Key storage storedKey = keys[i]; - if ( - keccak256(abi.encodePacked(storedKey.n)) == keyNHash && - keccak256(abi.encodePacked(storedKey.e)) == keyEHash - ) { + if (storedKey.kid == key.kid) { return true; } } From a0d16b63c0148758cf1c4bbeb4a7e318fee961ef Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Fri, 31 Jan 2025 10:00:41 -0300 Subject: [PATCH 10/13] Add keccak(iss) comment --- src/OidcKeyRegistry.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OidcKeyRegistry.sol b/src/OidcKeyRegistry.sol index 97c366fe..4efb61f9 100644 --- a/src/OidcKeyRegistry.sol +++ b/src/OidcKeyRegistry.sol @@ -13,6 +13,7 @@ contract OidcKeyRegistry is Initializable, OwnableUpgradeable { bytes e; // RSA exponent } + // Mapping uses keccak256(iss) as the key mapping(bytes32 => Key[MAX_KEYS]) public OIDCKeys; // Stores up to MAX_KEYS per issuer mapping(bytes32 => uint8) public keyIndexes; // Tracks the latest key index for each issuer From de98ef6514ff4494530baa299727e014c2ea11e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Ignacio=20Gonz=C3=A1lez?= Date: Fri, 31 Jan 2025 10:01:23 -0300 Subject: [PATCH 11/13] Update src/OidcKeyRegistry.sol --- src/OidcKeyRegistry.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OidcKeyRegistry.sol b/src/OidcKeyRegistry.sol index 4efb61f9..90f275eb 100644 --- a/src/OidcKeyRegistry.sol +++ b/src/OidcKeyRegistry.sol @@ -59,4 +59,4 @@ contract OidcKeyRegistry is Initializable, OwnableUpgradeable { return false; } -} \ No newline at end of file +} From dc3ff5f0bb2ada716814782b4c3287c2f19b30f4 Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Fri, 31 Jan 2025 10:44:45 -0300 Subject: [PATCH 12/13] Add getKey --- src/OidcKeyRegistry.sol | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/OidcKeyRegistry.sol b/src/OidcKeyRegistry.sol index 90f275eb..ad0ec64b 100644 --- a/src/OidcKeyRegistry.sol +++ b/src/OidcKeyRegistry.sol @@ -42,21 +42,13 @@ contract OidcKeyRegistry is Initializable, OwnableUpgradeable { } } - function getLatestKey(bytes32 issHash) public view returns (Key memory) { - return OIDCKeys[issHash][keyIndexes[issHash]]; - } - - function isValidKey(bytes32 issHash, Key memory key) public view returns (bool) { + function getKey(bytes32 issHash, bytes32 kid) public view returns (Key memory) { Key[MAX_KEYS] storage keys = OIDCKeys[issHash]; - for (uint8 i = 0; i < MAX_KEYS; i++) { - Key storage storedKey = keys[i]; - - if (storedKey.kid == key.kid) { - return true; + if (keys[i].kid == kid) { + return keys[i]; } } - - return false; + revert("Key not found"); } } From f98af4acd47a4ce3b5208f0bff641a8ac21c4bd4 Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Fri, 31 Jan 2025 11:05:50 -0300 Subject: [PATCH 13/13] Add require kid != 0 --- src/OidcKeyRegistry.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OidcKeyRegistry.sol b/src/OidcKeyRegistry.sol index ad0ec64b..ca1eca99 100644 --- a/src/OidcKeyRegistry.sol +++ b/src/OidcKeyRegistry.sol @@ -43,6 +43,7 @@ contract OidcKeyRegistry is Initializable, OwnableUpgradeable { } function getKey(bytes32 issHash, bytes32 kid) public view returns (Key memory) { + require(kid != 0, "Invalid kid"); Key[MAX_KEYS] storage keys = OIDCKeys[issHash]; for (uint8 i = 0; i < MAX_KEYS; i++) { if (keys[i].kid == kid) {