Skip to content

Commit

Permalink
feat: update PasskeyBinder
Browse files Browse the repository at this point in the history
  • Loading branch information
zkJoaquin committed Sep 26, 2024
1 parent e83e75e commit 4f3d90d
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 33 deletions.
5 changes: 2 additions & 3 deletions system-contracts/contracts/DefaultAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
77 changes: 50 additions & 27 deletions system-contracts/contracts/PasskeyBinder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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;
}
}

/**
Expand Down
6 changes: 3 additions & 3 deletions system-contracts/contracts/interfaces/IPasskeyBinder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 4f3d90d

Please sign in to comment.