Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 63 additions & 1 deletion src/BLSApkRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {BLSApkRegistryStorage, IBLSApkRegistry} from "./BLSApkRegistryStorage.so
import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol";

import {BN254} from "./libraries/BN254.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

contract BLSApkRegistry is BLSApkRegistryStorage {
using BN254 for BN254.G1Point;
Expand All @@ -16,6 +17,12 @@ contract BLSApkRegistry is BLSApkRegistryStorage {
_;
}

/// @notice when applied to a function, only allows the RegistryCoordinator owner to call it
modifier onlyRegistryCoordinatorOwner() {
_checkRegistryCoordinatorOwner();
_;
}

/// @notice Sets the (immutable) `registryCoordinator` address
constructor(
ISlashingRegistryCoordinator _slashingRegistryCoordinator
Expand Down Expand Up @@ -109,13 +116,42 @@ contract BLSApkRegistry is BLSApkRegistryStorage {
);

operatorToPubkey[operator] = params.pubkeyG1;
operatorToPubkeyG2[operator] = params.pubkeyG2;
operatorToPubkeyHash[operator] = pubkeyHash;
pubkeyHashToOperator[pubkeyHash] = operator;

emit NewPubkeyRegistration(operator, params.pubkeyG1, params.pubkeyG2);
return pubkeyHash;
}

/// @notice Verifies and registers a G2 public key for an operator that already has a G1 key
/// @dev This is meant to be used as a one-time way to add G2 public keys for operators that have G1 keys but no G2 key on chain
/// @param operator The address of the operator to register the G2 key for
/// @param pubkeyG2 The G2 public key to register
function verifyAndRegisterG2PubkeyForOperator(
address operator,
BN254.G2Point calldata pubkeyG2
) external onlyRegistryCoordinatorOwner {
// Get the operator's G1 pubkey. Reverts if they have not registered a key
(BN254.G1Point memory pubkeyG1,) = getRegisteredPubkey(operator);

_checkG2PubkeyNotSet(operator);

require(
BN254.pairing(
pubkeyG1,
BN254.negGeneratorG2(),
BN254.generatorG1(),
pubkeyG2
),
InvalidBLSSignatureOrPrivateKey()
);

operatorToPubkeyG2[operator] = pubkeyG2;

emit NewG2PubkeyRegistration(operator, pubkeyG2);
}

/**
*
* INTERNAL FUNCTIONS
Expand Down Expand Up @@ -192,7 +228,7 @@ contract BLSApkRegistry is BLSApkRegistryStorage {
revert BlockNumberBeforeFirstUpdate();
}

// Loop backward through apkHistory until we find an entry that preceeds `blockNumber`
// Loop backward through apkHistory until we find an entry that precedes `blockNumber`
for (uint256 j = quorumApkUpdatesLength; j > 0; j--) {
if (apkHistory[quorumNumber][j - 1].updateBlockNumber <= blockNumber) {
indices[i] = uint32(j - 1);
Expand Down Expand Up @@ -262,7 +298,33 @@ contract BLSApkRegistry is BLSApkRegistryStorage {
return operatorToPubkeyHash[operator];
}

/// @inheritdoc IBLSApkRegistry
function getOperatorPubkeyG2(
address operator
) public view override returns (BN254.G2Point memory) {
return operatorToPubkeyG2[operator];
}

function _checkRegistryCoordinator() internal view {
require(msg.sender == address(registryCoordinator), OnlyRegistryCoordinatorOwner());
}

function _checkRegistryCoordinatorOwner() internal view {
require(
msg.sender == Ownable(address(registryCoordinator)).owner(),
OnlyRegistryCoordinatorOwner()
);
}

/// @notice Checks if a G2 pubkey is already set for an operator
function _checkG2PubkeyNotSet(address operator) internal view {
BN254.G2Point memory existingG2Pubkey = getOperatorPubkeyG2(operator);
require(
existingG2Pubkey.X[0] == 0 &&
existingG2Pubkey.X[1] == 0 &&
existingG2Pubkey.Y[0] == 0 &&
existingG2Pubkey.Y[1] == 0,
G2PubkeyAlreadySet()
);
}
}
6 changes: 3 additions & 3 deletions src/BLSApkRegistryStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ abstract contract BLSApkRegistryStorage is Initializable, IBLSApkRegistry {
/// @inheritdoc IBLSApkRegistry
mapping(address operator => BN254.G1Point pubkeyG1) public operatorToPubkey;

/// AGGREGATE PUBLIC KEY STORAGE

/// @inheritdoc IBLSApkRegistry
mapping(uint8 quorumNumber => IBLSApkRegistryTypes.ApkUpdate[]) public apkHistory;
/// @inheritdoc IBLSApkRegistry
mapping(uint8 quorumNumber => BN254.G1Point) public currentApk;

mapping(address operator => BN254.G2Point) internal operatorToPubkeyG2;

constructor(
ISlashingRegistryCoordinator _slashingRegistryCoordinator
) {
Expand All @@ -40,5 +40,5 @@ abstract contract BLSApkRegistryStorage is Initializable, IBLSApkRegistry {
_disableInitializers();
}

uint256[45] private __GAP;
uint256[44] private __GAP;
}
15 changes: 15 additions & 0 deletions src/interfaces/IBLSApkRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ interface IBLSApkRegistryErrors {
error BlockNumberNotLatest();
/// @notice Thrown when the block number is before the first update.
error BlockNumberBeforeFirstUpdate();
/// @notice Thrown when a G2 pubkey has already been set for an operator
error G2PubkeyAlreadySet();
}

interface IBLSApkRegistryTypes {
Expand All @@ -50,6 +52,7 @@ interface IBLSApkRegistryTypes {
BN254.G1Point pubkeyG1;
BN254.G2Point pubkeyG2;
}

}

interface IBLSApkRegistryEvents is IBLSApkRegistryTypes {
Expand Down Expand Up @@ -78,6 +81,9 @@ interface IBLSApkRegistryEvents is IBLSApkRegistryTypes {
* @param quorumNumbers The quorum numbers the operator is being deregistered from.
*/
event OperatorRemovedFromQuorums(address operator, bytes32 operatorId, bytes quorumNumbers);

/// @notice Emitted when a G2 public key is registered for an operator
event NewG2PubkeyRegistration(address indexed operator, BN254.G2Point pubkeyG2);
}

interface IBLSApkRegistry is IBLSApkRegistryErrors, IBLSApkRegistryEvents {
Expand Down Expand Up @@ -118,6 +124,15 @@ interface IBLSApkRegistry is IBLSApkRegistryErrors, IBLSApkRegistryEvents {
address operator
) external view returns (uint256, uint256);

/*
* @notice Maps `operator` to their BLS public key in G2.
* @param operator The address of the operator.
* @return The operator's BLS public key in G2.
*/
function getOperatorPubkeyG2(
address operator
) external view returns (BN254.G2Point memory);

/*
* @notice Stores the history of aggregate public key updates for `quorumNumber` at `index`.
* @dev Returns a non-encoded IBLSApkRegistryTypes.ApkUpdate.
Expand Down
Loading