Skip to content

Commit

Permalink
feat: create struct for pubkey registration params
Browse files Browse the repository at this point in the history
note: code is currently not compiling due to a stack-too-deep error
error here:
 src/RegistryCoordinator.sol:254:69:
    |
254 |                 _deregisterOperator(operatorKickParams[i].operator, quorumNumbers[i:i+1]);
  • Loading branch information
ChaoticWalrus committed Dec 12, 2023
1 parent 5a022ae commit 11c51e1
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 144 deletions.
30 changes: 13 additions & 17 deletions src/BLSApkRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -96,17 +96,13 @@ 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 signedMessageHash is the registration message hash signed by the private key of the operator
* @param pubkeyG1 is the corresponding G1 public key of the operator
* @param pubkeyG2 is the corresponding G2 public key of the operator
* @param pubkeyRegistrationParams contains the G1 & G2 public keys of the operator, and a signature proving their ownership
*/
function registerBLSPublicKey(
address operator,
BN254.G1Point memory signedMessageHash,
BN254.G1Point memory pubkeyG1,
BN254.G2Point memory pubkeyG2
PubkeyRegistrationParams calldata pubkeyRegistrationParams
) external onlyRegistryCoordinator {
bytes32 pubkeyHash = BN254.hashG1Point(pubkeyG1);
bytes32 pubkeyHash = BN254.hashG1Point(pubkeyRegistrationParams.pubkeyG1);
require(
pubkeyHash != ZERO_PK_HASH, "BLSApkRegistry.registerBLSPublicKey: cannot register zero pubkey"
);
Expand All @@ -124,29 +120,29 @@ contract BLSApkRegistry is BLSApkRegistryStorage {

// gamma = h(sigma, P, P', H(m))
uint256 gamma = uint256(keccak256(abi.encodePacked(
signedMessageHash.X,
signedMessageHash.Y,
pubkeyG1.X,
pubkeyG1.Y,
pubkeyG2.X,
pubkeyG2.Y,
pubkeyRegistrationParams.pubkeyRegistrationSignature.X,
pubkeyRegistrationParams.pubkeyRegistrationSignature.Y,
pubkeyRegistrationParams.pubkeyG1.X,
pubkeyRegistrationParams.pubkeyG1.Y,
pubkeyRegistrationParams.pubkeyG2.X,
pubkeyRegistrationParams.pubkeyG2.Y,
messageHash.X,
messageHash.Y
))) % BN254.FR_MODULUS;

// e(sigma + P * gamma, [-1]_2) = e(H(m) + [1]_1 * gamma, P')
require(BN254.pairing(
signedMessageHash.plus(pubkeyG1.scalar_mul(gamma)),
pubkeyRegistrationParams.pubkeyRegistrationSignature.plus(pubkeyRegistrationParams.pubkeyG1.scalar_mul(gamma)),
BN254.negGeneratorG2(),
messageHash.plus(BN254.generatorG1().scalar_mul(gamma)),
pubkeyG2
pubkeyRegistrationParams.pubkeyG2
), "BLSApkRegistry.registerBLSPublicKey: either the G1 signature is wrong, or G1 and G2 private key do not match");

operatorToPubkey[operator] = pubkeyG1;
operatorToPubkey[operator] = pubkeyRegistrationParams.pubkeyG1;
operatorToPubkeyHash[operator] = pubkeyHash;
pubkeyHashToOperator[pubkeyHash] = operator;

emit NewPubkeyRegistration(operator, pubkeyG1, pubkeyG2);
emit NewPubkeyRegistration(operator, pubkeyRegistrationParams.pubkeyG1, pubkeyRegistrationParams.pubkeyG2);
}

/*******************************************************************************
Expand Down
20 changes: 15 additions & 5 deletions src/RegistryCoordinator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -147,20 +147,20 @@ contract RegistryCoordinator is EIP712, Initializable, IRegistryCoordinator, ISo
* @notice Registers msg.sender as an operator for one or more quorums. If any quorum reaches its maximum
* operator capacity, this method will fail.
* @param quorumNumbers is an ordered byte array containing the quorum numbers being registered for
* @param pubkeyRegistrationParams contains the G1 & G2 public keys of the operator, and a signature proving their ownership
* @dev the `pubkeyRegistrationParams` input param is ignored if the caller has previously registered a public key
*/
function registerOperator(
bytes calldata quorumNumbers,
string calldata socket,
BN254.G1Point memory pubkeyRegistrationSignature,
BN254.G1Point memory pubkeyG1,
BN254.G2Point memory pubkeyG2
IBLSApkRegistry.PubkeyRegistrationParams calldata pubkeyRegistrationParams
) external onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) {
/**
* IF the operator has never registered a pubkey before, THEN register their pubkey
* OTHERWISE, simply ignore the `pubkeyRegistrationSignature`, `pubkeyG1`, and `pubkeyG2` inputs
* OTHERWISE, simply ignore the provided `pubkeyRegistrationParams`
*/
if (blsApkRegistry.operatorToPubkeyHash(msg.sender) == 0) {
blsApkRegistry.registerBLSPublicKey(msg.sender, pubkeyRegistrationSignature, pubkeyG1, pubkeyG2);
blsApkRegistry.registerBLSPublicKey(msg.sender, pubkeyRegistrationParams);
}
bytes32 operatorId = blsApkRegistry.getOperatorId(msg.sender);

Expand Down Expand Up @@ -192,18 +192,28 @@ contract RegistryCoordinator is EIP712, Initializable, IRegistryCoordinator, ISo
* @notice Registers msg.sender as an operator for one or more quorums. If any quorum reaches its maximum operator
* capacity, `operatorKickParams` is used to replace an old operator with the new one.
* @param quorumNumbers is an ordered byte array containing the quorum numbers being registered for
* @param pubkeyRegistrationParams contains the G1 & G2 public keys of the operator, and a signature proving their ownership
* @param operatorKickParams are used to determine which operator is removed to maintain quorum capacity as the
* operator registers for quorums.
* @param churnApproverSignature is the signature of the churnApprover on the operator kick params
* @dev the `pubkeyRegistrationParams` input param is ignored if the caller has previously registered a public key
*/
function registerOperatorWithChurn(
bytes calldata quorumNumbers,
string calldata socket,
IBLSApkRegistry.PubkeyRegistrationParams calldata pubkeyRegistrationParams,
OperatorKickParam[] calldata operatorKickParams,
SignatureWithSaltAndExpiry memory churnApproverSignature
) external onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) {
require(operatorKickParams.length == quorumNumbers.length, "RegistryCoordinator.registerOperatorWithChurn: input length mismatch");

/**
* IF the operator has never registered a pubkey before, THEN register their pubkey
* OTHERWISE, simply ignore the `pubkeyRegistrationSignature`, `pubkeyG1`, and `pubkeyG2` inputs
*/
if (blsApkRegistry.operatorToPubkeyHash(msg.sender) == 0) {
blsApkRegistry.registerBLSPublicKey(msg.sender, pubkeyRegistrationParams);
}
bytes32 operatorId = blsApkRegistry.getOperatorId(msg.sender);

// Verify the churn approver's signature for the registering operator and kick params
Expand Down
41 changes: 25 additions & 16 deletions src/interfaces/IBLSApkRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,29 @@ import {BN254} from "src/libraries/BN254.sol";
* @author Layr Labs, Inc.
*/
interface IBLSApkRegistry is IRegistry {
// STRUCTS
/// @notice Data structure used to track the history of the Aggregate Public Key of all operators
struct ApkUpdate {
// first 24 bytes of keccak256(apk_x0, apk_x1, apk_y0, apk_y1)
bytes24 apkHash;
// block number at which the update occurred
uint32 updateBlockNumber;
// block number at which the next update occurred
uint32 nextUpdateBlockNumber;
}

/**
* @notice Struct used when registering a new public key
* @param signedMessageHash is the registration message hash signed by the private key of the operator
* @param pubkeyG1 is the corresponding G1 public key of the operator
* @param pubkeyG2 is the corresponding G2 public key of the operator
*/
struct PubkeyRegistrationParams {
BN254.G1Point pubkeyRegistrationSignature;
BN254.G1Point pubkeyG1;
BN254.G2Point pubkeyG2;
}

// EVENTS
/// @notice Emitted when `operator` registers with the public keys `pubkeyG1` and `pubkeyG2`.
event NewPubkeyRegistration(address indexed operator, BN254.G1Point pubkeyG1, BN254.G2Point pubkeyG2);
Expand All @@ -26,16 +49,6 @@ interface IBLSApkRegistry is IRegistry {
bytes quorumNumbers
);

/// @notice Data structure used to track the history of the Aggregate Public Key of all operators
struct ApkUpdate {
// first 24 bytes of keccak256(apk_x0, apk_x1, apk_y0, apk_y1)
bytes24 apkHash;
// block number at which the update occurred
uint32 updateBlockNumber;
// block number at which the next update occurred
uint32 nextUpdateBlockNumber;
}

/**
* @notice Registers the `operator`'s pubkey for the specified `quorumNumbers`.
* @param operator The address of the operator to register.
Expand Down Expand Up @@ -85,15 +98,11 @@ 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 signedMessageHash is the registration message hash signed by the private key of the operator
* @param pubkeyG1 is the corresponding G1 public key of the operator
* @param pubkeyG2 is the corresponding G2 public key of the operator
* @param pubkeyRegistrationParams contains the G1 & G2 public keys of the operator, and a signature proving their ownership
*/
function registerBLSPublicKey(
address operator,
BN254.G1Point memory signedMessageHash,
BN254.G1Point memory pubkeyG1,
BN254.G2Point memory pubkeyG2
PubkeyRegistrationParams calldata pubkeyRegistrationParams
) external;

/**
Expand Down
19 changes: 10 additions & 9 deletions test/ffi/BLSPubKeyCompendiumFFI.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity =0.8.12;

import "src/BLSApkRegistry.sol";
import "test/ffi/util/G2Operations.sol";
import {IBLSApkRegistry} from "src/interfaces/IBLSApkRegistry.sol";

contract BLSApkRegistryFFITests is G2Operations {
using BN254 for BN254.G1Point;
Expand All @@ -14,9 +15,7 @@ contract BLSApkRegistryFFITests is G2Operations {
IRegistryCoordinator registryCoordinator;

uint256 privKey;
BN254.G1Point pubKeyG1;
BN254.G2Point pubKeyG2;
BN254.G1Point signedMessageHash;
IBLSApkRegistry.PubkeyRegistrationParams pubkeyRegistrationParams;

address alice = address(0x69);

Expand All @@ -28,19 +27,21 @@ contract BLSApkRegistryFFITests is G2Operations {
cheats.assume(_privKey != 0);
_setKeys(_privKey);

signedMessageHash = _signMessage(alice);
pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(alice);

vm.prank(address(registryCoordinator));
blsApkRegistry.registerBLSPublicKey(alice, signedMessageHash, pubKeyG1, pubKeyG2);
blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams);

assertEq(blsApkRegistry.operatorToPubkeyHash(alice), BN254.hashG1Point(pubKeyG1), "pubkey hash not stored correctly");
assertEq(blsApkRegistry.pubkeyHashToOperator(BN254.hashG1Point(pubKeyG1)), alice, "operator address not stored correctly");
assertEq(blsApkRegistry.operatorToPubkeyHash(alice), BN254.hashG1Point(pubkeyRegistrationParams.pubkeyG1),
"pubkey hash not stored correctly");
assertEq(blsApkRegistry.pubkeyHashToOperator(BN254.hashG1Point(pubkeyRegistrationParams.pubkeyG1)), alice,
"operator address not stored correctly");
}

function _setKeys(uint256 _privKey) internal {
privKey = _privKey;
pubKeyG1 = BN254.generatorG1().scalar_mul(_privKey);
pubKeyG2 = G2Operations.mul(_privKey);
pubkeyRegistrationParams.pubkeyG1 = BN254.generatorG1().scalar_mul(_privKey);
pubkeyRegistrationParams.pubkeyG2 = G2Operations.mul(_privKey);
}

function _signMessage(address signer) internal view returns(BN254.G1Point memory) {
Expand Down
42 changes: 22 additions & 20 deletions test/unit/BLSApkRegistryUnit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ contract BLSApkRegistryUnitTests is Test {

BN254.G1Point internal defaultPubKey = BN254.G1Point(18260007818883133054078754218619977578772505796600400998181738095793040006897,3432351341799135763167709827653955074218841517684851694584291831827675065899);

BN254.G1Point pubKeyG1;
BN254.G2Point pubKeyG2;
BN254.G1Point signedMessageHash;
IBLSApkRegistry.PubkeyRegistrationParams pubkeyRegistrationParams;

address alice = address(1);
address bob = address(2);
Expand All @@ -39,13 +37,13 @@ contract BLSApkRegistryUnitTests is Test {
registryCoordinator = new RegistryCoordinatorMock();
blsApkRegistry = new BLSApkRegistryHarness(registryCoordinator);

pubKeyG1 = BN254.generatorG1().scalar_mul(privKey);
pubkeyRegistrationParams.pubkeyG1 = BN254.generatorG1().scalar_mul(privKey);

//privKey*G2
pubKeyG2.X[1] = 19101821850089705274637533855249918363070101489527618151493230256975900223847;
pubKeyG2.X[0] = 5334410886741819556325359147377682006012228123419628681352847439302316235957;
pubKeyG2.Y[1] = 354176189041917478648604979334478067325821134838555150300539079146482658331;
pubKeyG2.Y[0] = 4185483097059047421902184823581361466320657066600218863748375739772335928910;
pubkeyRegistrationParams.pubkeyG2.X[1] = 19101821850089705274637533855249918363070101489527618151493230256975900223847;
pubkeyRegistrationParams.pubkeyG2.X[0] = 5334410886741819556325359147377682006012228123419628681352847439302316235957;
pubkeyRegistrationParams.pubkeyG2.Y[1] = 354176189041917478648604979334478067325821134838555150300539079146482658331;
pubkeyRegistrationParams.pubkeyG2.Y[0] = 4185483097059047421902184823581361466320657066600218863748375739772335928910;


// Initialize a quorum
Expand Down Expand Up @@ -293,46 +291,50 @@ contract BLSApkRegistryUnitTests is Test {

// TODO: better organize / integrate tests migrated from `BLSPublicKeyCompendium` unit tests
function testRegisterBLSPublicKey() public {
signedMessageHash = _signMessage(alice);
pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(alice);
vm.prank(address(registryCoordinator));
blsApkRegistry.registerBLSPublicKey(alice, signedMessageHash, pubKeyG1, pubKeyG2);
blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams);

assertEq(blsApkRegistry.operatorToPubkeyHash(alice), BN254.hashG1Point(pubKeyG1), "pubkey hash not stored correctly");
assertEq(blsApkRegistry.pubkeyHashToOperator(BN254.hashG1Point(pubKeyG1)), alice, "operator address not stored correctly");
assertEq(blsApkRegistry.operatorToPubkeyHash(alice), BN254.hashG1Point(pubkeyRegistrationParams.pubkeyG1),
"pubkey hash not stored correctly");
assertEq(blsApkRegistry.pubkeyHashToOperator(BN254.hashG1Point(pubkeyRegistrationParams.pubkeyG1)), alice,
"operator address not stored correctly");
}

function testRegisterBLSPublicKey_NoMatch_Reverts() public {
signedMessageHash = _signMessage(alice);
BN254.G1Point memory badPubKeyG1 = BN254.generatorG1().scalar_mul(420); // mismatch public keys
pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(alice);
BN254.G1Point memory badPubkeyG1 = BN254.generatorG1().scalar_mul(420); // mismatch public keys

pubkeyRegistrationParams.pubkeyG1 = badPubkeyG1;

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, signedMessageHash, badPubKeyG1, pubKeyG2);
blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams);
}

function testRegisterBLSPublicKey_BadSig_Reverts() public {
signedMessageHash = _signMessage(bob); // sign with wrong private key
pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(bob); // sign with wrong private key

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, signedMessageHash, pubKeyG1, pubKeyG2);
blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams);
}

function testRegisterBLSPublicKey_OpRegistered_Reverts() public {
testRegisterBLSPublicKey(); // register alice

vm.prank(address(registryCoordinator));
vm.expectRevert(bytes("BLSApkRegistry.registerBLSPublicKey: operator already registered pubkey"));
blsApkRegistry.registerBLSPublicKey(alice, signedMessageHash, pubKeyG1, pubKeyG2);
blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams);
}

function testRegisterBLSPublicKey_PkRegistered_Reverts() public {
testRegisterBLSPublicKey();
signedMessageHash = _signMessage(bob); // same private key different operator
pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(bob); // same private key different operator

vm.prank(address(registryCoordinator));
vm.expectRevert(bytes("BLSApkRegistry.registerBLSPublicKey: public key already registered"));
blsApkRegistry.registerBLSPublicKey(bob, signedMessageHash, pubKeyG1, pubKeyG2);
blsApkRegistry.registerBLSPublicKey(bob, pubkeyRegistrationParams);
}

function _signMessage(address signer) internal view returns(BN254.G1Point memory) {
Expand Down
Loading

0 comments on commit 11c51e1

Please sign in to comment.