diff --git a/Makefile b/Makefile index 9c58853fb..eca6e5a1b 100644 --- a/Makefile +++ b/Makefile @@ -1064,7 +1064,7 @@ docker_logs_batcher: __TELEMETRY__: # Collector, Jaeger and Elixir API -telemetry_full_start: open_telemetry_start telemetry_start +telemetry_full_start: telemetry_compile_bls_verifier open_telemetry_start telemetry_start # Collector and Jaeger open_telemetry_start: ## Run open telemetry services using telemetry-docker-compose.yaml @@ -1108,6 +1108,10 @@ telemetry_create_env: @cd telemetry_api && \ cp .env.dev .env +telemetry_compile_bls_verifier: + @cd telemetry_api/priv && \ + go build ../bls_verifier/bls_verify.go + setup_local_aligned_all: tmux kill-session -t aligned_layer || true tmux new-session -d -s aligned_layer diff --git a/operator/pkg/operator.go b/operator/pkg/operator.go index b5be4f9e0..410919215 100644 --- a/operator/pkg/operator.go +++ b/operator/pkg/operator.go @@ -646,13 +646,12 @@ func (o *Operator) SendTelemetryData(ctx *cli.Context) error { hash.Write([]byte(ctx.App.Version)) // get hash - version := hash.Sum(nil) + var version [32]byte // All zeroed initially + copy(version[:], hash.Sum(nil)) // sign version - signature, err := crypto.Sign(version[:], o.Config.EcdsaConfig.PrivateKey) - if err != nil { - return err - } + signature := o.Config.BlsConfig.KeyPair.SignMessage(version) + public_key_g2 := o.Config.BlsConfig.KeyPair.GetPubKeyG2() ethRpcUrl, err := BaseUrlOnly(o.Config.BaseConfig.EthRpcUrl) if err != nil { return err @@ -671,12 +670,14 @@ func (o *Operator) SendTelemetryData(ctx *cli.Context) error { } body := map[string]interface{}{ - "version": ctx.App.Version, - "signature": signature, "eth_rpc_url": ethRpcUrl, "eth_rpc_url_fallback": ethRpcUrlFallback, "eth_ws_url": ethWsUrl, "eth_ws_url_fallback": ethWsUrlFallback, + "address": o.Address, + "version": ctx.App.Version, + "signature": signature.Bytes(), + "pub_key_g2": public_key_g2.Bytes(), } bodyBuffer := new(bytes.Buffer) diff --git a/telemetry_api/.gitignore b/telemetry_api/.gitignore index 930813079..0faab228d 100644 --- a/telemetry_api/.gitignore +++ b/telemetry_api/.gitignore @@ -27,3 +27,6 @@ telemetry_api-*.tar # Elixir lsp server .elixir_ls + +# Binaries +priv/bls_verify diff --git a/telemetry_api/bls_verifier/bls_verify.go b/telemetry_api/bls_verifier/bls_verify.go new file mode 100644 index 000000000..24c3cdafc --- /dev/null +++ b/telemetry_api/bls_verifier/bls_verify.go @@ -0,0 +1,91 @@ +package main + +import ( + "encoding/hex" + "flag" + "log" + "os" + + bls "github.com/Layr-Labs/eigensdk-go/crypto/bls" +) + +func main() { + signatureArg := flag.String("signature", "", "BLS signature bytes") + publicKeyG1X := flag.String("public-key-g1-x", "", "BLS public key on g1 affine x coord") + publicKeyG1Y := flag.String("public-key-g1-y", "", "BLS public key on g1 affine y coord") + publicKeyG2Arg := flag.String("public-key-g2", "", "BLS public key on g2") + messageArg := flag.String("message", "", "Hex-encoded message") + + flag.Parse() + + if *signatureArg == "" || *publicKeyG1X == "" || *publicKeyG1Y == "" || *publicKeyG2Arg == "" || *messageArg == "" { + log.Fatalf("All arguments (signature, publickey g1 hash, publickey g2, and messagehash) are required") + } + + signature, err := hex.DecodeString(*signatureArg) + if err != nil { + log.Fatalf("Failed to decode signature: %v", err) + } + + var pubkeyG1PointsBytes [2][]byte + xBytes, err := hex.DecodeString(*publicKeyG1X) + if err != nil { + log.Fatalf("Failed to decode G1 X: %v", err) + } + yBytes, err := hex.DecodeString(*publicKeyG1Y) + if err != nil { + log.Fatalf("Failed to decode G1 Y: %v", err) + } + pubkeyG1PointsBytes[0] = xBytes + pubkeyG1PointsBytes[1] = yBytes + + pubkeyG2Bytes, err := hex.DecodeString(*publicKeyG2Arg) + if err != nil { + log.Fatalf("Failed to decode pubkey: %v", err) + } + + messageHash, err := hex.DecodeString(*messageArg) + if err != nil { + log.Fatalf("Failed to decode message hash: %v", err) + } + + isValid, err := verifySignature(signature, pubkeyG1PointsBytes, pubkeyG2Bytes, messageHash) + if err != nil { + log.Fatalf("Error during verification: %v", err) + } + + if isValid { + os.Exit(0) + } else { + os.Exit(1) + } +} + +func verifySignature(signature []byte, pubkeyG1PointsBytes [2][]byte, pubkeyG2Bytes []byte, message []byte) (bool, error) { + pubkeyG1 := bls.NewZeroG1Point() + pubkeyG1.X.SetBytes(pubkeyG1PointsBytes[0]) + pubkeyG1.Y.SetBytes(pubkeyG1PointsBytes[1]) + + pubkeyG2 := bls.NewZeroG2Point() + _, err := pubkeyG2.SetBytes(pubkeyG2Bytes) + if err != nil { + return false, err + } + + var messageBytes [32]byte + copy(messageBytes[:], message[:]) + + sign := bls.NewZeroSignature() + _, err = sign.SetBytes(signature) + if err != nil { + return false, err + } + + // verify the equivalence between the points in the generators + valid, err := pubkeyG1.VerifyEquivalence(pubkeyG2) + if err != nil || !valid { + return false, err + } + + return sign.Verify(pubkeyG2, messageBytes) +} diff --git a/telemetry_api/lib/telemetry_api/bls_signature_verifier.ex b/telemetry_api/lib/telemetry_api/bls_signature_verifier.ex new file mode 100644 index 000000000..215a501b0 --- /dev/null +++ b/telemetry_api/lib/telemetry_api/bls_signature_verifier.ex @@ -0,0 +1,28 @@ +defmodule BLSSignatureVerifier do + def verify(signature, {pubkey_g1_x, pubkey_g1_y}, bls_pubkey_g2, message) do + pubkey_g1_x = <> + pubkey_g1_y = <> + + args = [ + "--signature", + Base.encode16(:binary.list_to_bin(signature)), + "--public-key-g1-x", + Base.encode16(pubkey_g1_x), + "--public-key-g1-y", + Base.encode16(pubkey_g1_y), + "--public-key-g2", + Base.encode16(:binary.list_to_bin(bls_pubkey_g2)), + "--message", + Base.encode16(message) + ] + + binary_path = Path.join(:code.priv_dir(:telemetry_api), "bls_verify") + {output, exit_code} = System.cmd(binary_path, args) + + case exit_code do + 0 -> {:ok, "Valid"} + 1 -> {:error, "Invalid signature"} + _ -> {:error, "Verification failed: #{output}"} + end + end +end diff --git a/telemetry_api/lib/telemetry_api/contract_managers/bls_apk_registry.ex b/telemetry_api/lib/telemetry_api/contract_managers/bls_apk_registry.ex new file mode 100644 index 000000000..528288c53 --- /dev/null +++ b/telemetry_api/lib/telemetry_api/contract_managers/bls_apk_registry.ex @@ -0,0 +1,46 @@ +defmodule BLSApkRegistry do + require Logger + + @aligned_config_file System.get_env("ALIGNED_CONFIG_FILE") + + config_file_path = + case @aligned_config_file do + nil -> raise("ALIGNED_CONFIG_FILE not set in .env") + file -> file + end + + {status, config_json_string} = File.read(config_file_path) + + case status do + :ok -> + Logger.debug("Aligned deployment file read successfully") + + :error -> + raise( + "Config file not read successfully, make sure your .env is correctly created, and make sure Eigenlayer config file is correctly stored" + ) + end + + @contract_address Jason.decode!(config_json_string) + |> Map.get("addresses") + |> Map.get("blsApkRegistry") + + use Ethers.Contract, + abi_file: "priv/abi/IBLSApkRegistry.json", + default_address: @contract_address + + def get_bls_apk_registry_address() do + @contract_address + end + + def get_operator_bls_pubkey(operator_address) do + case BLSApkRegistry.get_registered_pubkey(operator_address) + |> Ethers.call() do + {:ok, data} -> + {:ok, data} + + error -> + {:error, error} + end + end +end diff --git a/telemetry_api/lib/telemetry_api/operators.ex b/telemetry_api/lib/telemetry_api/operators.ex index 019499d2d..c3b2864f9 100644 --- a/telemetry_api/lib/telemetry_api/operators.ex +++ b/telemetry_api/lib/telemetry_api/operators.ex @@ -135,24 +135,32 @@ defmodule TelemetryApi.Operators do ## Examples - iex> update_operator(some_version, some_signature, %{field: value}) + iex> update_operator(address, some_version, some_signature, pubkey_g2, %{field: value}) {:ok, %Ecto.Changeset{}} - iex> update_operator(some_version, invalid_signature, %{field: value}) + iex> update_operator(address, some_version, invalid_signature, pubkey_g2, %{field: value}) {:error, "Some status", "Some message"} """ - def update_operator(version, signature, changes) do - with {:ok, address} <- SignatureVerifier.recover_address(version, signature) do - address = "0x" <> address - case Repo.get(Operator, address) do - nil -> - {:error, :bad_request, - "Provided address does not correspond to any registered operator"} - - operator -> - update_operator(operator, changes) - end + def update_operator(address, version, signature, pubkey_g2, changes) do + message_hash = ExKeccak.hash_256(version) + + case Repo.get(Operator, address) do + nil -> + {:error, :bad_request, "Provided address does not correspond to any registered operator"} + + operator -> + case BLSApkRegistry.get_operator_bls_pubkey(address) do + {:ok, [pubkey_g1_points, _]} -> + case BLSSignatureVerifier.verify(signature, pubkey_g1_points, pubkey_g2, message_hash) do + {:ok, _} -> + update_operator(operator, changes) + {:error, _} -> + {:error, :unauthorized, "Signature verification failed"} + end + {:error, _} -> + {:error, :not_found, "Failed to retrieve public key for the operator"} + end end end diff --git a/telemetry_api/lib/telemetry_api/signature_verifier.ex b/telemetry_api/lib/telemetry_api/signature_verifier.ex deleted file mode 100644 index 41360f3b2..000000000 --- a/telemetry_api/lib/telemetry_api/signature_verifier.ex +++ /dev/null @@ -1,59 +0,0 @@ -defmodule SignatureVerifier do - alias ExSecp256k1 - alias ExKeccak - alias :binary, as: Binary - - # Hash the version string using Keccak256 - defp hash_version(version) do - ExKeccak.hash_256(version) - end - - # Recover the public key from the signature and hashed version - defp recover_public_key(hash, signature, recovery_id) do - case ExSecp256k1.recover_compact(hash, signature, recovery_id) do - {:ok, public_key} -> {:ok, public_key} - _error -> {:error, :bad_request, "Failed to recover public key"} - end - end - - # Convert public key to Ethereum-like address - def public_key_to_address(public_key) do - # Remove the first byte (which is 0x04 for uncompressed public keys) - public_key = binary_part(public_key, 1, 64) - - # Hash the public key with Keccak256 - public_key_hash = ExKeccak.hash_256(public_key) - - # Get the last 20 bytes (Ethereum address format) - <<_::binary-size(12), address::binary-size(20)>> = public_key_hash - address - end - - @doc """ - Get the address from the version and signature - - Examples - iex> version = "v0.7.0" - iex> signature = N1UJOvjJT1W39MdQUYAOsKZj4aQ1Sjkwp31NJgafpjoUniGt24tSaLw6TlTKP68AkLtsIFoVEaJcJDj7TyvhLQA= - iex> recover_address(version, signature) - "0x..." - """ - def recover_address(version, signature) do - version_hash = hash_version(version) - # Signature contains r, s and v (recovery_id) - # r<>s is 64 bytes. - # v is the last byte of the signature and have to be converted to integer - {:ok, binary_signature} = Base.decode64(signature) - signature_len = byte_size(binary_signature) - rs = binary_part(binary_signature, 0, signature_len - 1) - recovery_id = Binary.decode_unsigned(binary_part(binary_signature, signature_len - 1, 1)) - - with {:ok, address} <- recover_public_key(version_hash, rs, recovery_id) do - addr = - public_key_to_address(address) - |> Base.encode16(case: :lower) - - {:ok, addr} - end - end -end diff --git a/telemetry_api/lib/telemetry_api_web/controllers/operator_controller.ex b/telemetry_api/lib/telemetry_api_web/controllers/operator_controller.ex index 64d093cf2..8d693b108 100644 --- a/telemetry_api/lib/telemetry_api_web/controllers/operator_controller.ex +++ b/telemetry_api/lib/telemetry_api_web/controllers/operator_controller.ex @@ -11,8 +11,17 @@ defmodule TelemetryApiWeb.OperatorController do render(conn, :index, operators: operators) end - def create_or_update(conn, %{"version" => version, "signature" => signature} = attrs) do - with {:ok, %Operator{} = operator} <- Operators.update_operator(version, signature, attrs) do + def create_or_update( + conn, + %{ + "address" => address, + "version" => version, + "signature" => signature, + "pub_key_g2" => pub_key_g2 + } = attrs + ) do + with {:ok, %Operator{} = operator} <- + Operators.update_operator(address, version, signature, pub_key_g2, attrs) do conn |> put_status(:created) |> put_resp_header("location", ~p"/api/operators/#{operator}") diff --git a/telemetry_api/priv/abi/IBLSApkRegistry.json b/telemetry_api/priv/abi/IBLSApkRegistry.json new file mode 100644 index 000000000..ddb45ac11 --- /dev/null +++ b/telemetry_api/priv/abi/IBLSApkRegistry.json @@ -0,0 +1 @@ +{"abi":[{"type":"function","name":"deregisterOperator","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"quorumNumbers","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"getApk","inputs":[{"name":"quorumNumber","type":"uint8","internalType":"uint8"}],"outputs":[{"name":"","type":"tuple","internalType":"struct BN254.G1Point","components":[{"name":"X","type":"uint256","internalType":"uint256"},{"name":"Y","type":"uint256","internalType":"uint256"}]}],"stateMutability":"view"},{"type":"function","name":"getApkHashAtBlockNumberAndIndex","inputs":[{"name":"quorumNumber","type":"uint8","internalType":"uint8"},{"name":"blockNumber","type":"uint32","internalType":"uint32"},{"name":"index","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bytes24","internalType":"bytes24"}],"stateMutability":"view"},{"type":"function","name":"getApkIndicesAtBlockNumber","inputs":[{"name":"quorumNumbers","type":"bytes","internalType":"bytes"},{"name":"blockNumber","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint32[]","internalType":"uint32[]"}],"stateMutability":"view"},{"type":"function","name":"getApkUpdateAtIndex","inputs":[{"name":"quorumNumber","type":"uint8","internalType":"uint8"},{"name":"index","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"tuple","internalType":"struct IBLSApkRegistry.ApkUpdate","components":[{"name":"apkHash","type":"bytes24","internalType":"bytes24"},{"name":"updateBlockNumber","type":"uint32","internalType":"uint32"},{"name":"nextUpdateBlockNumber","type":"uint32","internalType":"uint32"}]}],"stateMutability":"view"},{"type":"function","name":"getOperatorFromPubkeyHash","inputs":[{"name":"pubkeyHash","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"getOperatorId","inputs":[{"name":"operator","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"getRegisteredPubkey","inputs":[{"name":"operator","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"tuple","internalType":"struct BN254.G1Point","components":[{"name":"X","type":"uint256","internalType":"uint256"},{"name":"Y","type":"uint256","internalType":"uint256"}]},{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"initializeQuorum","inputs":[{"name":"quorumNumber","type":"uint8","internalType":"uint8"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"operatorToPubkeyHash","inputs":[{"name":"operator","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"pubkeyHashToOperator","inputs":[{"name":"pubkeyHash","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"registerBLSPublicKey","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"params","type":"tuple","internalType":"struct IBLSApkRegistry.PubkeyRegistrationParams","components":[{"name":"pubkeyRegistrationSignature","type":"tuple","internalType":"struct BN254.G1Point","components":[{"name":"X","type":"uint256","internalType":"uint256"},{"name":"Y","type":"uint256","internalType":"uint256"}]},{"name":"pubkeyG1","type":"tuple","internalType":"struct BN254.G1Point","components":[{"name":"X","type":"uint256","internalType":"uint256"},{"name":"Y","type":"uint256","internalType":"uint256"}]},{"name":"pubkeyG2","type":"tuple","internalType":"struct BN254.G2Point","components":[{"name":"X","type":"uint256[2]","internalType":"uint256[2]"},{"name":"Y","type":"uint256[2]","internalType":"uint256[2]"}]}]},{"name":"pubkeyRegistrationMessageHash","type":"tuple","internalType":"struct BN254.G1Point","components":[{"name":"X","type":"uint256","internalType":"uint256"},{"name":"Y","type":"uint256","internalType":"uint256"}]}],"outputs":[{"name":"operatorId","type":"bytes32","internalType":"bytes32"}],"stateMutability":"nonpayable"},{"type":"function","name":"registerOperator","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"quorumNumbers","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"registryCoordinator","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"event","name":"NewPubkeyRegistration","inputs":[{"name":"operator","type":"address","indexed":true,"internalType":"address"},{"name":"pubkeyG1","type":"tuple","indexed":false,"internalType":"struct BN254.G1Point","components":[{"name":"X","type":"uint256","internalType":"uint256"},{"name":"Y","type":"uint256","internalType":"uint256"}]},{"name":"pubkeyG2","type":"tuple","indexed":false,"internalType":"struct BN254.G2Point","components":[{"name":"X","type":"uint256[2]","internalType":"uint256[2]"},{"name":"Y","type":"uint256[2]","internalType":"uint256[2]"}]}],"anonymous":false},{"type":"event","name":"OperatorAddedToQuorums","inputs":[{"name":"operator","type":"address","indexed":false,"internalType":"address"},{"name":"operatorId","type":"bytes32","indexed":false,"internalType":"bytes32"},{"name":"quorumNumbers","type":"bytes","indexed":false,"internalType":"bytes"}],"anonymous":false},{"type":"event","name":"OperatorRemovedFromQuorums","inputs":[{"name":"operator","type":"address","indexed":false,"internalType":"address"},{"name":"operatorId","type":"bytes32","indexed":false,"internalType":"bytes32"},{"name":"quorumNumbers","type":"bytes","indexed":false,"internalType":"bytes"}],"anonymous":false}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{"deregisterOperator(address,bytes)":"f4e24fe5","getApk(uint8)":"5f61a884","getApkHashAtBlockNumberAndIndex(uint8,uint32,uint256)":"68bccaac","getApkIndicesAtBlockNumber(bytes,uint256)":"d5254a8c","getApkUpdateAtIndex(uint8,uint256)":"605747d5","getOperatorFromPubkeyHash(bytes32)":"47b314e8","getOperatorId(address)":"13542a4e","getRegisteredPubkey(address)":"7ff81a87","initializeQuorum(uint8)":"26d941f2","operatorToPubkeyHash(address)":"de29fac0","pubkeyHashToOperator(bytes32)":"e8bb9ae6","registerBLSPublicKey(address,((uint256,uint256),(uint256,uint256),(uint256[2],uint256[2])),(uint256,uint256))":"bf79ce58","registerOperator(address,bytes)":"3fb27952","registryCoordinator()":"6d14a987"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.27+commit.40a35a09\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"X\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"Y\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"struct BN254.G1Point\",\"name\":\"pubkeyG1\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"X\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"Y\",\"type\":\"uint256[2]\"}],\"indexed\":false,\"internalType\":\"struct BN254.G2Point\",\"name\":\"pubkeyG2\",\"type\":\"tuple\"}],\"name\":\"NewPubkeyRegistration\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"operatorId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quorumNumbers\",\"type\":\"bytes\"}],\"name\":\"OperatorAddedToQuorums\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"operatorId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quorumNumbers\",\"type\":\"bytes\"}],\"name\":\"OperatorRemovedFromQuorums\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"quorumNumbers\",\"type\":\"bytes\"}],\"name\":\"deregisterOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"quorumNumber\",\"type\":\"uint8\"}],\"name\":\"getApk\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"X\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"Y\",\"type\":\"uint256\"}],\"internalType\":\"struct BN254.G1Point\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"quorumNumber\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getApkHashAtBlockNumberAndIndex\",\"outputs\":[{\"internalType\":\"bytes24\",\"name\":\"\",\"type\":\"bytes24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"quorumNumbers\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"getApkIndicesAtBlockNumber\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"quorumNumber\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getApkUpdateAtIndex\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes24\",\"name\":\"apkHash\",\"type\":\"bytes24\"},{\"internalType\":\"uint32\",\"name\":\"updateBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"nextUpdateBlockNumber\",\"type\":\"uint32\"}],\"internalType\":\"struct IBLSApkRegistry.ApkUpdate\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"pubkeyHash\",\"type\":\"bytes32\"}],\"name\":\"getOperatorFromPubkeyHash\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"getOperatorId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"getRegisteredPubkey\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"X\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"Y\",\"type\":\"uint256\"}],\"internalType\":\"struct BN254.G1Point\",\"name\":\"\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"quorumNumber\",\"type\":\"uint8\"}],\"name\":\"initializeQuorum\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"operatorToPubkeyHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"pubkeyHash\",\"type\":\"bytes32\"}],\"name\":\"pubkeyHashToOperator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"X\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"Y\",\"type\":\"uint256\"}],\"internalType\":\"struct BN254.G1Point\",\"name\":\"pubkeyRegistrationSignature\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"X\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"Y\",\"type\":\"uint256\"}],\"internalType\":\"struct BN254.G1Point\",\"name\":\"pubkeyG1\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"X\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"Y\",\"type\":\"uint256[2]\"}],\"internalType\":\"struct BN254.G2Point\",\"name\":\"pubkeyG2\",\"type\":\"tuple\"}],\"internalType\":\"struct IBLSApkRegistry.PubkeyRegistrationParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"X\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"Y\",\"type\":\"uint256\"}],\"internalType\":\"struct BN254.G1Point\",\"name\":\"pubkeyRegistrationMessageHash\",\"type\":\"tuple\"}],\"name\":\"registerBLSPublicKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"operatorId\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"quorumNumbers\",\"type\":\"bytes\"}],\"name\":\"registerOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registryCoordinator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Layr Labs, Inc.\",\"kind\":\"dev\",\"methods\":{\"deregisterOperator(address,bytes)\":{\"details\":\"access restricted to the RegistryCoordinatorPreconditions (these are assumed, not validated in this contract): 1) `quorumNumbers` has no duplicates 2) `quorumNumbers.length` != 0 3) `quorumNumbers` is ordered in ascending order 4) the operator is not already deregistered 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for\",\"params\":{\"operator\":\"The address of the operator to deregister.\",\"quorumNumbers\":\"The quorum numbers the operator is deregistering from, where each byte is an 8 bit integer quorumNumber.\"}},\"getApkHashAtBlockNumberAndIndex(uint8,uint32,uint256)\":{\"params\":{\"blockNumber\":\"is the number of the block for which the latest ApkHash will be retrieved\",\"index\":\"is the index of the apkUpdate being retrieved from the list of quorum apkUpdates in storage\",\"quorumNumber\":\"is the quorum whose ApkHash is being retrieved\"}},\"getOperatorId(address)\":{\"details\":\"Returns zero in the event that the `operator` has never registered for the AVS\"},\"getRegisteredPubkey(address)\":{\"details\":\"Reverts if the operator has not registered a valid pubkey\"},\"initializeQuorum(uint8)\":{\"params\":{\"quorumNumber\":\"The number of the new quorum\"}},\"registerBLSPublicKey(address,((uint256,uint256),(uint256,uint256),(uint256[2],uint256[2])),(uint256,uint256))\":{\"params\":{\"operator\":\"is the operator for whom the key is being registered\",\"params\":\"contains the G1 & G2 public keys of the operator, and a signature proving their ownership\",\"pubkeyRegistrationMessageHash\":\"is a hash that the operator must sign to prove key ownership\"}},\"registerOperator(address,bytes)\":{\"details\":\"access restricted to the RegistryCoordinatorPreconditions (these are assumed, not validated in this contract): 1) `quorumNumbers` has no duplicates 2) `quorumNumbers.length` != 0 3) `quorumNumbers` is ordered in ascending order 4) the operator is not already registered\",\"params\":{\"operator\":\"The address of the operator to register.\",\"quorumNumbers\":\"The quorum numbers the operator is registering for, where each byte is an 8 bit integer quorumNumber.\"}}},\"title\":\"Minimal interface for a registry that keeps track of aggregate operator public keys across many quorums.\",\"version\":1},\"userdoc\":{\"events\":{\"NewPubkeyRegistration(address,(uint256,uint256),(uint256[2],uint256[2]))\":{\"notice\":\"Emitted when `operator` registers with the public keys `pubkeyG1` and `pubkeyG2`.\"}},\"kind\":\"user\",\"methods\":{\"deregisterOperator(address,bytes)\":{\"notice\":\"Deregisters the `operator`'s pubkey for the specified `quorumNumbers`.\"},\"getApk(uint8)\":{\"notice\":\"Returns the current APK for the provided `quorumNumber `\"},\"getApkHashAtBlockNumberAndIndex(uint8,uint32,uint256)\":{\"notice\":\"get 24 byte hash of the apk of `quorumNumber` at `blockNumber` using the provided `index`; called by checkSignatures in BLSSignatureChecker.sol.\"},\"getApkIndicesAtBlockNumber(bytes,uint256)\":{\"notice\":\"Returns the index of the quorumApk index at `blockNumber` for the provided `quorumNumber`\"},\"getApkUpdateAtIndex(uint8,uint256)\":{\"notice\":\"Returns the `ApkUpdate` struct at `index` in the list of APK updates for the `quorumNumber`\"},\"getOperatorFromPubkeyHash(bytes32)\":{\"notice\":\"Returns the operator address for the given `pubkeyHash`\"},\"getOperatorId(address)\":{\"notice\":\"returns the ID used to identify the `operator` within this AVS.\"},\"getRegisteredPubkey(address)\":{\"notice\":\"Returns the pubkey and pubkey hash of an operator\"},\"initializeQuorum(uint8)\":{\"notice\":\"Initializes a new quorum by pushing its first apk update\"},\"operatorToPubkeyHash(address)\":{\"notice\":\"mapping from operator address to pubkey hash. Returns *zero* if the `operator` has never registered, and otherwise returns the hash of the public key of the operator.\"},\"pubkeyHashToOperator(bytes32)\":{\"notice\":\"mapping from pubkey hash to operator address. Returns *zero* if no operator has ever registered the public key corresponding to `pubkeyHash`, and otherwise returns the (unique) registered operator who owns the BLS public key that is the preimage of `pubkeyHash`.\"},\"registerBLSPublicKey(address,((uint256,uint256),(uint256,uint256),(uint256[2],uint256[2])),(uint256,uint256))\":{\"notice\":\"Called by the RegistryCoordinator register an operator as the owner of a BLS public key.\"},\"registerOperator(address,bytes)\":{\"notice\":\"Registers the `operator`'s pubkey for the specified `quorumNumbers`.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/eigenlayer-middleware/src/interfaces/IBLSApkRegistry.sol\":\"IBLSApkRegistry\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@openzeppelin-upgrades-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/\",\":@openzeppelin-upgrades/contracts/=lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/contracts/\",\":@openzeppelin-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/\",\":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":@openzeppelin/contracts/=lib/eigenlayer-middleware/lib/openzeppelin-contracts/contracts/\",\":ds-test/=lib/eigenlayer-middleware/lib/ds-test/src/\",\":eigenlayer-contracts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/\",\":eigenlayer-core-contracts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/contracts/core/\",\":eigenlayer-core/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/\",\":eigenlayer-middleware/=lib/eigenlayer-middleware/src/\",\":eigenlayer-scripts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/script/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts-upgradeable-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":openzeppelin/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/contracts/\"]},\"sources\":{\"lib/eigenlayer-middleware/src/interfaces/IBLSApkRegistry.sol\":{\"keccak256\":\"0xc07a5edfd95ab4f16f16a8dc8e76eadf4b0e90fe49db90540d01daaad86898c5\",\"license\":\"BUSL-1.1\",\"urls\":[\"bzz-raw://52b53266450a53da641e82d8ae3be93c5e09f8342b4ea0cc96bb9038d8406354\",\"dweb:/ipfs/QmVuoiQyqPTLCGnyt8zDaxiyaj4ETdgTGKv4MDHWzqEDjp\"]},\"lib/eigenlayer-middleware/src/interfaces/IRegistry.sol\":{\"keccak256\":\"0x51426a17fb7e54bd3720e2890104e97a8559a13ff248b3d6b840916751c143d3\",\"license\":\"BUSL-1.1\",\"urls\":[\"bzz-raw://01f91289e6100d528cb8b318cb14ff22a0bc52882c9d4db41585e030cc9ddc25\",\"dweb:/ipfs/Qmb22nqGrsrtNovHRwbMCvDHGENuxAgrWu3Db4p7Er2MHY\"]},\"lib/eigenlayer-middleware/src/libraries/BN254.sol\":{\"keccak256\":\"0xb428c8d0c3b325507a88a61a80115493eb88606ccc19ed64a31e11294ab853b3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d7b6fb935bfe0494e6ff970c8f30a86d5f4cf5c3e0967300c28cd383c043acae\",\"dweb:/ipfs/QmUHfFZaVjLPXhkBmcxrZhAHZaSFQDqXtrLGpjGBQBa5Ki\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.27+commit.40a35a09"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"operator","type":"address","indexed":true},{"internalType":"struct BN254.G1Point","name":"pubkeyG1","type":"tuple","components":[{"internalType":"uint256","name":"X","type":"uint256"},{"internalType":"uint256","name":"Y","type":"uint256"}],"indexed":false},{"internalType":"struct BN254.G2Point","name":"pubkeyG2","type":"tuple","components":[{"internalType":"uint256[2]","name":"X","type":"uint256[2]"},{"internalType":"uint256[2]","name":"Y","type":"uint256[2]"}],"indexed":false}],"type":"event","name":"NewPubkeyRegistration","anonymous":false},{"inputs":[{"internalType":"address","name":"operator","type":"address","indexed":false},{"internalType":"bytes32","name":"operatorId","type":"bytes32","indexed":false},{"internalType":"bytes","name":"quorumNumbers","type":"bytes","indexed":false}],"type":"event","name":"OperatorAddedToQuorums","anonymous":false},{"inputs":[{"internalType":"address","name":"operator","type":"address","indexed":false},{"internalType":"bytes32","name":"operatorId","type":"bytes32","indexed":false},{"internalType":"bytes","name":"quorumNumbers","type":"bytes","indexed":false}],"type":"event","name":"OperatorRemovedFromQuorums","anonymous":false},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"quorumNumbers","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"deregisterOperator"},{"inputs":[{"internalType":"uint8","name":"quorumNumber","type":"uint8"}],"stateMutability":"view","type":"function","name":"getApk","outputs":[{"internalType":"struct BN254.G1Point","name":"","type":"tuple","components":[{"internalType":"uint256","name":"X","type":"uint256"},{"internalType":"uint256","name":"Y","type":"uint256"}]}]},{"inputs":[{"internalType":"uint8","name":"quorumNumber","type":"uint8"},{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"uint256","name":"index","type":"uint256"}],"stateMutability":"view","type":"function","name":"getApkHashAtBlockNumberAndIndex","outputs":[{"internalType":"bytes24","name":"","type":"bytes24"}]},{"inputs":[{"internalType":"bytes","name":"quorumNumbers","type":"bytes"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"stateMutability":"view","type":"function","name":"getApkIndicesAtBlockNumber","outputs":[{"internalType":"uint32[]","name":"","type":"uint32[]"}]},{"inputs":[{"internalType":"uint8","name":"quorumNumber","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"}],"stateMutability":"view","type":"function","name":"getApkUpdateAtIndex","outputs":[{"internalType":"struct IBLSApkRegistry.ApkUpdate","name":"","type":"tuple","components":[{"internalType":"bytes24","name":"apkHash","type":"bytes24"},{"internalType":"uint32","name":"updateBlockNumber","type":"uint32"},{"internalType":"uint32","name":"nextUpdateBlockNumber","type":"uint32"}]}]},{"inputs":[{"internalType":"bytes32","name":"pubkeyHash","type":"bytes32"}],"stateMutability":"view","type":"function","name":"getOperatorFromPubkeyHash","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"stateMutability":"view","type":"function","name":"getOperatorId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"stateMutability":"view","type":"function","name":"getRegisteredPubkey","outputs":[{"internalType":"struct BN254.G1Point","name":"","type":"tuple","components":[{"internalType":"uint256","name":"X","type":"uint256"},{"internalType":"uint256","name":"Y","type":"uint256"}]},{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[{"internalType":"uint8","name":"quorumNumber","type":"uint8"}],"stateMutability":"nonpayable","type":"function","name":"initializeQuorum"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"stateMutability":"view","type":"function","name":"operatorToPubkeyHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[{"internalType":"bytes32","name":"pubkeyHash","type":"bytes32"}],"stateMutability":"view","type":"function","name":"pubkeyHashToOperator","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"struct IBLSApkRegistry.PubkeyRegistrationParams","name":"params","type":"tuple","components":[{"internalType":"struct BN254.G1Point","name":"pubkeyRegistrationSignature","type":"tuple","components":[{"internalType":"uint256","name":"X","type":"uint256"},{"internalType":"uint256","name":"Y","type":"uint256"}]},{"internalType":"struct BN254.G1Point","name":"pubkeyG1","type":"tuple","components":[{"internalType":"uint256","name":"X","type":"uint256"},{"internalType":"uint256","name":"Y","type":"uint256"}]},{"internalType":"struct BN254.G2Point","name":"pubkeyG2","type":"tuple","components":[{"internalType":"uint256[2]","name":"X","type":"uint256[2]"},{"internalType":"uint256[2]","name":"Y","type":"uint256[2]"}]}]},{"internalType":"struct BN254.G1Point","name":"pubkeyRegistrationMessageHash","type":"tuple","components":[{"internalType":"uint256","name":"X","type":"uint256"},{"internalType":"uint256","name":"Y","type":"uint256"}]}],"stateMutability":"nonpayable","type":"function","name":"registerBLSPublicKey","outputs":[{"internalType":"bytes32","name":"operatorId","type":"bytes32"}]},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"quorumNumbers","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"registerOperator"},{"inputs":[],"stateMutability":"view","type":"function","name":"registryCoordinator","outputs":[{"internalType":"address","name":"","type":"address"}]}],"devdoc":{"kind":"dev","methods":{"deregisterOperator(address,bytes)":{"details":"access restricted to the RegistryCoordinatorPreconditions (these are assumed, not validated in this contract): 1) `quorumNumbers` has no duplicates 2) `quorumNumbers.length` != 0 3) `quorumNumbers` is ordered in ascending order 4) the operator is not already deregistered 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for","params":{"operator":"The address of the operator to deregister.","quorumNumbers":"The quorum numbers the operator is deregistering from, where each byte is an 8 bit integer quorumNumber."}},"getApkHashAtBlockNumberAndIndex(uint8,uint32,uint256)":{"params":{"blockNumber":"is the number of the block for which the latest ApkHash will be retrieved","index":"is the index of the apkUpdate being retrieved from the list of quorum apkUpdates in storage","quorumNumber":"is the quorum whose ApkHash is being retrieved"}},"getOperatorId(address)":{"details":"Returns zero in the event that the `operator` has never registered for the AVS"},"getRegisteredPubkey(address)":{"details":"Reverts if the operator has not registered a valid pubkey"},"initializeQuorum(uint8)":{"params":{"quorumNumber":"The number of the new quorum"}},"registerBLSPublicKey(address,((uint256,uint256),(uint256,uint256),(uint256[2],uint256[2])),(uint256,uint256))":{"params":{"operator":"is the operator for whom the key is being registered","params":"contains the G1 & G2 public keys of the operator, and a signature proving their ownership","pubkeyRegistrationMessageHash":"is a hash that the operator must sign to prove key ownership"}},"registerOperator(address,bytes)":{"details":"access restricted to the RegistryCoordinatorPreconditions (these are assumed, not validated in this contract): 1) `quorumNumbers` has no duplicates 2) `quorumNumbers.length` != 0 3) `quorumNumbers` is ordered in ascending order 4) the operator is not already registered","params":{"operator":"The address of the operator to register.","quorumNumbers":"The quorum numbers the operator is registering for, where each byte is an 8 bit integer quorumNumber."}}},"version":1},"userdoc":{"kind":"user","methods":{"deregisterOperator(address,bytes)":{"notice":"Deregisters the `operator`'s pubkey for the specified `quorumNumbers`."},"getApk(uint8)":{"notice":"Returns the current APK for the provided `quorumNumber `"},"getApkHashAtBlockNumberAndIndex(uint8,uint32,uint256)":{"notice":"get 24 byte hash of the apk of `quorumNumber` at `blockNumber` using the provided `index`; called by checkSignatures in BLSSignatureChecker.sol."},"getApkIndicesAtBlockNumber(bytes,uint256)":{"notice":"Returns the index of the quorumApk index at `blockNumber` for the provided `quorumNumber`"},"getApkUpdateAtIndex(uint8,uint256)":{"notice":"Returns the `ApkUpdate` struct at `index` in the list of APK updates for the `quorumNumber`"},"getOperatorFromPubkeyHash(bytes32)":{"notice":"Returns the operator address for the given `pubkeyHash`"},"getOperatorId(address)":{"notice":"returns the ID used to identify the `operator` within this AVS."},"getRegisteredPubkey(address)":{"notice":"Returns the pubkey and pubkey hash of an operator"},"initializeQuorum(uint8)":{"notice":"Initializes a new quorum by pushing its first apk update"},"operatorToPubkeyHash(address)":{"notice":"mapping from operator address to pubkey hash. Returns *zero* if the `operator` has never registered, and otherwise returns the hash of the public key of the operator."},"pubkeyHashToOperator(bytes32)":{"notice":"mapping from pubkey hash to operator address. Returns *zero* if no operator has ever registered the public key corresponding to `pubkeyHash`, and otherwise returns the (unique) registered operator who owns the BLS public key that is the preimage of `pubkeyHash`."},"registerBLSPublicKey(address,((uint256,uint256),(uint256,uint256),(uint256[2],uint256[2])),(uint256,uint256))":{"notice":"Called by the RegistryCoordinator register an operator as the owner of a BLS public key."},"registerOperator(address,bytes)":{"notice":"Registers the `operator`'s pubkey for the specified `quorumNumbers`."}},"version":1}},"settings":{"remappings":["@openzeppelin-upgrades-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/","@openzeppelin-upgrades/contracts/=lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/contracts/","@openzeppelin-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@openzeppelin/contracts/=lib/eigenlayer-middleware/lib/openzeppelin-contracts/contracts/","ds-test/=lib/eigenlayer-middleware/lib/ds-test/src/","eigenlayer-contracts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/","eigenlayer-core-contracts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/contracts/core/","eigenlayer-core/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/","eigenlayer-middleware/=lib/eigenlayer-middleware/src/","eigenlayer-scripts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/script/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","openzeppelin-contracts-upgradeable-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/","openzeppelin-contracts/=lib/openzeppelin-contracts/","openzeppelin/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/contracts/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"lib/eigenlayer-middleware/src/interfaces/IBLSApkRegistry.sol":"IBLSApkRegistry"},"evmVersion":"paris","libraries":{}},"sources":{"lib/eigenlayer-middleware/src/interfaces/IBLSApkRegistry.sol":{"keccak256":"0xc07a5edfd95ab4f16f16a8dc8e76eadf4b0e90fe49db90540d01daaad86898c5","urls":["bzz-raw://52b53266450a53da641e82d8ae3be93c5e09f8342b4ea0cc96bb9038d8406354","dweb:/ipfs/QmVuoiQyqPTLCGnyt8zDaxiyaj4ETdgTGKv4MDHWzqEDjp"],"license":"BUSL-1.1"},"lib/eigenlayer-middleware/src/interfaces/IRegistry.sol":{"keccak256":"0x51426a17fb7e54bd3720e2890104e97a8559a13ff248b3d6b840916751c143d3","urls":["bzz-raw://01f91289e6100d528cb8b318cb14ff22a0bc52882c9d4db41585e030cc9ddc25","dweb:/ipfs/Qmb22nqGrsrtNovHRwbMCvDHGENuxAgrWu3Db4p7Er2MHY"],"license":"BUSL-1.1"},"lib/eigenlayer-middleware/src/libraries/BN254.sol":{"keccak256":"0xb428c8d0c3b325507a88a61a80115493eb88606ccc19ed64a31e11294ab853b3","urls":["bzz-raw://d7b6fb935bfe0494e6ff970c8f30a86d5f4cf5c3e0967300c28cd383c043acae","dweb:/ipfs/QmUHfFZaVjLPXhkBmcxrZhAHZaSFQDqXtrLGpjGBQBa5Ki"],"license":"MIT"}},"version":1},"id":126} \ No newline at end of file