diff --git a/system-contracts/contracts/DefaultAccount.sol b/system-contracts/contracts/DefaultAccount.sol index f1a9a7645..ecbad1175 100644 --- a/system-contracts/contracts/DefaultAccount.sol +++ b/system-contracts/contracts/DefaultAccount.sol @@ -167,10 +167,9 @@ contract DefaultAccount is IAccount { uint32(gasleft()), address(PASSKEY_BINDER), 0, - abi.encodeCall(IPasskeyBinder.getAuthorizedKey, (_credentialIdHash)) + abi.encodeCall(IPasskeyBinder.getAuthorizedKey, (address(this), _credentialIdHash)) ); - (address passkeyOwner, uint256 x, uint256 y) = abi.decode(returnData, (address, uint256, uint256)); - require(passkeyOwner == address(this), "Passkey is not owned by the account"); + (uint256 x, uint256 y) = abi.decode(returnData, (uint256, uint256)); require(x != 0 && y != 0, "Passkey is not set"); return (x, y); } diff --git a/system-contracts/contracts/PasskeyBinder.sol b/system-contracts/contracts/PasskeyBinder.sol index 17e3b3079..cf1aad1d5 100644 --- a/system-contracts/contracts/PasskeyBinder.sol +++ b/system-contracts/contracts/PasskeyBinder.sol @@ -20,26 +20,26 @@ contract PasskeyBinder is IPasskeyBinder { uint256 y; } + // Deprecated struct AuthorizedKey { address owner; P256PublicKey publicKey; } mapping(address account => EnumerableSet.Bytes32Set credentialIdHashSet) private accountToCredentialIdHashSet; - mapping(bytes32 credentialIdHash => AuthorizedKey) private authorizedKeys; + mapping(bytes32 credentialIdHash => AuthorizedKey) private authorizedKeys; // Deprecated + mapping(bytes32 credentialIdHash => P256PublicKey) private authorizedPublicKeys; /// @dev Event emitted when a P256 key is added event AddedP256PublicKey(bytes32 indexed credentialIdHash, address indexed owner, uint256 x, uint256 y); - /// @dev Event emitted when a P256 key is removed - event RemovedP256PublicKey(bytes32 indexed credentialIdHash, address indexed owner, uint256 x, uint256 y); - + event RemovedP256PublicKey(bytes32 indexed credentialIdHash, address indexed owner); + /// @dev Event emitted when a P256 key is deprecated + event DeprecatedP256PublicKey(bytes32 indexed credentialIdHash); /// @dev Error emitted when a P256 key is not on the curve error KeyNotOnCurve(uint256 x, uint256 y); /// @dev Error emitted when an empty credential id hash is attempted to be added error InvalidCredentialIdHash(); - /// @dev Error emitted when a P256 key is already stored and attempted to be added - error KeyAlreadyExists(bytes32 credentialIdHash); /// @dev Error emitted when a P256 key is not stored and attempted to be removed error KeyDoesNotExist(bytes32 credentialIdHash); /// @dev Error emitted when a P256 key is not owned by the caller @@ -48,7 +48,7 @@ contract PasskeyBinder is IPasskeyBinder { error DoesNotEOA(); /** - * @notice Adds a P256 public key to the contract + * @notice Adding a P256 public key to the caller * @param _credentialIdHash The ID Hash of the credential to add * @param _x The X value of the public key * @param _y The Y value of the public key @@ -65,50 +65,73 @@ contract PasskeyBinder is IPasskeyBinder { if (_credentialIdHash == bytes32(0)) revert InvalidCredentialIdHash(); - AuthorizedKey storage authorizedKey = authorizedKeys[_credentialIdHash]; - - if (authorizedKey.owner != address(0)) revert KeyAlreadyExists(_credentialIdHash); + P256PublicKey memory publicKey = authorizedPublicKeys[_credentialIdHash]; + if (publicKey.x == 0 && publicKey.y == 0) { + authorizedPublicKeys[_credentialIdHash] = P256PublicKey({x: _x, y: _y}); + } - authorizedKeys[_credentialIdHash] = AuthorizedKey({owner: sender, publicKey: P256PublicKey({x: _x, y: _y})}); accountToCredentialIdHashSet[sender].add(_credentialIdHash); emit AddedP256PublicKey(_credentialIdHash, sender, _x, _y); } /** - * @notice Removes a P256 public key from the contract + * @notice Removes P256 public key for caller * @param _credentialIdHash The ID Hash of the credential to remove */ function removeP256PublicKey(bytes32 _credentialIdHash) external { address sender = msg.sender; - AuthorizedKey memory authorizedKey = authorizedKeys[_credentialIdHash]; - address publicKeyOwner = authorizedKey.owner; + EnumerableSet.Bytes32Set storage credentialIdHashSet = accountToCredentialIdHashSet[sender]; + + bool isOwner = credentialIdHashSet.contains(_credentialIdHash); + if (!isOwner) revert DoesNotOwner(_credentialIdHash); + + accountToCredentialIdHashSet[sender].remove(_credentialIdHash); - if (publicKeyOwner == address(0)) revert KeyDoesNotExist(_credentialIdHash); - if (publicKeyOwner != sender) revert DoesNotOwner(_credentialIdHash); + emit RemovedP256PublicKey(_credentialIdHash, sender); + } - uint256 x = authorizedKey.publicKey.x; - uint256 y = authorizedKey.publicKey.y; + /** + * @notice Deprecate owner-specified P256 public key + * @param _credentialIdHash The ID Hash of the credential to deprecate + */ + function deprecateP256PublicKey(bytes32 _credentialIdHash) external { + address sender = msg.sender; + EnumerableSet.Bytes32Set storage credentialIdHashSet = accountToCredentialIdHashSet[sender]; - delete authorizedKeys[_credentialIdHash]; + bool isOwner = credentialIdHashSet.contains(_credentialIdHash); + if (!isOwner) revert DoesNotOwner(_credentialIdHash); + P256PublicKey memory publicKey = authorizedPublicKeys[_credentialIdHash]; + if (publicKey.x == 0 && publicKey.y == 0) revert KeyDoesNotExist(_credentialIdHash); + + delete authorizedPublicKeys[_credentialIdHash]; accountToCredentialIdHashSet[sender].remove(_credentialIdHash); - emit RemovedP256PublicKey(_credentialIdHash, sender, x, y); + emit DeprecatedP256PublicKey(_credentialIdHash); } /** * @notice Returns authorized key infos by credential id hash + * @param _account The account to get the authorized key * @param _credentialIdHash The ID Hash of the credential to get - * @return owner The owner of the public key * @return x The X value of the public key * @return y The Y value of the public key */ - function getAuthorizedKey(bytes32 _credentialIdHash) external view returns (address owner, uint256 x, uint256 y) { - AuthorizedKey memory authorizedKey = authorizedKeys[_credentialIdHash]; - - owner = authorizedKey.owner; - x = authorizedKey.publicKey.x; - y = authorizedKey.publicKey.y; + function getAuthorizedKey( + address _account, + bytes32 _credentialIdHash + ) external view returns (uint256 x, uint256 y) { + EnumerableSet.Bytes32Set storage credentialIdHashSet = accountToCredentialIdHashSet[_account]; + P256PublicKey memory publicKey = authorizedPublicKeys[_credentialIdHash]; + bool isOwner = credentialIdHashSet.contains(_credentialIdHash); + + if (isOwner) { + x = publicKey.x; + y = publicKey.y; + } else { + x = 0; + y = 0; + } } /** diff --git a/system-contracts/contracts/interfaces/IPasskeyBinder.sol b/system-contracts/contracts/interfaces/IPasskeyBinder.sol index 5b1ffab81..756839c79 100644 --- a/system-contracts/contracts/interfaces/IPasskeyBinder.sol +++ b/system-contracts/contracts/interfaces/IPasskeyBinder.sol @@ -5,12 +5,12 @@ pragma solidity 0.8.20; interface IPasskeyBinder { /** * @notice Returns authorized key infos by credential id hash - * @param credentialIdHash The ID Hash of the credential to get - * @return owner The owner of the public key + * @param _account The account to get the authorized key + * @param _credentialIdHash The ID Hash of the credential to get * @return x The X value of the public key * @return y The Y value of the public key */ - function getAuthorizedKey(bytes32 credentialIdHash) external view returns (address owner, uint256 x, uint256 y); + function getAuthorizedKey(address _account, bytes32 _credentialIdHash) external view returns (uint256 x, uint256 y); /** * @notice Returns the number of credential id hash set length