From ebe657e1167e59dc7959dfe11c8194b72bf9a347 Mon Sep 17 00:00:00 2001 From: Alex <18387287+wadealexc@users.noreply.github.com> Date: Thu, 28 Dec 2023 15:03:01 -0500 Subject: [PATCH] =?UTF-8?q?docs:=20update=20reg=20coord=20to=20include=20p?= =?UTF-8?q?ubkey=20registration=20and=20service=20man=E2=80=A6=20(#116)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: update reg coord to include pubkey registration and service manager usage * docs: add service manager to tech docs intro * fix: update table of contents * docs: add docs for BLSSignatureChecker and OperatorStateRetriever * docs: address feedback --- docs/BLSSignatureChecker.md | 201 ++++++++++++++++++++++++++++- docs/README.md | 15 ++- docs/RegistryCoordinator.md | 17 ++- docs/ServiceManagerBase.md | 68 ++++++++++ docs/old/BLSPublicKeyCompendium.md | 27 ---- docs/registries/BLSApkRegistry.md | 14 ++ 6 files changed, 309 insertions(+), 33 deletions(-) create mode 100644 docs/ServiceManagerBase.md delete mode 100644 docs/old/BLSPublicKeyCompendium.md diff --git a/docs/BLSSignatureChecker.md b/docs/BLSSignatureChecker.md index bc860a6f..31e8d09e 100644 --- a/docs/BLSSignatureChecker.md +++ b/docs/BLSSignatureChecker.md @@ -1 +1,200 @@ -TODO! \ No newline at end of file +[core-docs-m2]: https://github.com/Layr-Labs/eigenlayer-contracts/tree/m2-mainnet/docs +[core-dmgr-docs]: https://github.com/Layr-Labs/eigenlayer-contracts/blob/m2-mainnet/docs/core/DelegationManager.md +[core-dmgr-register]: https://github.com/Layr-Labs/eigenlayer-contracts/blob/m2-mainnet/docs/core/DelegationManager.md#registeroperatortoavs +[core-dmgr-deregister]: https://github.com/Layr-Labs/eigenlayer-contracts/blob/m2-mainnet/docs/core/DelegationManager.md#deregisteroperatorfromavs + +[eigenda-service-manager]: https://github.com/Layr-Labs/eigenda/blob/m2-mainnet-contracts/contracts/src/core/EigenDAServiceManager.sol + +## BLSSignatureChecker + +| File | Type | Proxy | +| -------- | -------- | -------- | +| [`BLSSignatureChecker.sol`](../src/BLSSignatureChecker.sol) | Singleton | Transparent proxy | +| [`OperatorStateRetriever.sol`](../src/OperatorStateRetriever.sol) | Singleton | None | + +`BLSSignatureChecker` and `OperatorStateRetriever` perform (respectively) the onchain and offchain portions of BLS signature validation for the aggregate of a quorum's registered Operators. + +The `OperatorStateRetriever` has various view methods intended to be called by offchain infrastructure in order to prepare a call to `BLSSignatureChecker.checkSignatures`. These methods traverse the state histories kept by the various registry contracts (see [./RegistryCoordinator.md](./RegistryCoordinator.md)) to query states at specific block numbers. + +These historical states are then used within `BLSSignatureChecker` to validate a BLS signature formed from an aggregated subset of the Operators registered for one or more quorums at some specific block number. + +#### High-level Concepts + +This document organizes methods according to the following themes (click each to be taken to the relevant section): +* [Onchain](#onchain) +* [Offchain](#offchain) +* [System Configuration](#system-configuration) + +--- + +### Onchain + +#### `BLSSignatureChecker.checkSignatures` + +```solidity +function checkSignatures( + bytes32 msgHash, + bytes calldata quorumNumbers, + uint32 referenceBlockNumber, + NonSignerStakesAndSignature memory params +) + public + view + returns (QuorumStakeTotals memory, bytes32) + +struct NonSignerStakesAndSignature { + uint32[] nonSignerQuorumBitmapIndices; + BN254.G1Point[] nonSignerPubkeys; + BN254.G1Point[] quorumApks; + BN254.G2Point apkG2; + BN254.G1Point sigma; + uint32[] quorumApkIndices; + uint32[] totalStakeIndices; + uint32[][] nonSignerStakeIndices; +} + +struct QuorumStakeTotals { + uint96[] signedStakeForQuorum; + uint96[] totalStakeForQuorum; +} +``` + +The goal of this method is to allow an AVS to validate a BLS signature formed from the aggregate pubkey ("apk") of Operators registered in one or more quorums at some `referenceBlockNumber`. + +Some notes on method parameters: +* `referenceBlockNumber` is the reason each registry contract keeps historical states: so that lookups can be performed on each registry's info at a particular block. This is important because Operators may sign some data on behalf of an AVS, then deregister from one or more of the AVS's quorums. Historical states allow signature validation to be performed against a "fixed point" in AVS/quorum history. +* `quorumNumbers` is used to perform signature validation across one *or more* quorums. Also, Operators may be registered for more than one quorum - and for each quorum an Operator is registered for, that Operator's pubkey is included in that quorum's apk within the `BLSApkRegistry`. This means that, when calculating an apk across multiple `quorumNumbers`, Operators registered for more than one of these quorums will have their pubkey included more than once in the total apk. +* `params` contains both a signature from all signing Operators, as well as several fields that identify registered, non-signing Operators. While non-signing Operators haven't contributed to the signature, but need to be accounted for because, as Operators registered for one or more signing quorums, their public keys are included in that quorum's apk. Essentially, in order to validate the signature, nonsigners' public keys need to be subtracted out from the total apk to derive the apk that actually signed the message. + +This method performs the following steps. Note that each step involves lookups of historical state from `referenceBlockNumber`, but the writing in this section will use the present tense because adding "at the `referenceBlockNumber`" everywhere gets confusing. Steps follow: +1. Calculate the *total nonsigner apk*, an aggregate pubkey composed of all nonsigner pubkeys. For each nonsigner: + * Query the `RegistryCoordinator` to get the nonsigner's registered quorums. + * Multiply the nonsigner's pubkey by the number of quorums in `quorumNumbers` the nonsigner is registered for. + * Add the result to the *total nonsigner apk*. +2. Calculate the negative of the *total nonsigner apk*. +3. For each quorum: + * Query the `BLSApkRegistry` to get the *quorum apk*: the aggregate pubkey of all Operators registered for that quorum. + * Add the *quorum apk* to the *total nonsigner apk*. This effectively subtracts out any pubkeys belonging to nonsigning Operators in the quorum, leaving only pubkeys of signing Operators. We'll call the result the *total signing apk*. + * Query the `StakeRegistry` to get the total stake for the quorum. + * For each nonsigner, if the nonsigner is registered for the quorum, query the `StakeRegistry` for their stake and subtract it from the total. This leaves only stake belonging to signing Operators. +4. Use the `msgHash`, the *total signing apk*, `params.apkG2`, and `params.sigma` to validate the BLS signature. +5. Return the total stake and signing stakes for each quorum, along with a hash identifying the `referenceBlockNumber` and non-signers + +*Entry Points* (EigenDA): +* Called by [`EigenDAServiceManager.confirmBatch`][eigenda-service-manager] + +*Requirements*: +* Input validation: + * Quorum-related fields MUST have equal lengths: `quorumNumbers`, `params.quorumApks`, `params.quorumApkIndices`, `params.totalStakeIndices`, `params.nonSignerStakeIndices` + * Nonsigner-related fields MUST have equal lengths: `params.nonSignerPubkeys`, `params.nonSignerQuorumBitmapIndices` + * `referenceBlockNumber` MUST NOT be greater than `block.number` + * `quorumNumbers` MUST be an ordered list of valid, initialized quorums + * `params.nonSignerPubkeys` MUST ONLY contain unique pubkeys, in ascending order of their pubkey hash +* For each quorum: + * If stale stakes are forbidden (see [`BLSSignatureChecker.setStaleStakesForbidden`](#blssignaturecheckersetstalestakesforbidden)), check the last `quorumUpdateBlockNumber` is within `DelegationManager.withdrawalDelayBlocks` of `referenceBlockNumber`. This references a value in the EigenLayer core contracts - see [EigenLayer core docs][core-docs-m2] for more info. + * Validate that each `params.quorumApks` corresponds to the quorum's apk at the `referenceBlockNumber` +* For each historical state lookup, the `referenceBlockNumber` and provided index MUST point to a valid historical entry: + * `referenceBlockNumber` MUST come after the entry's `updateBlockNumber` + * The entry's `nextUpdateBlockNumber` MUST EITHER be 0, OR greater than `referenceBlockNumber` + +--- + +### Offchain + +These methods perform very gas-heavy lookups through various registry states, and are called by offchain infrastructure to construct calldata for a call to `BLSSignatureChecker.checkSignatures`: +* [`OperatorStateRetriever.getOperatorState (operatorId)`](#operatorstateretrievergetoperatorstate-operatorid) +* [`OperatorStateRetriever.getOperatorState (quorumNumbers)`](#operatorstateretrievergetoperatorstate-quorumnumbers) +* [`OperatorStateRetriever.getCheckSignaturesIndices`](#operatorstateretrievergetchecksignaturesindices) + +#### `OperatorStateRetriever.getOperatorState (operatorId)` + +```solidity +function getOperatorState( + IRegistryCoordinator registryCoordinator, + bytes32 operatorId, + uint32 blockNumber +) + external + view + returns (uint256, Operator[][] memory) + +struct Operator { + bytes32 operatorId; + uint96 stake; +} +``` + +Traverses history in the `RegistryCoordinator`, `IndexRegistry`, and `StakeRegistry` to retrieve information on an Operator (given by `operatorId`) and the quorums they are registered for at a specific `blockNumber`. Returns: +* `uint256`: a bitmap of the quorums the Operator was registered for at `blockNumber` +* `Operator[][]`: For each of the quorums mentioned above, this is a list of the Operators registered for that quorum at `blockNumber`, containing each Operator's `operatorId` and `stake`. + +#### `OperatorStateRetriever.getOperatorState (quorumNumbers)` + +```solidity +function getOperatorState( + IRegistryCoordinator registryCoordinator, + bytes memory quorumNumbers, + uint32 blockNumber +) + public + view + returns(Operator[][] memory) +``` + +Traverses history in the `RegistryCoordinator`, `IndexRegistry`, and `StakeRegistry` to retrieve information on the Operator set registered for each quorum in `quorumNumbers` at `blockNumber`. Returns: +* `Operator[][]`: For each quorum in `quorumNumbers`, this is a list of the Operators registered for that quorum at `blockNumber`, containing each Operator's `operatorId` and `stake`. + +#### `OperatorStateRetriever.getCheckSignaturesIndices` + +```solidity +function getCheckSignaturesIndices( + IRegistryCoordinator registryCoordinator, + uint32 referenceBlockNumber, + bytes calldata quorumNumbers, + bytes32[] calldata nonSignerOperatorIds +) + external + view + returns (CheckSignaturesIndices memory) + +struct CheckSignaturesIndices { + uint32[] nonSignerQuorumBitmapIndices; + uint32[] quorumApkIndices; + uint32[] totalStakeIndices; + uint32[][] nonSignerStakeIndices; // nonSignerStakeIndices[quorumNumberIndex][nonSignerIndex] +} +``` + +Traverses histories in the `RegistryCoordinator`, `IndexRegistry`, `StakeRegistry`, and `BLSApkRegistry` to retrieve information on one or more quorums' Operator sets and nonsigning Operators at a given `referenceBlockNumber`. + +The return values are all "indices," because of the linear historical state each registry keeps. Offchain code calls this method to compute indices into historical state, which later is leveraged for cheap lookups in `BLSSignatureChecker.checkSignatures` (rather than traversing over the history during an onchain operation). + +For each quorum, this returns: +* `uint32[] nonSignerQuorumBitmapIndices`: The indices in `RegistryCoordinator._operatorBitmapHistory` where each nonsigner's registered quorum bitmap can be found at `referenceBlockNumber`. Length is equal to the number of nonsigners included in `nonSignerOperatorIds` +* `uint32[] quorumApkIndices`: The indices in `BLSApkRegistry.apkHistory` where the quorum's apk can be found at `referenceBlockNumber`. Length is equal to the number of quorums in `quorumNumbers`. +* `uint32[] totalStakeIndices`: The indices in `StakeRegistry._totalStakeHistory` where each quorum's total stake can be found at `referenceBlockNumber`. Length is equal to the number of quorums in `quorumNumbers`. +* `uint32[][] nonSignerStakeIndices`: For each quorum, a list of the indices of each nonsigner's `StakeRegistry.operatorStakeHistory` entry at `referenceBlockNumber`. Length is equal to the number of quorums in `quorumNumbers`, and each sub-list is equal in length to the number of nonsigners in `nonSignerOperatorIds` registered for that quorum at `referenceBlockNumber` + +--- + +### System Configuration + +#### `BLSSignatureChecker.setStaleStakesForbidden` + +```solidity +function setStaleStakesForbidden( + bool value +) + external + onlyCoordinatorOwner +``` + +This method allows the `RegistryCoordinator` Owner to update `staleStakesForbidden` in the `BLSSignatureChecker`. If stale stakes are forbidden, `BLSSignatureChecker.checkSignatures` will perform an additional check when querying each quorum's apk, Operator stakes, and total stakes. + +This additional check requires that each quorum was updated within a certain block window of the `referenceBlockNumber` passed into `BLSSignatureChecker.checkSignatures`. + +*Effects*: +* Sets `staleStakesForbidden` to `value` + +*Requirements*: +* Caller MUST be the `RegistryCoordinator` Owner \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 54bf44ec..e0017c24 100644 --- a/docs/README.md +++ b/docs/README.md @@ -34,6 +34,7 @@ For more information on EigenDA, check out the repo: [Layr-Labs/eigenda][eigenda * [State Histories](#state-histories) * [Hooking Into EigenLayer Core](#hooking-into-eigenlayer-core) * [System Components](#system-components) + * [Service Manager](#service-manager) * [Registries](#registries) * [BLSSignatureChecker](#blssignaturechecker) @@ -105,6 +106,18 @@ Eventually, operator slashing and payment for services will be part of the middl ### System Components +#### Service Manager + +| Code | Type | Proxy | +| -------- | -------- | -------- | +| [`ServiceManagerBase.sol`](../src/ServiceManagerBase.sol) | Singleton | Transparent proxy | + +The Service Manager contract serves as the AVS's address relative to EigenLayer core contracts. When operators register for/deregister from the AVS, the Service Manager forwards this request to the DelegationManager (see [Hooking Into EigenLayer Core](#hooking-into-eigenlayer-core) above). + +It also contains a few convenience methods used to query operator information by the frontend. + +See full documentation in [`ServiceManagerBase.md`](./ServiceManagerBase.md). + #### Registries | Code | Type | Proxy | @@ -136,4 +149,4 @@ The BLSSignatureChecker verifies signatures made by the aggregate pubkeys ("Apk" The `OperatorStateRetriever` is used by offchain code to query the `RegistryCoordinator` (and its registries) for information that will ultimately be passed into `BLSSignatureChecker.checkSignatures`. -See full documentation in [`BLSSignatureChecker.md`](./BLSSignatureChecker.md). \ No newline at end of file +See full documentation for both of these contracts in [`BLSSignatureChecker.md`](./BLSSignatureChecker.md). \ No newline at end of file diff --git a/docs/RegistryCoordinator.md b/docs/RegistryCoordinator.md index ae82c64b..7f65b7db 100644 --- a/docs/RegistryCoordinator.md +++ b/docs/RegistryCoordinator.md @@ -42,6 +42,7 @@ These methods allow operators to register for/deregister from one or more quorum function registerOperator( bytes calldata quorumNumbers, string calldata socket, + IBLSApkRegistry.PubkeyRegistrationParams calldata params, SignatureWithSaltAndExpiry memory operatorSignature ) external @@ -53,12 +54,16 @@ Registers the caller as an Operator for one or more quorums, as long as registra * `StakeRegistry.registerOperator` * `IndexRegistry.registerOperator` -If the Operator was not currently registered for any quorums, this method will register the Operator to the AVS in the EigenLayer core contracts (`DelegationManager.registerOperatorToAVS`), passing in the provided `operatorSignature`. See the [`DelegationManager` docs][core-dmgr-docs] for more details. +If the Operator has never registered for any of this AVS's quorums before, they need to register a BLS public key to participate in AVS signing events. In this case, this method will automatically pass `params` to the `BLSApkRegistry` to perform public key registration. The registered pubkey hash becomes the Operator's unique operator id, used to identify them in many places in the middleware contracts. + +If the Operator was not currently registered for any quorums, this method will register the Operator to the AVS in the EigenLayer core contracts via the `ServiceManagerBase`. *Effects*: +* If the Operator has never registered for the AVS before: + * Registers their BLS pubkey in the `BLSApkRegistry` (see [`BLSApkRegistry.registerBLSPublicKey`](./registries/BLSApkRegistry.md#registerblspublickey)) * If the Operator was not currently registered for any quorums: * Updates their status to `REGISTERED` - * Registers them in the core contracts (see [`DelegationManager.registerOperatorToAVS`][core-dmgr-register]) + * Registers them in the core contracts (see [`ServiceManagerBase.registerOperatorToAVS`](./ServiceManagerBase.md#registeroperatortoavs)) * Adds the new quorums to the Operator's current registered quorums, and updates the Operator's bitmap history * See [`BLSApkRegistry.registerOperator`](./registries/BLSApkRegistry.md#registeroperator) * See [`StakeRegistry.registerOperator`](./registries/StakeRegistry.md#registeroperator) @@ -71,7 +76,7 @@ If the Operator was not currently registered for any quorums, this method will r * `quorumNumbers` MUST contain at least one valid quorum * `quorumNumbers` MUST NOT contain any quorums the Operator is already registered for * If the Operator was not currently registered for any quorums: - * See [`DelegationManager.registerOperatorToAVS`][core-dmgr-register] + * See [`ServiceManagerBase.registerOperatorToAVS`](./ServiceManagerBase.md#registeroperatortoavs) * See [`BLSApkRegistry.registerOperator`](./registries/BLSApkRegistry.md#registeroperator) * See [`StakeRegistry.registerOperator`](./registries/StakeRegistry.md#registeroperator) * See [`IndexRegistry.registerOperator`](./registries/IndexRegistry.md#registeroperator) @@ -83,6 +88,7 @@ If the Operator was not currently registered for any quorums, this method will r function registerOperatorWithChurn( bytes calldata quorumNumbers, string calldata socket, + IBLSApkRegistry.PubkeyRegistrationParams calldata params, OperatorKickParam[] calldata operatorKickParams, SignatureWithSaltAndExpiry memory churnApproverSignature, SignatureWithSaltAndExpiry memory operatorSignature @@ -121,7 +127,9 @@ function deregisterOperator( Allows an Operator to deregister themselves from one or more quorums. *Effects*: -* If the Operator is no longer registered for any quorums, updates their status to `DEREGISTERED` +* If the Operator is no longer registered for any quorums: + * Updates their status to `DEREGISTERED` + * Deregisters them in the core contracts (see [`ServiceManagerBase.deregisterOperatorFromAVS`](./ServiceManagerBase.md#deregisteroperatorfromavs)) * Removes the new quorums from the Operator's current registered quorums, and updates the Operator's bitmap history * See [`BLSApkRegistry.deregisterOperator`](./registries/BLSApkRegistry.md#deregisteroperator) * See [`StakeRegistry.deregisterOperator`](./registries/StakeRegistry.md#deregisteroperator) @@ -133,6 +141,7 @@ Allows an Operator to deregister themselves from one or more quorums. * `quorumNumbers` MUST be an ordered array of quorum numbers, with no entry exceeding the current `quorumCount` * `quorumNumbers` MUST contain at least one valid quorum * `quorumNumbers` MUST ONLY contain bits that are also set in the Operator's current registered quorum bitmap +* See [`ServiceManagerBase.deregisterOperatorFromAVS`](./ServiceManagerBase.md#deregisteroperatorfromavs) * See [`BLSApkRegistry.deregisterOperator`](./registries/BLSApkRegistry.md#deregisteroperator) * See [`StakeRegistry.deregisterOperator`](./registries/StakeRegistry.md#deregisteroperator) * See [`IndexRegistry.deregisterOperator`](./registries/IndexRegistry.md#deregisteroperator) diff --git a/docs/ServiceManagerBase.md b/docs/ServiceManagerBase.md new file mode 100644 index 00000000..e42e10c5 --- /dev/null +++ b/docs/ServiceManagerBase.md @@ -0,0 +1,68 @@ +[core-dmgr-docs]: https://github.com/Layr-Labs/eigenlayer-contracts/blob/m2-mainnet/docs/core/DelegationManager.md +[core-dmgr-register]: https://github.com/Layr-Labs/eigenlayer-contracts/blob/m2-mainnet/docs/core/DelegationManager.md#registeroperatortoavs +[core-dmgr-deregister]: https://github.com/Layr-Labs/eigenlayer-contracts/blob/m2-mainnet/docs/core/DelegationManager.md#deregisteroperatorfromavs + +## ServiceManagerBase + +| File | Type | Proxy | +| -------- | -------- | -------- | +| [`ServiceManagerBase.sol`](../src/ServiceManagerBase.sol) | Singleton | Transparent proxy | + +The `ServiceManagerBase` represents the AVS's address relative to EigenLayer core. When registering or deregistering an operator from an AVS, the AVS's `ServiceManagerBase` communicates this change to the core contracts, allowing the core contracts to maintain an up-to-date view on operator registration status with various AVSs. + +*As of M2*: +* Currently, this contract is used by the `DelegationManager` to keep track of operator registration and deregistration. Eventually, this relationship will be expanded to allow operators to opt in to slashing and payments for services. + +--- + +#### `registerOperatorToAVS` + +```solidity +function registerOperatorToAVS( + address operator, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature +) + public + virtual + onlyRegistryCoordinator +``` + +When the `RegistryCoordinator` registers an operator for an AVS and they were not previously registered, it calls this method on `ServiceManagerBase`, which forwards the call to the EigenLayer core contract, the `DelegationManager`. + +*Entry Points*: +* `RegistryCoordinator.registerOperator` +* `RegistryCoordinator.registerOperatorWithChurn` + +*Effects*: +* See EigenLayer core: [`DelegationManager.registerOperatorToAVS`][core-dmgr-register] + +*Requirements*: +* Caller MUST be the `RegistryCoordinator` +* See EigenLayer core: [`DelegationManager.registerOperatorToAVS`][core-dmgr-register] + +#### `deregisterOperatorFromAVS` + +```solidity +function deregisterOperatorFromAVS( + address operator +) + public + virtual + onlyRegistryCoordinator +``` + +When the `RegistryCoordinator` deregisters an operator from an AVS, it calls this method on `ServiceManagerBase`, which forwards the call to the EigenLayer core contract, the `DelegationManager`. + +*Entry Points*: +* `RegistryCoordinator.registerOperatorWithChurn` +* `RegistryCoordinator.deregisterOperator` +* `RegistryCoordinator.ejectOperator` +* `RegistryCoordinator.updateOperators` +* `RegistryCoordinator.updateOperatorsForQuorum` + +*Effects*: +* See EigenLayer core: [`DelegationManager.deregisterOperatorFromAVS`][core-dmgr-deregister] + +*Requirements*: +* Caller MUST be the `RegistryCoordinator` +* See EigenLayer core: [`DelegationManager.deregisterOperatorFromAVS`][core-dmgr-deregister] \ No newline at end of file diff --git a/docs/old/BLSPublicKeyCompendium.md b/docs/old/BLSPublicKeyCompendium.md deleted file mode 100644 index c97adc32..00000000 --- a/docs/old/BLSPublicKeyCompendium.md +++ /dev/null @@ -1,27 +0,0 @@ -# BLSPublicKeyCompendium - -This contract is shared by all AVSs and serves as a single place for operators to connect their execution layer address to a bn254 public key. This contract also prevents [rogue key attacks](https://xn--2-umb.com/22/bls-signatures/#rogue-key-attack). - -## Flows - -There is only one flow for this contract, which is a call from an operator to register a bn254 public key as controlled by their execution layer address. - -### Cryptographic Verification - -Operators provide the contract with -- A BLS signature $\sigma \in \mathbb{G}_1$ of $M = (msg.sender, chain.id, \text{"EigenLayer\_BN254\_Pubkey\_Registration"})$ -- Their public keys $pk_1 \in \mathbb{G}_1$ and $pk_2 \in \mathbb{G}_2$ - -The contract then -- Calculates $\gamma = keccak256(\sigma, pk_1, pk_2, M)$ -- Verifies the paring $e(\sigma + \gamma pk_1, [1]_2) = e(H(m) + \gamma[1]_1, pk_2)$ - -This verifies that the operator owns the secret key corresponding to the public keys and that the $pk_1$ and $pk_2$ have the same discrete logarithm according to their respective curve's generators. - -We do this particular verification because aggregation of public keys and hashing to the curve is cheap in $\mathbb{G}_1$ on ethereum, and the above scheme allows for both! (aggregation to be done in the [BLSSignatureChecker](./BLSSignatureChecker.md)) More detailed notes exist [here](https://geometry.xyz/notebook/Optimized-BLS-multisignatures-on-EVM). - -The contract then stores a map from the execution layer address to the hash of the operator's $\mathbb{G}_1$ public key and the other way around. - -### Upstream Dependencies - -The [BLSPubkeyRegistry](./BLSPubkeyRegistry.md) looks up the public key hashes in this contract when operators register with a certain public key. diff --git a/docs/registries/BLSApkRegistry.md b/docs/registries/BLSApkRegistry.md index 4c707ca3..935ce4a2 100644 --- a/docs/registries/BLSApkRegistry.md +++ b/docs/registries/BLSApkRegistry.md @@ -71,6 +71,20 @@ TODO *Requirements*: * +#### `registerBLSPublicKey` + +```solidity + +``` + +TODO + +*Effects*: +* + +*Requirements*: +* + #### `initializeQuorum` ```solidity