diff --git a/src/BLSApkRegistry.sol b/src/BLSApkRegistry.sol index 060de2d0..5bb14fba 100644 --- a/src/BLSApkRegistry.sol +++ b/src/BLSApkRegistry.sol @@ -97,10 +97,12 @@ contract BLSApkRegistry is BLSApkRegistryStorage { * @notice Called by the RegistryCoordinator register an operator as the owner of a BLS public key. * @param operator is the operator for whom the key is being registered * @param params contains the G1 & G2 public keys of the operator, and a signature proving their ownership + * @param pubkeyRegistrationMessageHash is a hash that the operator must sign to prove key ownership */ function registerBLSPublicKey( address operator, - PubkeyRegistrationParams calldata params + PubkeyRegistrationParams calldata params, + BN254.G1Point calldata pubkeyRegistrationMessageHash ) external onlyRegistryCoordinator returns (bytes32 operatorId) { bytes32 pubkeyHash = BN254.hashG1Point(params.pubkeyG1); require( @@ -115,9 +117,6 @@ contract BLSApkRegistry is BLSApkRegistryStorage { "BLSApkRegistry.registerBLSPublicKey: public key already registered" ); - // H(m) - BN254.G1Point memory messageHash = getMessageHash(operator); - // gamma = h(sigma, P, P', H(m)) uint256 gamma = uint256(keccak256(abi.encodePacked( params.pubkeyRegistrationSignature.X, @@ -126,15 +125,15 @@ contract BLSApkRegistry is BLSApkRegistryStorage { params.pubkeyG1.Y, params.pubkeyG2.X, params.pubkeyG2.Y, - messageHash.X, - messageHash.Y + pubkeyRegistrationMessageHash.X, + pubkeyRegistrationMessageHash.Y ))) % BN254.FR_MODULUS; // e(sigma + P * gamma, [-1]_2) = e(H(m) + [1]_1 * gamma, P') require(BN254.pairing( params.pubkeyRegistrationSignature.plus(params.pubkeyG1.scalar_mul(gamma)), BN254.negGeneratorG2(), - messageHash.plus(BN254.generatorG1().scalar_mul(gamma)), + pubkeyRegistrationMessageHash.plus(BN254.generatorG1().scalar_mul(gamma)), params.pubkeyG2 ), "BLSApkRegistry.registerBLSPublicKey: either the G1 signature is wrong, or G1 and G2 private key do not match"); @@ -215,19 +214,6 @@ contract BLSApkRegistry is BLSApkRegistryStorage { return (pubkey, pubkeyHash); } - /** - * @notice Returns the message hash that an operator must sign to register their BLS public key. - * @param operator is the address of the operator registering their BLS public key - */ - function getMessageHash(address operator) public view returns (BN254.G1Point memory) { - return BN254.hashToG1(keccak256(abi.encodePacked( - operator, - address(this), - block.chainid, - "EigenLayer_BN254_Pubkey_Registration" - ))); - } - /** * @notice Returns the indices of the quorumApks index at `blockNumber` for the provided `quorumNumbers` * @dev Returns the current indices if `blockNumber >= block.number` diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 0eef3632..c96e969b 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -35,6 +35,8 @@ contract RegistryCoordinator is EIP712, Initializable, IRegistryCoordinator, ISo /// @notice The EIP-712 typehash for the `DelegationApproval` struct used by the contract bytes32 public constant OPERATOR_CHURN_APPROVAL_TYPEHASH = keccak256("OperatorChurnApproval(bytes32 registeringOperatorId,OperatorKickParam[] operatorKickParams)OperatorKickParam(address operator,bytes32[] operatorIdsToSwap)"); + /// @notice The EIP-712 typehash used for registering BLS public keys + bytes32 public constant PUBKEY_REGISTRATION_TYPEHASH = keccak256("BN254PubkeyRegistration(address operator)"); /// @notice The maximum value of a quorum bitmap uint256 internal constant MAX_QUORUM_BITMAP = type(uint192).max; /// @notice The basis point denominator @@ -161,7 +163,7 @@ contract RegistryCoordinator is EIP712, Initializable, IRegistryCoordinator, ISo */ bytes32 operatorId = blsApkRegistry.getOperatorId(msg.sender); if (operatorId == 0) { - operatorId = blsApkRegistry.registerBLSPublicKey(msg.sender, params); + operatorId = blsApkRegistry.registerBLSPublicKey(msg.sender, params, pubkeyRegistrationMessageHash(msg.sender)); } // Register the operator in each of the registry contracts @@ -213,7 +215,7 @@ contract RegistryCoordinator is EIP712, Initializable, IRegistryCoordinator, ISo */ bytes32 operatorId = blsApkRegistry.getOperatorId(msg.sender); if (operatorId == 0) { - operatorId = blsApkRegistry.registerBLSPublicKey(msg.sender, params); + operatorId = blsApkRegistry.registerBLSPublicKey(msg.sender, params, pubkeyRegistrationMessageHash(msg.sender)); } // Verify the churn approver's signature for the registering operator and kick params @@ -760,4 +762,16 @@ contract RegistryCoordinator is EIP712, Initializable, IRegistryCoordinator, ISo // calculate the digest hash return _hashTypedDataV4(keccak256(abi.encode(OPERATOR_CHURN_APPROVAL_TYPEHASH, registeringOperatorId, operatorKickParams, salt, expiry))); } + + /** + * @notice Returns the message hash that an operator must sign to register their BLS public key. + * @param operator is the address of the operator registering their BLS public key + */ + function pubkeyRegistrationMessageHash(address operator) public view returns (BN254.G1Point memory) { + return BN254.hashToG1( + _hashTypedDataV4( + keccak256(abi.encode(PUBKEY_REGISTRATION_TYPEHASH, operator)) + ) + ); + } } diff --git a/src/interfaces/IBLSApkRegistry.sol b/src/interfaces/IBLSApkRegistry.sol index b35b45fe..48fc680f 100644 --- a/src/interfaces/IBLSApkRegistry.sol +++ b/src/interfaces/IBLSApkRegistry.sol @@ -99,10 +99,12 @@ interface IBLSApkRegistry is IRegistry { * @notice Called by the RegistryCoordinator register an operator as the owner of a BLS public key. * @param operator is the operator for whom the key is being registered * @param params contains the G1 & G2 public keys of the operator, and a signature proving their ownership + * @param pubkeyRegistrationMessageHash is a hash that the operator must sign to prove key ownership */ function registerBLSPublicKey( address operator, - PubkeyRegistrationParams calldata params + PubkeyRegistrationParams calldata params, + BN254.G1Point calldata pubkeyRegistrationMessageHash ) external returns (bytes32 operatorId); /** @@ -111,12 +113,6 @@ interface IBLSApkRegistry is IRegistry { */ function getRegisteredPubkey(address operator) external view returns (BN254.G1Point memory, bytes32); - /** - * @notice Returns the message hash that an operator must sign to register their BLS public key. - * @param operator is the address of the operator registering their BLS public key - */ - function getMessageHash(address operator) external view returns (BN254.G1Point memory); - /// @notice Returns the current APK for the provided `quorumNumber ` function getApk(uint8 quorumNumber) external view returns (BN254.G1Point memory); diff --git a/src/interfaces/IRegistryCoordinator.sol b/src/interfaces/IRegistryCoordinator.sol index ca6f8629..6d2c153d 100644 --- a/src/interfaces/IRegistryCoordinator.sol +++ b/src/interfaces/IRegistryCoordinator.sol @@ -4,6 +4,7 @@ pragma solidity =0.8.12; import {IBLSApkRegistry} from "src/interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry} from "src/interfaces/IStakeRegistry.sol"; import {IIndexRegistry} from "src/interfaces/IIndexRegistry.sol"; +import {BN254} from "src/libraries/BN254.sol"; /** * @title Interface for a contract that coordinates between various registries for an AVS. @@ -134,4 +135,10 @@ interface IRegistryCoordinator { /// @notice Returns the number of registries function numRegistries() external view returns (uint256); + + /** + * @notice Returns the message hash that an operator must sign to register their BLS public key. + * @param operator is the address of the operator registering their BLS public key + */ + function pubkeyRegistrationMessageHash(address operator) external view returns (BN254.G1Point memory); } \ No newline at end of file diff --git a/test/ffi/BLSPubKeyCompendiumFFI.t.sol b/test/ffi/BLSPubKeyCompendiumFFI.t.sol index 0910ab5d..3bb75118 100644 --- a/test/ffi/BLSPubKeyCompendiumFFI.t.sol +++ b/test/ffi/BLSPubKeyCompendiumFFI.t.sol @@ -30,7 +30,7 @@ contract BLSApkRegistryFFITests is G2Operations { pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(alice); vm.prank(address(registryCoordinator)); - blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams); + blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams, registryCoordinator.pubkeyRegistrationMessageHash(alice)); assertEq(blsApkRegistry.operatorToPubkeyHash(alice), BN254.hashG1Point(pubkeyRegistrationParams.pubkeyG1), "pubkey hash not stored correctly"); @@ -45,7 +45,7 @@ contract BLSApkRegistryFFITests is G2Operations { } function _signMessage(address signer) internal view returns(BN254.G1Point memory) { - BN254.G1Point memory messageHash = blsApkRegistry.getMessageHash(signer); + BN254.G1Point memory messageHash = registryCoordinator.pubkeyRegistrationMessageHash(signer); return BN254.scalar_mul(messageHash, privKey); } } diff --git a/test/mocks/RegistryCoordinatorMock.sol b/test/mocks/RegistryCoordinatorMock.sol index 87cbb436..fccf4d92 100644 --- a/test/mocks/RegistryCoordinatorMock.sol +++ b/test/mocks/RegistryCoordinatorMock.sol @@ -58,4 +58,10 @@ contract RegistryCoordinatorMock is IRegistryCoordinator { function registerOperator(bytes memory quorumNumbers, bytes calldata) external {} function deregisterOperator(bytes calldata quorumNumbers, bytes calldata) external {} + + function pubkeyRegistrationMessageHash(address operator) public view returns (BN254.G1Point memory) { + return BN254.hashToG1( + keccak256(abi.encode(operator)) + ); + } } diff --git a/test/unit/BLSApkRegistryUnit.t.sol b/test/unit/BLSApkRegistryUnit.t.sol index 683d59ff..0d8ed07a 100644 --- a/test/unit/BLSApkRegistryUnit.t.sol +++ b/test/unit/BLSApkRegistryUnit.t.sol @@ -292,8 +292,9 @@ contract BLSApkRegistryUnitTests is Test { // TODO: better organize / integrate tests migrated from `BLSPublicKeyCompendium` unit tests function testRegisterBLSPublicKey() public { pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(alice); + BN254.G1Point memory messageHash = registryCoordinator.pubkeyRegistrationMessageHash(alice); vm.prank(address(registryCoordinator)); - blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams); + blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams, messageHash); assertEq(blsApkRegistry.operatorToPubkeyHash(alice), BN254.hashG1Point(pubkeyRegistrationParams.pubkeyG1), "pubkey hash not stored correctly"); @@ -307,38 +308,42 @@ contract BLSApkRegistryUnitTests is Test { pubkeyRegistrationParams.pubkeyG1 = badPubkeyG1; + BN254.G1Point memory messageHash = registryCoordinator.pubkeyRegistrationMessageHash(alice); vm.prank(address(registryCoordinator)); vm.expectRevert(bytes("BLSApkRegistry.registerBLSPublicKey: either the G1 signature is wrong, or G1 and G2 private key do not match")); - blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams); + blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams, messageHash); } function testRegisterBLSPublicKey_BadSig_Reverts() public { pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(bob); // sign with wrong private key + BN254.G1Point memory messageHash = registryCoordinator.pubkeyRegistrationMessageHash(alice); vm.prank(address(registryCoordinator)); vm.expectRevert(bytes("BLSApkRegistry.registerBLSPublicKey: either the G1 signature is wrong, or G1 and G2 private key do not match")); - blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams); + blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams, messageHash); } function testRegisterBLSPublicKey_OpRegistered_Reverts() public { testRegisterBLSPublicKey(); // register alice + BN254.G1Point memory messageHash = registryCoordinator.pubkeyRegistrationMessageHash(alice); vm.prank(address(registryCoordinator)); vm.expectRevert(bytes("BLSApkRegistry.registerBLSPublicKey: operator already registered pubkey")); - blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams); + blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams, messageHash); } function testRegisterBLSPublicKey_PkRegistered_Reverts() public { testRegisterBLSPublicKey(); pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(bob); // same private key different operator + BN254.G1Point memory messageHash = registryCoordinator.pubkeyRegistrationMessageHash(bob); vm.prank(address(registryCoordinator)); vm.expectRevert(bytes("BLSApkRegistry.registerBLSPublicKey: public key already registered")); - blsApkRegistry.registerBLSPublicKey(bob, pubkeyRegistrationParams); + blsApkRegistry.registerBLSPublicKey(bob, pubkeyRegistrationParams, messageHash); } function _signMessage(address signer) internal view returns(BN254.G1Point memory) { - BN254.G1Point memory messageHash = blsApkRegistry.getMessageHash(signer); + BN254.G1Point memory messageHash = registryCoordinator.pubkeyRegistrationMessageHash(signer); return BN254.scalar_mul(messageHash, privKey); }