diff --git a/Cargo.lock b/Cargo.lock index 3f830afb5..376fec1f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1963,13 +1963,6 @@ dependencies = [ [[package]] name = "eigen-chainio-utils" version = "0.0.1-alpha" -dependencies = [ - "ark-bn254", - "ark-ff 0.4.2", - "eigen-crypto-bls", - "eigen-crypto-bn254", - "eigen-utils", -] [[package]] name = "eigen-cli" @@ -2001,9 +1994,7 @@ dependencies = [ "alloy-signer", "alloy-signer-local", "alloy-transport-http", - "ark-bn254", "ark-ff 0.4.2", - "eigen-chainio-utils", "eigen-client-elcontracts", "eigen-crypto-bls", "eigen-logging", @@ -2079,12 +2070,9 @@ dependencies = [ "ark-bn254", "ark-ec", "ark-ff 0.4.2", + "ark-std 0.4.0", "eigen-crypto-bn254", "eigen-utils", - "ethers", - "eyre", - "hex", - "num-bigint 0.4.5", "rand", "thiserror", "tokio", @@ -2094,30 +2082,13 @@ dependencies = [ name = "eigen-crypto-bn254" version = "0.0.1-alpha" dependencies = [ - "alloy-primitives", "ark-bn254", - "ark-ff 0.4.2", - "rand", - "thiserror", - "tokio", -] - -[[package]] -name = "eigen-crypto-keystore" -version = "0.0.1-alpha" -dependencies = [ - "aes", "ark-ec", "ark-ff 0.4.2", - "ctr", - "eigen-crypto-bls", - "eth-keystore", - "ethers", - "eyre", + "num-bigint 0.4.5", "rand", - "scrypt", - "serde", - "serde_json", + "rust-bls-bn254", + "tokio", ] [[package]] @@ -2617,7 +2588,6 @@ dependencies = [ "const-hex", "enr", "ethers-core", - "futures-channel", "futures-core", "futures-timer", "futures-util", @@ -2722,15 +2692,23 @@ version = "0.0.1-alpha" dependencies = [ "alloy-primitives", "alloy-provider", + "alloy-signer-local", "ark-bn254", + "ark-ec", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "eigen-chainio-utils", "eigen-client-avsregistry", "eigen-client-elcontracts", "eigen-crypto-bls", "eigen-crypto-bn254", + "eigen-logging", "eigen-testing-utils", + "eigen-types", "eigen-utils", "eyre", + "lazy_static", "tokio", ] @@ -3763,9 +3741,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" @@ -4956,6 +4934,19 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" +[[package]] +name = "rust-bls-bn254" +version = "0.1.0" +source = "git+https://github.com/Layr-Labs/rust-bls-bn254.git?rev=bd712a7#bd712a7d556f7869a423956deee702f4a5546aa8" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff 0.4.2", + "ark-std 0.4.0", + "num-bigint 0.4.5", + "sha2", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -5204,7 +5195,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" dependencies = [ "hmac", - "password-hash", "pbkdf2 0.11.0", "salsa20", "sha2", diff --git a/Cargo.toml b/Cargo.toml index b4d2ead67..3f2feda0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ members = [ "crates/crypto/bn254/", "crates/utils/", "crates/crypto/bls/", - "crates/crypto/keystore/", "crates/eigen-cli/", "crates/metrics/collectors/economic/", "crates/metrics/collectors/rpc_calls/", @@ -49,6 +48,8 @@ rust.rust_2018_idioms = { level = "deny", priority = -1 } rustdoc.all = "warn" [workspace.dependencies] +ark-bn254 = "0.4.0" +ark-ec = "0.4.2" ark-ff = "0.4.0" async-trait = "0.1.81" aws-config = "1.5.4" @@ -63,7 +64,6 @@ eigen-client-fireblocks = { path = "crates/chainio/clients/fireblocks" } eigen-contract-bindings = { path = "crates/contracts/bindings/" } eigen-crypto-bls = { path = "crates/crypto/bls/" } eigen-crypto-bn254 = { path = "crates/crypto/bn254/" } -eigen-crypto-keystore = { path = "crates/crypto/keystore/" } eigen-metrics = { version = "0.0.1-alpha", path = "crates/metrics/" } eigen-metrics-collectors-economic = { path = "crates/metrics/collectors/economic" } eigen-metrics-collectors-rpc-calls = { path = "crates/metrics/collectors/rpc_calls" } @@ -94,14 +94,14 @@ reth = { git = "https://github.com/paradigmxyz/reth" } serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.121" syn = "2.0" -testcontainers = "0.20.1" thiserror = "1.0" tokio = { version = "1.37.0", features = ["test-util", "full", "sync"] } tracing = "0.1.40" tracing-subscriber = { version = "0.3", features = ["json"] } url = "2.5.2" - -#misc +testcontainers = "0.20.1" +rust-bls-bn254 = {git = "https://github.com/Layr-Labs/rust-bls-bn254.git", rev = "be3ef87", features = ["std"] } +#misc parking_lot = "0.12" #alloy diff --git a/crates/chainio/clients/avsregistry/Cargo.toml b/crates/chainio/clients/avsregistry/Cargo.toml index 9770da1cb..6387d8716 100644 --- a/crates/chainio/clients/avsregistry/Cargo.toml +++ b/crates/chainio/clients/avsregistry/Cargo.toml @@ -19,10 +19,8 @@ eigen-types.workspace = true eigen-crypto-bls.workspace = true ark-ff.workspace = true eigen-client-elcontracts.workspace = true -eigen-chainio-utils.workspace = true eigen-utils.workspace = true eigen-logging.workspace = true -ark-bn254 = "0.4.0" thiserror.workspace = true tracing.workspace = true alloy-network.workspace = true diff --git a/crates/chainio/clients/avsregistry/src/error.rs b/crates/chainio/clients/avsregistry/src/error.rs index 3010cd709..2545b8775 100644 --- a/crates/chainio/clients/avsregistry/src/error.rs +++ b/crates/chainio/clients/avsregistry/src/error.rs @@ -1,5 +1,6 @@ use alloy_contract::Error as AlloyError; use eigen_client_elcontracts::error::ElContractsError; +use eigen_crypto_bls::error::BlsError; use thiserror::Error; /// Error returned by AvsRegistry @@ -136,6 +137,10 @@ pub enum AvsRegistryError { /// ElContractsError compatibility #[error("ElContractsError: {0}")] ElContractsError(String), + + /// BlsError compatibility + #[error("BlsError :{0}")] + BlsError(String), } impl From for AvsRegistryError { @@ -143,3 +148,9 @@ impl From for AvsRegistryError { AvsRegistryError::ElContractsError(err.to_string()) } } + +impl From for AvsRegistryError { + fn from(err: BlsError) -> Self { + AvsRegistryError::BlsError(err.to_string()) + } +} diff --git a/crates/chainio/clients/avsregistry/src/writer.rs b/crates/chainio/clients/avsregistry/src/writer.rs index 2109524f8..bb3b3bb0c 100644 --- a/crates/chainio/clients/avsregistry/src/writer.rs +++ b/crates/chainio/clients/avsregistry/src/writer.rs @@ -1,23 +1,16 @@ -use alloy_signer::SignerSync; +use alloy_signer::Signer; use alloy_signer_local::PrivateKeySigner; -use ark_bn254::G1Projective; -use eigen_chainio_utils::{ - convert_bn254_to_ark, convert_to_bn254_g1_point, convert_to_bn254_g2_point, -}; use eigen_client_elcontracts::reader::ELChainReader; use eigen_logging::tracing_logger::TracingLogger; -use std::str::FromStr; - -use eigen_utils::binding::{ - BLSApkRegistry::{G1Point, PubkeyRegistrationParams}, - RegistryCoordinator::{ - self, G1Point as RegistryG1Point, G2Point as RegistryG2Point, - PubkeyRegistrationParams as RegistryPubkeyRegistrationParams, - }, +use eigen_utils::binding::RegistryCoordinator::{ + self, G1Point as RegistryG1Point, G2Point as RegistryG2Point, PubkeyRegistrationParams, }; +use std::str::FromStr; use alloy_primitives::{Address, Bytes, FixedBytes, TxHash, U256}; -use eigen_crypto_bls::attestation::KeyPair; +use eigen_crypto_bls::{ + alloy_g1_point_to_g1_affine, convert_to_g1_point, convert_to_g2_point, BlsKeyPair, +}; use tracing::info; use RegistryCoordinator::SignatureWithSaltAndExpiry; @@ -27,6 +20,9 @@ use eigen_utils::{ get_provider, get_signer, }; +/// Gas limit for registerOperator in [`RegistryCoordinator`] +pub const GAS_LIMIT_REGISTER_OPERATOR_REGISTRY_COORDINATOR: u128 = 2000000; + /// AvsRegistry Writer #[derive(Debug)] pub struct AvsRegistryChainWriter { @@ -126,7 +122,7 @@ impl AvsRegistryChainWriter { /// Register operator in quorum with avs registry coordinator pub async fn register_operator_in_quorum_with_avs_registry_coordinator( &self, - bls_key_pair: KeyPair, + bls_key_pair: BlsKeyPair, operator_to_avs_registration_sig_salt: FixedBytes<32>, operator_to_avs_registration_sig_expiry: U256, quorum_numbers: Bytes, @@ -134,7 +130,6 @@ impl AvsRegistryChainWriter { ) -> Result { let provider = get_signer(self.signer.clone(), &self.provider); let wallet = PrivateKeySigner::from_str(&self.signer).expect("failed to generate wallet "); - // tracing info info!(avs_service_manager = %self.service_manager_addr, operator= %wallet.address(),quorum_numbers = ?quorum_numbers,"quorum_numbers,registering operator with the AVS's registry coordinator"); let contract_registry_coordinator = @@ -149,32 +144,24 @@ impl AvsRegistryChainWriter { let RegistryCoordinator::pubkeyRegistrationMessageHashReturn { _0: g1_hashes_msg_to_sign, } = g1_hashes_msg_to_sign_return; - let signed_msg = convert_to_bn254_g1_point( - bls_key_pair - .sign_hashes_to_curve_message(G1Projective::from( - convert_bn254_to_ark(G1Point { - X: g1_hashes_msg_to_sign.X, - Y: g1_hashes_msg_to_sign.Y, - }) - .point, - )) - .sig(), - ); + let sig = bls_key_pair + .sign_hashed_to_curve_message(alloy_g1_point_to_g1_affine( + g1_hashes_msg_to_sign, + )) + .g1_point(); + let alloy_g1_point_signed_msg = convert_to_g1_point(sig.g1())?; - let g1_pubkey_bn254 = convert_to_bn254_g1_point(bls_key_pair.get_pub_key_g1()); - let g2_projective = bls_key_pair - .get_pub_key_g2() - .expect("Failed to get g2 projective"); + let g1_pub_key_bn254 = convert_to_g1_point(bls_key_pair.public_key().g1())?; - let g2_pubkey_bn254 = convert_to_bn254_g2_point(g2_projective); + let g2_pub_key_bn254 = convert_to_g2_point(bls_key_pair.public_key_g2().g2())?; let pub_key_reg_params = PubkeyRegistrationParams { - pubkeyRegistrationSignature: signed_msg, - pubkeyG1: g1_pubkey_bn254, - pubkeyG2: g2_pubkey_bn254, + pubkeyRegistrationSignature: alloy_g1_point_signed_msg, + pubkeyG1: g1_pub_key_bn254, + pubkeyG2: g2_pub_key_bn254, }; - let msg_to_sign_result = self + let msg_to_sign = self .el_reader .calculate_operator_avs_registration_digest_hash( wallet.address(), @@ -182,52 +169,48 @@ impl AvsRegistryChainWriter { operator_to_avs_registration_sig_salt, operator_to_avs_registration_sig_expiry, ) - .await; - - match msg_to_sign_result { - Ok(msg_to_sign) => { - let operator_signature = wallet - .sign_message_sync(msg_to_sign.as_slice()) - .expect("failed to sign message"); - - let operator_signature_with_salt_and_expiry = SignatureWithSaltAndExpiry { - signature: operator_signature.as_bytes().into(), - salt: operator_to_avs_registration_sig_salt, - expiry: operator_to_avs_registration_sig_expiry, - }; - - let contract_call = contract_registry_coordinator.registerOperator( - quorum_numbers.clone(), - socket, - RegistryPubkeyRegistrationParams { - pubkeyRegistrationSignature: RegistryG1Point { - X: pub_key_reg_params.pubkeyRegistrationSignature.X, - Y: pub_key_reg_params.pubkeyRegistrationSignature.Y, - }, - pubkeyG1: RegistryG1Point { - X: pub_key_reg_params.pubkeyG1.X, - Y: pub_key_reg_params.pubkeyG1.Y, - }, - pubkeyG2: RegistryG2Point { - X: pub_key_reg_params.pubkeyG2.X, - Y: pub_key_reg_params.pubkeyG2.Y, - }, - }, - operator_signature_with_salt_and_expiry, - ); - - let tx_call = contract_call.gas(2000000); - let tx_result = tx_call.send().await; - - match tx_result { - Ok(tx) => { - info!(tx_hash = ?tx,"succesfully deregistered operator with the AVS's registry coordinator" ); - return Ok(*tx.tx_hash()); - } - Err(e) => Err(AvsRegistryError::AlloyContractError(e)), - } + .await?; + + let operator_signature = wallet + .sign_hash(&msg_to_sign) + .await + .expect("failed to sign message"); + + let operator_signature_with_salt_and_expiry = SignatureWithSaltAndExpiry { + signature: operator_signature.as_bytes().into(), + salt: operator_to_avs_registration_sig_salt, + expiry: operator_to_avs_registration_sig_expiry, + }; + + let contract_call = contract_registry_coordinator.registerOperator( + quorum_numbers.clone(), + socket, + PubkeyRegistrationParams { + pubkeyRegistrationSignature: RegistryG1Point { + X: pub_key_reg_params.pubkeyRegistrationSignature.X, + Y: pub_key_reg_params.pubkeyRegistrationSignature.Y, + }, + pubkeyG1: RegistryG1Point { + X: pub_key_reg_params.pubkeyG1.X, + Y: pub_key_reg_params.pubkeyG1.Y, + }, + pubkeyG2: RegistryG2Point { + X: pub_key_reg_params.pubkeyG2.X, + Y: pub_key_reg_params.pubkeyG2.Y, + }, + }, + operator_signature_with_salt_and_expiry, + ); + + let tx_call = contract_call.gas(GAS_LIMIT_REGISTER_OPERATOR_REGISTRY_COORDINATOR); + let tx_result = tx_call.send().await; + + match tx_result { + Ok(tx) => { + info!(tx_hash = ?tx,"Succesfully deregistered operator with the AVS's registry coordinator" ); + Ok(*tx.tx_hash()) } - Err(e) => Err(AvsRegistryError::ElContractsError(e.to_string())), + Err(e) => Err(AvsRegistryError::AlloyContractError(e)), } } Err(_) => Err(AvsRegistryError::PubKeyRegistrationMessageHash), diff --git a/crates/chainio/clients/elcontracts/src/writer.rs b/crates/chainio/clients/elcontracts/src/writer.rs index e46229f25..dee68d7b1 100644 --- a/crates/chainio/clients/elcontracts/src/writer.rs +++ b/crates/chainio/clients/elcontracts/src/writer.rs @@ -14,6 +14,9 @@ use eigen_utils::{ use tracing::info; use DelegationManager::OperatorDetails; +/// Gas limit for registerAsOperator in [`DelegationManager`] +pub const GAS_LIMIT_REGISTER_AS_OPERATOR_DELEGATION_MANAGER: u128 = 300000; + #[derive(Debug, Clone)] pub struct ELChainWriter { delegation_manager: Address, @@ -61,12 +64,12 @@ impl ELChainWriter { Some(metadata) => { let contract_call = contract_delegation_manager.registerAsOperator(op_details, metadata); - contract_call.gas(130000) + contract_call.gas(300000) } None => { let contract_call = contract_delegation_manager.registerAsOperator(op_details, "".to_string()); - contract_call.gas(130000) + contract_call.gas(300000) } }; let binding_tx_result = binding.send().await; @@ -147,7 +150,6 @@ impl ELChainWriter { .el_chain_reader .get_strategy_and_underlying_erc20_token(strategy_addr) .await; - match tokens_result { Ok(tokens) => { let (_, underlying_token_contract, underlying_token) = tokens; diff --git a/crates/chainio/utils/Cargo.toml b/crates/chainio/utils/Cargo.toml index c844b0791..beac95c7b 100644 --- a/crates/chainio/utils/Cargo.toml +++ b/crates/chainio/utils/Cargo.toml @@ -9,8 +9,3 @@ repository.workspace = true license-file.workspace = true [dependencies] -ark-bn254 = "0.4.0" -ark-ff.workspace = true -eigen-crypto-bls.workspace = true -eigen-crypto-bn254.workspace = true -eigen-utils.workspace = true \ No newline at end of file diff --git a/crates/chainio/utils/src/lib.rs b/crates/chainio/utils/src/lib.rs index 0ed1dd41c..042d7a137 100644 --- a/crates/chainio/utils/src/lib.rs +++ b/crates/chainio/utils/src/lib.rs @@ -2,38 +2,3 @@ html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" )] -#![cfg_attr(not(test), warn(unused_crate_dependencies))] - -use ark_bn254::G1Projective; -use ark_bn254::G2Projective; -use ark_ff::BigInteger256; -use eigen_crypto_bls::attestation::G1Point as AttestationG1Point; -use eigen_crypto_bn254::utils::biginteger256_to_u256; -use eigen_crypto_bn254::utils::u256_to_bigint256; -use eigen_utils::binding::BLSApkRegistry::{G1Point, G2Point}; - -pub fn convert_bn254_to_ark(g1_point: G1Point) -> AttestationG1Point { - AttestationG1Point::new(u256_to_bigint256(g1_point.X), u256_to_bigint256(g1_point.Y)) -} - -pub fn convert_to_bn254_g1_point(g1: G1Projective) -> G1Point { - let x: BigInteger256 = g1.x.into(); - let y: BigInteger256 = g1.y.into(); - - G1Point { - X: biginteger256_to_u256(x), - Y: biginteger256_to_u256(y), - } -} - -pub fn convert_to_bn254_g2_point(g2: G2Projective) -> G2Point { - let x_0: BigInteger256 = g2.x.c0.into(); - let x_1: BigInteger256 = g2.x.c1.into(); - let y_0: BigInteger256 = g2.y.c0.into(); - let y_1: BigInteger256 = g2.y.c1.into(); - - G2Point { - X: [biginteger256_to_u256(x_0), biginteger256_to_u256(x_1)], - Y: [biginteger256_to_u256(y_0), biginteger256_to_u256(y_1)], - } -} diff --git a/crates/crypto/bls/Cargo.toml b/crates/crypto/bls/Cargo.toml index d181f8f1c..223523ba7 100644 --- a/crates/crypto/bls/Cargo.toml +++ b/crates/crypto/bls/Cargo.toml @@ -9,18 +9,14 @@ repository.workspace = true license-file.workspace = true [dependencies] -ark-bn254 = "0.4.0" +ark-bn254.workspace = true ark-ff.workspace = true eigen-crypto-bn254.workspace = true thiserror.workspace = true -ark-ec = "0.4.2" +ark-ec.workspace = true alloy-primitives.workspace = true -hex = "0.4.3" eigen-utils.workspace = true -ethers = { version = "2.0", features = ["rustls", "ws"] } -eyre = "0.6.8" -num-bigint = "0.4.4" - +ark-std = { version = "0.4.0", default-features = false } [dev-dependencies] rand = "0.8.4" tokio = { workspace = true, features = ["full"] } diff --git a/crates/crypto/bls/README.md b/crates/crypto/bls/README.md index 6b0e7a160..da57cf08c 100644 --- a/crates/crypto/bls/README.md +++ b/crates/crypto/bls/README.md @@ -1 +1,14 @@ -# eigen Bls utilities +# Eigen Layer Bls + +This crate contains the following utilities: + +- New bls key pair generation +- Get Public Key on G1 and G2 +- Helper functions to convert Arkworks parameters to alloy compatible . Ex: + - convert_to_g1_point : Converts G1Affine to Alloy compatible G1Point + - convert_to_g2_point : Converts G2Affine to Alloy compatible G2Point + - alloy_g1_point_to_g1_affine: Converts Alloy G1Point to G1Affine +- Signing a message using the keypair + +## Example +- [Registering an operator](https://github.com/Layr-Labs/eigensdk-rs/blob/main/examples/avsregistry-write/examples/register_operator_in_quorum_with_avs_registry_coordinator.rs) \ No newline at end of file diff --git a/crates/crypto/bls/src/attestation.rs b/crates/crypto/bls/src/attestation.rs deleted file mode 100644 index 927c178ed..000000000 --- a/crates/crypto/bls/src/attestation.rs +++ /dev/null @@ -1,318 +0,0 @@ -use crate::error::BlsError; -use alloy_primitives::U256; -use ark_bn254::{Bn254, Fq, Fq2, Fr, G1Affine, G1Projective, G2Projective}; -use ark_ec::{pairing::Pairing, CurveGroup}; -use ark_ff::{BigInteger256, Field, One, PrimeField}; -use eigen_crypto_bn254::utils::{ - get_g2_generator, mul_by_generator_g1, mul_by_generator_g2, u256_to_bigint256, -}; -use hex::FromHex; -use std::fmt::Write; -use std::ops::{Add, Mul}; -pub fn new_fp_element(x: BigInteger256) -> Fq { - Fq::from(x) -} - -fn new_fp2_element(a: BigInteger256, b: BigInteger256) -> Fq2 { - Fq2::new(Fq::from(a), Fq::from(b)) -} - -pub type PrivateKey = Fr; - -#[derive(Debug, Clone)] -pub struct Signature { - g1_point: G1Point, -} - -impl Signature { - pub fn new_zero_signature() -> Self { - Signature { - g1_point: G1Point::new_zero_g1_point(), - } - } - - pub fn get_g1_point(&self) -> G1Point { - self.g1_point.clone() - } - - pub fn sig(&self) -> G1Projective { - self.g1_point.point - } - - /// Verify BLS signature using BN254 - /// TODO : test this . 99% this is wrong - pub fn verify_signature(&self, pubkey: G2Projective, message: &[u8; 32]) -> bool { - let msg_hash = hash_to_g1(message); - let g1_affine = self.g1_point.point.into_affine(); - - let g2_affine = pubkey.into_affine(); - - let generator = get_g2_generator().unwrap(); - let pairing_left = Bn254::pairing(g1_affine, generator); - - let pairing_right = Bn254::pairing(msg_hash, g2_affine); - - pairing_left == pairing_right - } -} - -fn hash_to_g1(digest: &[u8; 32]) -> G1Affine { - let one = Fq::one(); - let three = Fq::from(3u64); - let mut x = Fq::from_le_bytes_mod_order(digest); - - loop { - let x_cubed = x.square() * x; - let y_squared = x_cubed + three; - - if let Some(y) = y_squared.sqrt() { - let point = G1Projective::new(x, y, Fq::one()); - return point.into_affine(); - } else { - x += &one; - } - } -} - -#[derive(Debug, Default)] -pub struct KeyPair { - priv_key: PrivateKey, - pub_key: G1Projective, -} - -impl KeyPair { - pub fn new(key: PrivateKey) -> Result { - let priv_key_projective_cconfig_result = mul_by_generator_g1(key); - - match priv_key_projective_cconfig_result { - Ok(priv_key_projective_cconfig) => Ok(Self { - priv_key: key, - pub_key: priv_key_projective_cconfig, - }), - Err(_) => Err(BlsError::MulByG1Projective), - } - } - - pub fn from_string(s: String) -> Result { - let bigint_key = hex_string_to_biginteger256(&s); - let key = Fr::from(bigint_key); - KeyPair::new(key) - } - - pub fn sign_hashes_to_curve_message(&self, g1_hashes_msg: G1Projective) -> Signature { - let sig = g1_hashes_msg.mul(self.priv_key); - - Signature { - g1_point: G1Point { point: sig }, - } - } - - pub fn get_pub_key_g1(&self) -> G1Projective { - self.pub_key - } - - pub fn get_pub_key_g2(&self) -> Result { - let mul_result = mul_by_generator_g2(self.priv_key); - - match mul_result { - Ok(mul) => Ok(mul), - Err(_) => Err(BlsError::MulByG2Projective), - } - } - - pub fn priv_key(&self) -> PrivateKey { - self.priv_key - } -} - -pub fn bigint_to_hex(bigint: &BigInteger256) -> String { - let mut hex_string = String::new(); - for part in bigint.0.iter().rev() { - write!(&mut hex_string, "{:016x}", part).unwrap(); - } - hex_string -} - -pub fn hex_string_to_biginteger256(hex_str: &str) -> BigInteger256 { - let bytes = Vec::from_hex(hex_str).unwrap(); - - assert!(bytes.len() <= 32, "Byte length exceeds 32 bytes"); - - let mut padded_bytes = [0u8; 32]; - let start = 32 - bytes.len(); - padded_bytes[start..].copy_from_slice(&bytes); - - let mut limbs = [0u64; 4]; - for (i, chunk) in padded_bytes.chunks(8).rev().enumerate() { - let mut array = [0u8; 8]; - let len = chunk.len().min(8); - array[..len].copy_from_slice(&chunk[..len]); // Copy the bytes into the fixed-size array - limbs[i] = u64::from_be_bytes(array); - } - - BigInteger256::new(limbs) -} - -#[derive(Debug, Clone)] -pub struct G1Point { - pub point: G1Projective, -} - -#[derive(Debug, Clone)] -pub struct G2Point { - pub point: G2Projective, -} - -impl G2Point { - // Function to create a new G2Point from x and y coordinates, where each coordinate is a pair of BigIntegers - pub fn new(x: (BigInteger256, BigInteger256), y: (BigInteger256, BigInteger256)) -> Self { - // Convert x and y to Fq2 elements - let x_elem = new_fp2_element(x.1, x.0); - let y_elem = new_fp2_element(y.1, y.0); - - // Create a new G2 point in projective coordinates - let point = G2Projective::new(x_elem, y_elem, Fq2::one()); // Z coordinate is set to 1 - - G2Point { point } - } - - pub fn add(&mut self, p2: G2Point) -> G2Point { - let added_point = self.point.add(p2.point); - G2Point { point: added_point } - } - - pub fn new_zero_g2_point() -> Self { - G2Point::new( - ( - u256_to_bigint256(U256::from(0)), - u256_to_bigint256(U256::from(0)), - ), - ( - u256_to_bigint256(U256::from(0)), - u256_to_bigint256(U256::from(0)), - ), - ) - } -} - -impl G1Point { - // Function to create a new G1Point from x and y coordinates - pub fn new(x: BigInteger256, y: BigInteger256) -> Self { - // Convert x and y to field elements - let x_elem = new_fp_element(x); - let y_elem = new_fp_element(y); - - // Create a new G1 point in projective coordinates - let point = G1Projective::new(x_elem, y_elem, Fq::one()); // Z coordinate is set to 1 - - G1Point { point } - } - - pub fn add(&mut self, p2: G1Point) -> G1Point { - let added_point = self.point.add(p2.point); - G1Point { point: added_point } - } - - pub fn new_zero_g1_point() -> Self { - G1Point::new( - u256_to_bigint256(U256::from(0)), - u256_to_bigint256(U256::from(0)), - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ark_ff::UniformRand; - use ark_ff::{BigInt, Zero}; - use rand::{thread_rng, RngCore}; - #[tokio::test] - async fn test_keypair_generation() { - let mut rng = thread_rng(); - let private_key = Fr::rand(&mut rng); - let keypair = KeyPair::new(private_key).unwrap(); - let pub_key = keypair.get_pub_key_g1(); - - // Check that the public key is not zero - assert_ne!(pub_key, G1Projective::zero()); - } - - #[tokio::test] - async fn test_signature_generation() { - let mut rng = thread_rng(); - let private_key = Fr::rand(&mut rng); - let keypair = KeyPair::new(private_key).unwrap(); - - let message = [0u8; 32]; - let msg_hash = hash_to_g1(&message); - - let signature = keypair.sign_hashes_to_curve_message(msg_hash.into()); - - // Check that the signature is not zero - assert_ne!(signature.sig(), G1Projective::zero()); - } - - #[tokio::test] - async fn test_signature_verification() { - let mut rng = thread_rng(); - let private_key = Fr::rand(&mut rng); - let keypair = KeyPair::new(private_key).unwrap(); - let pub_key_g2 = keypair.get_pub_key_g2().unwrap(); - // generate a random message - let mut message = [0u8; 32]; - rng.fill_bytes(&mut message); - - let msg_hash = hash_to_g1(&message); - - let signature = keypair.sign_hashes_to_curve_message(msg_hash.into()); - - // Check that the signature is not zero - assert_ne!(signature.sig(), G1Projective::zero()); - let mut wrong_message = [0u8; 32]; - rng.fill_bytes(&mut wrong_message); - // Check that the signature verifies - assert!(signature.verify_signature(pub_key_g2, &message)); - assert!(!signature.verify_signature(pub_key_g2, &wrong_message)) - } - - #[tokio::test] - async fn test_signature_verification_invalid() { - let mut rng = thread_rng(); - let private_key = Fr::rand(&mut rng); - let keypair = KeyPair::new(private_key).unwrap(); - - let mut message = [0u8; 32]; - rng.fill_bytes(&mut message); - - let msg_hash = hash_to_g1(&message); - - let signature = keypair.sign_hashes_to_curve_message(msg_hash.into()); - - // Check that the signature is not zero - assert_ne!(signature.sig(), G1Projective::zero()); - - // Check that the signature does not verify with a different public key - let different_pub_key = G2Projective::rand(&mut rng); - assert!(!signature.verify_signature(different_pub_key, &message)); - } - - #[tokio::test] - async fn test_keypair_from_string() { - let bigint = BigInt([ - 12844100841192127628, - 7068359412155877604, - 5417847382009744817, - 1586467664616413849, - ]); - let hex_string = bigint_to_hex(&bigint); - let converted_bigint = hex_string_to_biginteger256(&hex_string); - assert_eq!(bigint, converted_bigint); - let keypair_result_from_string = KeyPair::from_string(hex_string); - let keypair_result_normal = KeyPair::new(Fr::from(bigint)); - - let keypair_from_string = keypair_result_from_string.unwrap(); - let keypair_from_new = keypair_result_normal.unwrap(); - assert_eq!(keypair_from_new.priv_key, keypair_from_string.priv_key); - } -} diff --git a/crates/crypto/bls/src/error.rs b/crates/crypto/bls/src/error.rs index 9f7da6f86..431728059 100644 --- a/crates/crypto/bls/src/error.rs +++ b/crates/crypto/bls/src/error.rs @@ -2,15 +2,15 @@ use thiserror::Error; #[derive(Debug, Error)] pub enum BlsError { - /// Multiply private key to g2 projective - #[error("Failed to multiply by G2 Projective")] - MulByG2Projective, + /// Invalid Bls Private Key + #[error("Invalid bls private key ")] + InvalidBlsPrivateKey, - /// Multiply private key to g1 projective - #[error("Failed to multiply by G1 Projective")] - MulByG1Projective, + /// Invalid G1Affine + #[error("Points missing in G1Affine")] + InvalidG1Affine, - /// Failed to generate keypair from private key string - #[error("Failed to generate keypair from String")] - KeyPairFromString, + /// Invalid G2Affine + #[error("Points missing in G2Affine")] + InvalidG2Affine, } diff --git a/crates/crypto/bls/src/lib.rs b/crates/crypto/bls/src/lib.rs index c5eae949d..4c4309f14 100644 --- a/crates/crypto/bls/src/lib.rs +++ b/crates/crypto/bls/src/lib.rs @@ -4,181 +4,393 @@ )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] -pub mod attestation; - +use alloy_primitives::{B256, U256}; +use ark_std::str::FromStr; pub mod error; -use ark_bn254::{Fq, Fr, G1Affine, G2Affine}; +use crate::error::BlsError; +use ark_bn254::{Fq, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; use ark_ec::{AffineRepr, CurveGroup}; -use ark_ff::{ - fields::{Field, PrimeField}, - BigInt, BigInteger, One, -}; -use eigen_utils::binding::BLSApkRegistry::{G1Point, G2Point}; -use ethers::{core::types::H256, types::Address, utils::keccak256}; -use num_bigint::BigUint; - +use ark_ff::{fields::PrimeField, BigInt, BigInteger256}; +use eigen_crypto_bn254::utils::map_to_curve; +use eigen_utils::binding::RegistryCoordinator::{self}; +use RegistryCoordinator::{G1Point, G2Point}; pub type PrivateKey = Fr; pub type PublicKey = G1Affine; pub type BlsSignature = G1Affine; -pub type OperatorId = H256; +pub type OperatorId = B256; -#[derive(Debug, Default)] -pub struct BlsKeypair { - pub private: PrivateKey, - pub public: PublicKey, +#[derive(Debug, Clone)] +pub struct BlsG1Point { + g1: G1Affine, } -impl From for Option { - fn from(val: BlsKeypair) -> Self { - if let Some((x, y)) = val.public.xy() { - Some(G1Point { - X: alloy_primitives::U256::from_le_slice(&x.into_bigint().to_bytes_le()[..]), - Y: alloy_primitives::U256::from_le_slice(&y.into_bigint().to_bytes_le()[..]), - }) - } else { - None - } +impl BlsG1Point { + pub fn new(g1: G1Affine) -> Self { + Self { g1 } } -} -impl From for Option { - fn from(val: BlsKeypair) -> Self { - let g2 = val.public_g2(); - if let Some((x, y)) = g2.xy() { - Some(G2Point { - X: [ - alloy_primitives::U256::from_le_slice(&x.c0.into_bigint().to_bytes_le()[..]), - alloy_primitives::U256::from_le_slice(&x.c1.into_bigint().to_bytes_le()[..]), - ], - Y: [ - alloy_primitives::U256::from_le_slice(&y.c0.into_bigint().to_bytes_le()[..]), - alloy_primitives::U256::from_le_slice(&y.c1.into_bigint().to_bytes_le()[..]), - ], - }) - } else { - None - } + pub fn g1(&self) -> G1Affine { + self.g1 } } -impl BlsKeypair { - pub fn public_g2(&self) -> G2Affine { - (G2Affine::generator() * self.private).into_affine() +#[derive(Debug, Clone)] +pub struct BlsG2Point { + g2: G2Affine, +} + +impl BlsG2Point { + pub fn new(g2: G2Affine) -> Self { + Self { g2 } } - pub fn operator_id(&self) -> OperatorId { - let xy = self.public.xy().expect("should have public"); - keccak256( - [ - xy.0.into_bigint().to_bytes_be(), - xy.1.into_bigint().to_bytes_be(), - ] - .concat(), - ) - .into() - } - - pub fn make_pubkey_registration_data( - &self, - operator_addr: Address, - bls_pubkey_comp_addr: Address, - chain_id: u64, - ) -> eyre::Result { - let bytes = [ - operator_addr.as_bytes(), - bls_pubkey_comp_addr.as_bytes(), - &[0_u8; 24], - &chain_id.to_be_bytes(), - b"EigenLayer_BN254_Pubkey_Registration", - ] - .concat(); - let hash: H256 = keccak256(&bytes).into(); - self.sign(hash.as_bytes()) - } - - pub fn sign(&self, msg: &[u8]) -> eyre::Result { - let h = Self::map_to_curve(msg)?; - let sig = h * self.private; - - Ok(sig.into_affine()) - } - - pub fn sign_hashed(&self, msg: G1Affine) -> eyre::Result { - let sig = msg * self.private; - - Ok(sig.into_affine()) - } - /// implements BN254 map to curve from - /// contracts/lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/contracts/libraries/BN254.sol - /// for a hash, maps to a point on curve - /// y^2 = x^3 + b - fn map_to_curve(hash: &[u8]) -> eyre::Result { - let mut x: Fq = Fq::from_be_bytes_mod_order(hash); - let b = BigInt::<4>::from(3_u32); - - loop { - let beta = x.pow(b) + Fq::from(3_u32); - if let Some(y) = beta.sqrt() { - return Ok(PublicKey::new(x, y)); - } else { - x += Fq::one() + pub fn g2(&self) -> G2Affine { + self.g2 + } +} + +/// Bls key pair with public key on G1 +pub struct BlsKeyPair { + /// Private Key + priv_key: Fr, + /// Public Key on G1 + pub_key: BlsG1Point, +} + +impl BlsKeyPair { + /// Input [`Fr`] as a [`String`] + pub fn new(fr: String) -> Result { + let sk_result = Fr::from_str(&fr); + match sk_result { + Ok(sk) => { + let pk = G1Projective::from(G1Affine::generator()) * sk; + Ok(Self { + priv_key: sk, + pub_key: BlsG1Point::new(pk.into_affine()), + }) } + Err(_) => Err(BlsError::InvalidBlsPrivateKey), } } - pub fn priv_key(&self) -> Fr { - self.private + /// Get public key on G1 + pub fn public_key(&self) -> BlsG1Point { + self.pub_key.clone() } -} -pub struct EthConvert; -impl EthConvert { - pub fn to_u256(p: &Fq) -> alloy_primitives::U256 { - alloy_primitives::U256::from_le_slice(&p.into_bigint().to_bytes_le()[..]) + pub fn sign_hashed_to_curve_message(&self, g1_hashed_msg: G1Affine) -> Signature { + let sk_int: BigInteger256 = self.priv_key.into(); + let r = g1_hashed_msg.mul_bigint(sk_int); + Signature::new(r.into_affine()) } - pub fn to_g1(xy: G1Affine) -> Option { - xy.xy().map(|(x, y)| G1Point { - X: EthConvert::to_u256(x), - Y: EthConvert::to_u256(y), + pub fn sign_message(&self, message: &[u8]) -> Signature { + let g1 = map_to_curve(message); + let sk_int: BigInteger256 = self.priv_key.into(); + let r = g1.mul_bigint(sk_int); + Signature::new(r.into_affine()) + } + + /// Get public key on G2 + pub fn public_key_g2(&self) -> BlsG2Point { + let pk = G2Projective::from(G2Affine::generator()) * self.priv_key; + BlsG2Point::new(pk.into_affine()) + } +} + +/// Convert [`G1Point`] to [`G1Affine`] +pub fn alloy_g1_point_to_g1_affine(g1_point: G1Point) -> G1Affine { + let x_point = g1_point.X.into_limbs(); + let x = Fq::new(BigInteger256::new(x_point)); + let y_point = g1_point.Y.into_limbs(); + let y = Fq::new(BigInteger256::new(y_point)); + G1Affine::new(x, y) +} + +/// Convert [`G1Affine`] to Alloy [`G1Point`] +pub fn convert_to_g1_point(g1: G1Affine) -> Result { + let x_point_result = g1.x(); + let y_point_result = g1.y(); + + if let (Some(x_point), Some(y_point)) = (x_point_result, y_point_result) { + let x = BigInt::new(x_point.into_bigint().0); + let y = BigInt::new(y_point.into_bigint().0); + + let x_u256 = U256::from_limbs(x.0); + let y_u256 = U256::from_limbs(y.0); + + Ok(G1Point { + X: x_u256, + Y: y_u256, }) + } else { + Err(BlsError::InvalidG1Affine) } +} + +/// Convert [`G2Affine`] to [`G2Point`] +pub fn convert_to_g2_point(g2: G2Affine) -> Result { + let x_point_result = g2.x(); + // let x_point_c1 = g2.x().unwrap().c1; + + let y_point_result = g2.y(); + // let y_point_c1 = g2.y().unwrap().c1; + + if let (Some(x_point), Some(y_point)) = (x_point_result, y_point_result) { + let x_point_c0 = x_point.c0; + let x_point_c1 = x_point.c1; + let y_point_c0 = y_point.c0; + let y_point_c1 = y_point.c1; - pub fn to_g2(xy: G2Affine) -> Option { - xy.xy().map(|(x, y)| G2Point { - X: [EthConvert::to_u256(&x.c1), EthConvert::to_u256(&x.c0)], - Y: [EthConvert::to_u256(&y.c1), EthConvert::to_u256(&y.c0)], + let x_0 = BigInt::new(x_point_c0.into_bigint().0); + let x_1 = BigInt::new(x_point_c1.into_bigint().0); + let y_0 = BigInt::new(y_point_c0.into_bigint().0); + let y_1 = BigInt::new(y_point_c1.into_bigint().0); + + let x_u256_0 = U256::from_limbs(x_0.0); + let x_u256_1 = U256::from_limbs(x_1.0); + let y_u256_0 = U256::from_limbs(y_0.0); + let y_u256_1 = U256::from_limbs(y_1.0); + + Ok(G2Point { + X: [x_u256_1, x_u256_0], + Y: [y_u256_1, y_u256_0], }) + } else { + Err(BlsError::InvalidG2Affine) } +} + +/// Signature instance on [`G1Affine`] +#[derive(Debug, Clone)] +pub struct Signature { + g1_point: BlsG1Point, +} - pub fn from_g1(xy: G1Point) -> G1Affine { - let x = BigUint::from_bytes_le(&xy.X.to_le_bytes::<32>()[..]); - let y = BigUint::from_bytes_le(&xy.Y.to_le_bytes::<32>()[..]); - G1Affine::new(x.into(), y.into()) +impl Signature { + pub fn new(g1: G1Affine) -> Self { + Self { + g1_point: BlsG1Point::new(g1), + } + } + + pub fn g1_point(&self) -> BlsG1Point { + self.g1_point.clone() } } #[cfg(test)] mod tests { - use super::{BlsKeypair, PublicKey}; - use ark_bn254::Fq; + + use super::*; + use ark_bn254::Fq2; + use eigen_crypto_bn254::utils::verify_message; #[test] - fn test_map_parity() { - use std::str::FromStr; - // taken from golang impl - let x = Fq::from_str( - "21808877952123445795107598745041753552237365029343566086488416315631580963384", + fn test_convert_to_g1_point() { + let x_point = Fq::from_str( + "17709620697113958145616918533531128159269167719799793368595970620022661612059", ) .unwrap(); - let y = Fq::from_str( - "11638128931416599220980524115187668264422283409187640152391635080130668110949", + let y_point = Fq::from_str( + "9890439522434691655532127414660267222813910180198976870423582442696952349816", ) .unwrap(); - let expected = PublicKey::new(x, y); - let msg = b"07c2ee97b7ae54ffe597b9db97ede3b7"; - let r = BlsKeypair::map_to_curve(msg).unwrap(); - assert_eq!(r, expected); + let g1_affine = G1Affine::new(x_point, y_point); + + let alloy_g1_point = convert_to_g1_point(g1_affine).unwrap(); + assert_eq!( + alloy_g1_point.X, + U256::from_str( + "17709620697113958145616918533531128159269167719799793368595970620022661612059" + ) + .unwrap() + ); + assert_eq!( + alloy_g1_point.Y, + U256::from_str( + "9890439522434691655532127414660267222813910180198976870423582442696952349816" + ) + .unwrap() + ); + } + + #[test] + fn test_alloy_g1_point_to_g1_affine() { + let alloy_g1_point = G1Point { + X: U256::from_str( + "17709620697113958145616918533531128159269167719799793368595970620022661612059", + ) + .unwrap(), + Y: U256::from_str( + "9890439522434691655532127414660267222813910180198976870423582442696952349816", + ) + .unwrap(), + }; + + let g1_affine = alloy_g1_point_to_g1_affine(alloy_g1_point); + assert_eq!( + U256::from_limbs(g1_affine.x().unwrap().into_bigint().0), + U256::from_str( + "17709620697113958145616918533531128159269167719799793368595970620022661612059" + ) + .unwrap() + ); + assert_eq!( + U256::from_limbs(g1_affine.y().unwrap().into_bigint().0), + U256::from_str( + "9890439522434691655532127414660267222813910180198976870423582442696952349816" + ) + .unwrap() + ); + } + + #[test] + fn test_convert_to_g2_point() { + let x_point_c0 = Fq::from_str( + "6834287759893774453556191528501556195232162436167606874229072410417955767882", + ) + .unwrap(); + let x_point_c1 = Fq::from_str( + "15529400123788596166111036611862227541174221446291015207340396747864347375335", + ) + .unwrap(); + + let y_point_c0 = Fq::from_str( + "7616309349481520605447660298084926776417001188005125143383153219707218450524", + ) + .unwrap(); + let y_point_c1 = Fq::from_str( + "19775028091101520702581412350510183088819198056772055625089714355379667714558", + ) + .unwrap(); + + let x_point = Fq2::new(x_point_c0, x_point_c1); + let y_point = Fq2::new(y_point_c0, y_point_c1); + + let g2_affine = G2Affine::new(x_point, y_point); + + let alloy_g2_point = convert_to_g2_point(g2_affine).unwrap(); + assert_eq!( + alloy_g2_point.X[0], + U256::from_str( + "15529400123788596166111036611862227541174221446291015207340396747864347375335" + ) + .unwrap() + ); + assert_eq!( + alloy_g2_point.X[1], + U256::from_str( + "6834287759893774453556191528501556195232162436167606874229072410417955767882" + ) + .unwrap() + ); + assert_eq!( + alloy_g2_point.Y[0], + U256::from_str( + "19775028091101520702581412350510183088819198056772055625089714355379667714558" + ) + .unwrap() + ); + assert_eq!( + alloy_g2_point.Y[1], + U256::from_str( + "7616309349481520605447660298084926776417001188005125143383153219707218450524" + ) + .unwrap() + ); + } + + #[test] + fn test_bls_key_pair() { + let bls_priv_key = + "12248929636257230549931416853095037629726205319386239410403476017439825112537"; + let bls_key_pair = BlsKeyPair::new(bls_priv_key.to_string()).unwrap(); + + assert_eq!( + U256::from_limbs(bls_key_pair.public_key().g1().x().unwrap().into_bigint().0), + U256::from_str( + "277950648056014144722774518899051149098728246263316284984520891067822832300" + ) + .unwrap() + ); + assert_eq!( + U256::from_limbs(bls_key_pair.public_key().g1().y().unwrap().into_bigint().0), + U256::from_str( + "16927236637669640540790285431111034664564710839671197540688155537113438534238" + ) + .unwrap() + ); + } + + #[test] + fn test_map_to_curve() { + let message: [u8; 32] = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + ]; + let g1 = map_to_curve(&message); + + assert_eq!( + U256::from_limbs(g1.x().unwrap().into_bigint().0), + U256::from_str( + "455867356320691211509944977504407603390036387149619137164185182714736811811" + ) + .unwrap() + ); + assert_eq!( + U256::from_limbs(g1.y().unwrap().into_bigint().0), + U256::from_str( + "9802125641729881429496664198939823213610051907104384160271670136040620850981" + ) + .unwrap() + ); + } + + #[test] + fn test_sign_message() { + let message: [u8; 32] = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + ]; + let bls_priv_key = + "12248929636257230549931416853095037629726205319386239410403476017439825112537"; + let bls_key_pair = BlsKeyPair::new(bls_priv_key.to_string()).unwrap(); + + let signature = bls_key_pair.sign_message(&message); + assert_eq!( + U256::from_limbs(signature.g1_point().g1().x().unwrap().into_bigint().0), + U256::from_str( + "6125087140203962697351933212367898471377426213402772883153680722977416765651" + ) + .unwrap() + ); + assert_eq!( + U256::from_limbs(signature.g1_point().g1().y().unwrap().into_bigint().0), + U256::from_str( + "19120302240465611628345095276448175199636936878728446037184749040811421969742" + ) + .unwrap() + ); + } + + #[test] + fn test_verify_message() { + let message: [u8; 32] = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + ]; + let bls_priv_key = + "12248929636257230549931416853095037629726205319386239410403476017439825112537"; + let bls_key_pair = BlsKeyPair::new(bls_priv_key.to_string()).unwrap(); + + let signature = bls_key_pair.sign_message(&message); + + assert!(verify_message( + bls_key_pair.public_key_g2().g2(), + &message, + signature.g1_point().g1() + )); } } diff --git a/crates/crypto/bn254/Cargo.toml b/crates/crypto/bn254/Cargo.toml index 3f97463f9..3c0f48756 100644 --- a/crates/crypto/bn254/Cargo.toml +++ b/crates/crypto/bn254/Cargo.toml @@ -9,10 +9,12 @@ repository.workspace = true license-file.workspace = true [dependencies] +ark-bn254.workspace = true +ark-ec.workspace = true ark-ff.workspace = true -ark-bn254 = "0.4.0" -thiserror.workspace = true -alloy-primitives.workspace = true +num-bigint = "0.4.4" +rust-bls-bn254.workspace = true + [dev-dependencies] tokio = { workspace = true, features = ["full"] } diff --git a/crates/crypto/bn254/src/error.rs b/crates/crypto/bn254/src/error.rs index 0ee879bf6..8b1378917 100644 --- a/crates/crypto/bn254/src/error.rs +++ b/crates/crypto/bn254/src/error.rs @@ -1,8 +1 @@ -use thiserror::Error; -#[derive(Debug, Error)] -pub enum Bn254Err { - /// Build Fq instance from string - #[error("failed to build a Fq instance from string ")] - Fq, -} diff --git a/crates/crypto/bn254/src/utils.rs b/crates/crypto/bn254/src/utils.rs index aa5e9711c..bb94cad3f 100644 --- a/crates/crypto/bn254/src/utils.rs +++ b/crates/crypto/bn254/src/utils.rs @@ -1,125 +1,56 @@ -use crate::error::Bn254Err; -use alloy_primitives::U256; -use ark_bn254::{Fq, Fq2, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; -use ark_ff::{BigInteger, BigInteger256}; -use std::ops::Mul; -use std::str::FromStr; - -/// Converts [U256] to [BigInteger256] -pub fn u256_to_bigint256(value: U256) -> BigInteger256 { - // Convert U256 to a big-endian byte array - let bytes: [u8; 32] = value.to_be_bytes(); - - // BigInteger256 expects a 4-element array of 64-bit values in little-endian order - let mut data = [0u64; 4]; - - // Iterate over the bytes in chunks of 8 bytes and convert to u64 - for (i, chunk) in bytes.chunks(8).enumerate() { - let mut chunk_array = [0u8; 8]; - chunk_array.copy_from_slice(chunk); - data[3 - i] = u64::from_be_bytes(chunk_array); - } - - BigInteger256::new(data) -} - -pub fn biginteger256_to_u256(bi: BigInteger256) -> U256 { - let s = bi.to_bytes_be(); - U256::from_be_slice(&s) -} - -pub fn get_g1_generator() -> Result { - let x_result = Fq::from_str("1"); - - let y_result = Fq::from_str("2"); - - match x_result { - Ok(x) => match y_result { - Ok(y) => Ok(G1Affine::new(x, y)), - Err(_) => Err(Bn254Err::Fq), - }, - Err(_) => Err(Bn254Err::Fq), - } -} - -pub fn get_g2_generator() -> Result { - let x_0_result = Fq::from_str( - "10857046999023057135944570762232829481370756359578518086990519993285655852781", - ); - - let x_1result = Fq::from_str( - "11559732032986387107991004021392285783925812861821192530917403151452391805634", - ); - - match x_0_result { - Ok(x_0) => { - match x_1result { - Ok(x_1) => { - let x = Fq2::new(x_0, x_1); - - let y_0_result = Fq::from_str("8495653923123431417604973247489272438418190587263600148770280649306958101930"); - - match y_0_result { - Ok(y_0) => { - let y_1_result = Fq::from_str("4082367875863433681332203403145435568316851327593401208105741076214120093531"); - - match y_1_result { - Ok(y_1) => { - let y = Fq2::new(y_0, y_1); - Ok(G2Affine::new(x, y)) - } - Err(_) => Err(Bn254Err::Fq), - } - } - Err(_) => Err(Bn254Err::Fq), - } - } - Err(_) => Err(Bn254Err::Fq), - } +use ark_bn254::{Fq, G1Affine, G1Projective, G2Affine}; +use ark_ec::{AffineRepr, CurveGroup}; +use ark_ff::{ + fields::{Field, PrimeField}, + One, +}; +use num_bigint::BigUint; +use rust_bls_bn254::pairing; + +/// MapToCurve implements the simple hash-and-check (also sometimes try-and-increment) algorithm +/// see https://hackmd.io/@benjaminion/bls12-381#Hash-and-check +/// Note that this function needs to be the same as the one used in the contract: +/// https://github.com/Layr-Labs/eigenlayer-middleware/blob/1feb6ae7e12f33ce8eefb361edb69ee26c118b5d/src/libraries/BN254.sol#L292 +/// we don't use the newer constant time hash-to-curve algorithms as they are gas-expensive to compute onchain +pub fn map_to_curve(digest: &[u8]) -> G1Affine { + let one = Fq::one(); + let three = Fq::from(3u64); + let big_int = BigUint::from_bytes_be(digest); + let mut bytes = [0u8; 32]; + big_int + .to_bytes_be() + .iter() + .rev() + .enumerate() + .for_each(|(i, &b)| bytes[i] = b); + + let mut x = Fq::from_le_bytes_mod_order(&bytes); + + loop { + // y = x^3 + 3 + let mut y = x; + y.square_in_place(); + y *= x; + y += three; + + // Check if y is a quadratic residue (i.e., has a square root in the field) + if let Some(y) = y.sqrt() { + return G1Projective::new(x, y, Fq::one()).into_affine(); + } else { + // x = x + 1 + x += one; } - Err(_) => Err(Bn254Err::Fq), } } -pub fn mul_by_generator_g1(pvt_key: Fr) -> Result { - let g1_gen_result = get_g1_generator(); - - match g1_gen_result { - Ok(g1_gen) => { - let s: G1Projective = g1_gen.into(); - Ok(s.mul(pvt_key)) - } - Err(_) => Err(Bn254Err::Fq), +/// Verifies message on G2 +pub fn verify_message(public_key: G2Affine, message: &[u8], signature: G1Affine) -> bool { + if !signature.is_in_correct_subgroup_assuming_on_curve() || !signature.is_on_curve() { + return false; } -} -pub fn mul_by_generator_g2(pvt_key: Fr) -> Result { - let g2_gen_result = get_g2_generator(); - - match g2_gen_result { - Ok(g2_gen) => { - let s: G2Projective = g2_gen.into(); - Ok(s.mul(pvt_key)) - } - Err(_) => Err(Bn254Err::Fq), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[tokio::test] - async fn test_u256_to_bigint256() { - let u256 = U256::from(123456789); - let result = u256_to_bigint256(u256); - assert_eq!(result, BigInteger256::from(123456789u32)); - } - - #[tokio::test] - async fn test_bigint256_to_u256() { - let bi = BigInteger256::from(123456789u32); - let result = biginteger256_to_u256(bi); - assert_eq!(result, U256::from(123456789)); - } + let q = map_to_curve(message); + let c1 = pairing(public_key, q); + let c2 = pairing(G2Affine::generator(), signature); + c1 == c2 } diff --git a/crates/crypto/keystore/Cargo.toml b/crates/crypto/keystore/Cargo.toml deleted file mode 100644 index a136e7868..000000000 --- a/crates/crypto/keystore/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "eigen-crypto-keystore" -version.workspace = true -edition.workspace = true -rust-version.workspace = true -repository.workspace = true - -[dependencies] -aes = "0.8.0" -ark-ec = "0.4.2" -ark-ff = { version = "0.4.2", features = ["std"] } -ctr = "0.9.0" -eth-keystore = "0.5.0" -ethers = { version = "2.0", features = ["rustls", "ws"] } -eyre = "0.6.8" -rand = "0.8.5" -scrypt = "0.10.0" -serde = { version = "1.0.192", features = ["derive"] } -serde_json = { version = "1.0.85" } -eigen-crypto-bls.workspace = true - diff --git a/crates/crypto/keystore/src/lib.rs b/crates/crypto/keystore/src/lib.rs deleted file mode 100644 index bae6fb7fa..000000000 --- a/crates/crypto/keystore/src/lib.rs +++ /dev/null @@ -1,147 +0,0 @@ -#![doc( - html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", - issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" -)] -#![cfg_attr(not(test), warn(unused_crate_dependencies))] - -use aes::{ - cipher::{InnerIvInit, KeyInit, StreamCipherCore}, - Aes128, -}; -use ark_ec::{AffineRepr, CurveGroup}; -use ark_ff::{fields::PrimeField, Field}; -use eigen_crypto_bls::{BlsKeypair, PrivateKey, PublicKey}; -use eth_keystore::{CryptoJson, KdfparamsType}; -use ethers::{signers::LocalWallet, types::H256, utils::keccak256}; -use eyre::{eyre, Ok, Report}; -use rand::{thread_rng, RngCore}; -use scrypt::{scrypt, Params as ScryptParams}; -use serde::{Deserialize, Serialize}; -use std::{fmt::Debug, fs::File, io::Read, path::Path}; - -#[derive(Default)] -pub struct EncodedKeystore { - encrypted_keystore: Option, - password: Option, -} - -impl EncodedKeystore { - pub fn from_path

(path: &P, password: Option) -> eyre::Result - where - P: AsRef, - { - let mut file = File::open(path)?; - let mut contents = String::new(); - file.read_to_string(&mut contents)?; - let keystore: Keystore = serde_json::from_str(&contents)?; - Ok(Self { - encrypted_keystore: Some(keystore), - password, - }) - } - - pub fn from_string(contents: String, password: Option) -> eyre::Result { - let keystore: Keystore = serde_json::from_str(&contents)?; - Ok(Self { - encrypted_keystore: Some(keystore), - password, - }) - } - - pub fn random() -> eyre::Result { - Ok(Self::default()) - } - - pub fn into_bls_keypair(self) -> eyre::Result { - let fr = if let Some(keystore) = self.encrypted_keystore { - let secret = decrypt_key(keystore, self.password.unwrap_or_default())?; - PrivateKey::from_be_bytes_mod_order(&secret) - } else { - let rnd = &mut [0_u8; 32]; - let mut rng = thread_rng(); - loop { - rng.fill_bytes(rnd); - if let Some(key) = PrivateKey::from_random_bytes(rnd) { - break key; - } - } - }; - let p = PublicKey::generator() * fr; - - Ok(BlsKeypair { - private: fr, - public: p.into_affine(), - }) - } - - pub fn into_wallet(self) -> eyre::Result { - if let Some(keystore) = self.encrypted_keystore { - let secret = decrypt_key(keystore, self.password.unwrap_or_default())?; - Ok(LocalWallet::from_bytes(&secret)?) - } else { - Ok(LocalWallet::new(&mut thread_rng())) - } - } -} - -#[derive(Debug, Deserialize, Serialize)] -struct Keystore { - crypto: CryptoJson, -} - -fn decrypt_key(keystore: Keystore, password: S) -> eyre::Result> -where - S: AsRef<[u8]>, -{ - // Derive the key. - let key = match keystore.crypto.kdfparams { - KdfparamsType::Pbkdf2 { .. } => { - return Err(Report::msg("Pbkdf2 not supported")); - } - KdfparamsType::Scrypt { - dklen, - n, - p, - r, - salt, - } => { - let mut key = vec![0u8; dklen as usize]; - let log_n = (n as f32).log2() as u8; - let scrypt_params = ScryptParams::new(log_n, r, p)?; - scrypt(password.as_ref(), &salt, &scrypt_params, key.as_mut_slice())?; - key - } - }; - - // Derive the MAC from the derived key and ciphertext. - let derived_mac: H256 = keccak256([&key[16..32], &keystore.crypto.ciphertext].concat()).into(); - - if derived_mac.as_bytes() != keystore.crypto.mac.as_slice() { - return Err(eyre!("MacMismatch")); - } - - // Decrypt the private key bytes using AES-128-CTR - let decryptor = - Aes128Ctr::new(&key[..16], &keystore.crypto.cipherparams.iv[..16]).expect("invalid length"); - - let mut pk = keystore.crypto.ciphertext; - decryptor.apply_keystream(&mut pk); - - Ok(pk) -} - -struct Aes128Ctr { - inner: ctr::CtrCore, -} - -impl Aes128Ctr { - fn new(key: &[u8], iv: &[u8]) -> eyre::Result { - let cipher = aes::Aes128::new_from_slice(key).unwrap(); - let inner = ctr::CtrCore::inner_iv_slice_init(cipher, iv)?; - Ok(Self { inner }) - } - - fn apply_keystream(self, buf: &mut [u8]) { - self.inner.apply_keystream_partial(buf.into()); - } -} diff --git a/crates/services/avsregistry/src/chaincaller.rs b/crates/services/avsregistry/src/chaincaller.rs index ea42a5887..71f9dd17b 100644 --- a/crates/services/avsregistry/src/chaincaller.rs +++ b/crates/services/avsregistry/src/chaincaller.rs @@ -1,147 +1,125 @@ -use alloy_primitives::{Bytes, FixedBytes, U256}; -use eigen_chainio_utils::convert_to_bn254_g1_point; -use eigen_client_avsregistry::reader::AvsRegistryChainReader; -use eigen_crypto_bls::attestation::G1Point as BlsG1Point; -use eigen_crypto_bn254::utils::u256_to_bigint256; -use eigen_logging::{logger::Logger, tracing_logger::TracingLogger}; -use eigen_services_operatorsinfo::operatorsinfo_inmemory::OperatorInfoServiceInMemory; -use eigen_types::operator::{OperatorAvsState, OperatorInfo, OperatorPubKeys, QuorumAvsState}; -use eigen_utils::binding::BLSApkRegistry::G1Point; -use std::collections::HashMap; +// use alloy_primitives::{Bytes, FixedBytes, U256}; +// use eigen_client_avsregistry::reader::AvsRegistryChainReader; +// use eigen_crypto_bls::BlsG1Point; +// use eigen_services_operatorsinfo::operatorsinfo_inmemory::OperatorInfoServiceInMemory; +// use eigen_types::operator::{OperatorAvsState, OperatorInfo, OperatorPubKeys, QuorumAvsState}; +// use eigen_utils::binding::BLSApkRegistry::G1Point; +// use std::collections::HashMap; -#[derive(Debug)] -pub struct AvsRegistryServiceChainCaller { - logger: TracingLogger, - avs_registry: AvsRegistryChainReader, - operators_info_service: OperatorInfoServiceInMemory, -} +// #[derive(Debug)] +// pub struct AvsRegistryServiceChainCaller { +// avs_registry: AvsRegistryChainReader, +// operators_info_service: OperatorInfoServiceInMemory, +// } -impl AvsRegistryServiceChainCaller { - pub fn new( - logger: TracingLogger, - avs_registry: AvsRegistryChainReader, - operators_info_service: OperatorInfoServiceInMemory, - ) -> Self { - Self { - logger, - avs_registry, - operators_info_service, - } - } +// impl AvsRegistryServiceChainCaller { +// pub fn new( +// avs_registry: AvsRegistryChainReader, +// operators_info_service: OperatorInfoServiceInMemory, +// ) -> Self { +// Self { +// avs_registry, +// operators_info_service, +// } +// } - pub fn get_avs_registry(&self) -> AvsRegistryChainReader { - self.avs_registry.clone() - } +// pub fn get_avs_registry(&self) -> AvsRegistryChainReader { +// self.avs_registry.clone() +// } - pub async fn get_operators_avs_state_at_block( - &self, - block_num: u32, - quorum_nums: Bytes, - ) -> Result, OperatorAvsState>, String> { - let mut operators_avs_state: HashMap, OperatorAvsState> = HashMap::new(); - // temporarily using string for errors(For logging stuff on error) . TODO change to appropriate errors - let operators_stakes_in_quorums_result = self - .avs_registry - .get_operators_stake_in_quorums_at_block(block_num, quorum_nums.clone()) - .await; +// pub async fn get_operators_avs_state_at_block( +// &self, +// block_num: u32, +// quorum_nums: Bytes, +// ) -> HashMap, OperatorAvsState> { +// let mut operators_avs_state: HashMap, OperatorAvsState> = HashMap::new(); - match operators_stakes_in_quorums_result { - Ok(operators_stakes_in_quorums) => { - if operators_stakes_in_quorums.len() != quorum_nums.len() { - // throw error - self.logger.fatal( - "Number of quorums returned from get_operators_stake_in_quorums_at_block does not match number of quorums \ - requested. Probably pointing to old contract or wrong implementation service AvsRegistryServiceChainCaller", - &["eigen-services-avsregistry.chaincaller.get_operators_avs_state_at_block"] - ) - } +// let operators_stakes_in_quorums = self +// .avs_registry +// .get_operators_stake_in_quorums_at_block(block_num, quorum_nums.clone()) +// .await +// .unwrap(); - for (quorum_id, quorum_num) in quorum_nums.iter().enumerate() { - for operator in &operators_stakes_in_quorums[quorum_id] { - let info = self.get_operator_info(*operator.operatorId).await; - let stake_per_quorum = HashMap::new(); - let avs_state = operators_avs_state - .entry(FixedBytes(*operator.operatorId)) - .or_insert_with(|| OperatorAvsState { - operator_id: *operator.operatorId, - operator_info: OperatorInfo { pub_keys: info }, - stake_per_quorum, - block_num: block_num.into(), - }); - avs_state - .stake_per_quorum - .insert(*quorum_num, U256::from(operator.stake)); - } - } +// if operators_stakes_in_quorums.len() != quorum_nums.len() { +// // throw error +// } - Ok(operators_avs_state) - } - Err(_) => Err("Failed to get oeprators avs state at block".to_string()), - } - } +// for (quorum_id, quorum_num) in quorum_nums.iter().enumerate() { +// for operator in &operators_stakes_in_quorums[quorum_id] { +// let info = self.get_operator_info(*operator.operatorId).await; +// let stake_per_quorum = HashMap::new(); +// let avs_state = operators_avs_state +// .entry(FixedBytes(*operator.operatorId)) +// .or_insert_with(|| OperatorAvsState { +// operator_id: *operator.operatorId, +// operator_info: OperatorInfo { pub_keys: info }, +// stake_per_quorum, +// block_num: block_num.into(), +// }); +// avs_state +// .stake_per_quorum +// .insert(*quorum_num, U256::from(operator.stake)); +// } +// } - pub async fn get_quorums_avs_state_at_block( - &self, - quorum_nums: Bytes, - block_num: u32, - ) -> Result, String> { - let operators_avs_state_result = self - .get_operators_avs_state_at_block(block_num, quorum_nums.clone()) - .await; +// operators_avs_state +// } - match operators_avs_state_result { - Ok(operators_avs_state) => { - // TODO(supernova) remove String add Result - let mut quorums_avs_state: HashMap = HashMap::new(); +// pub async fn get_quorums_avs_state_at_block( +// &self, +// quorum_nums: Bytes, +// block_num: u32, +// ) -> HashMap { +// let operators_avs_state = self +// .get_operators_avs_state_at_block(block_num, quorum_nums.clone()) +// .await; - for quorum_num in quorum_nums.iter() { - let mut pub_key_g1 = BlsG1Point::new( - u256_to_bigint256(U256::from(0)), - u256_to_bigint256(U256::from(0)), - ); - let mut total_stake: U256 = U256::from(0); - for operator in operators_avs_state.values() { - if !operator.stake_per_quorum[quorum_num].is_zero() { - if let Some(pubkeys) = &operator.operator_info.pub_keys { - let g1_point = BlsG1Point::new( - u256_to_bigint256(pubkeys.g1_pub_key.X), - u256_to_bigint256(pubkeys.g1_pub_key.Y), - ); - pub_key_g1.add(g1_point); - total_stake += operator.stake_per_quorum[quorum_num]; - } - } - } - let g1_point = convert_to_bn254_g1_point(pub_key_g1.point); - quorums_avs_state.insert( - *quorum_num, - QuorumAvsState { - quorum_num: *quorum_num, - total_stake, - agg_pub_key_g1: G1Point { - X: g1_point.X, - Y: g1_point.Y, - }, - block_num, - }, - ); - } - Ok(quorums_avs_state) - } +// let mut quorums_avs_state: HashMap = HashMap::new(); - Err(_) => Err("Failed to get quorums from avs registry ".to_string()), - } - } +// for quorum_num in quorum_nums.iter() { +// let mut pub_key_g1 = BlsG1Point::new( +// u256_to_bigint256(U256::from(0)), +// u256_to_bigint256(U256::from(0)), +// ); +// let mut total_stake: U256 = U256::from(0); +// for operator in operators_avs_state.values() { +// if !operator.stake_per_quorum[quorum_num].is_zero() { +// if let Some(pubkeys) = &operator.operator_info.pub_keys { +// let g1_point = BlsG1Point::new( +// u256_to_bigint256(pubkeys.g1_pub_key.X), +// u256_to_bigint256(pubkeys.g1_pub_key.Y), +// ); +// pub_key_g1.add(g1_point); +// total_stake += operator.stake_per_quorum[quorum_num]; +// } +// } +// } +// let g1_point = convert_to_bn254_g1_point(pub_key_g1.point); +// quorums_avs_state.insert( +// *quorum_num, +// QuorumAvsState { +// quorum_num: *quorum_num, +// total_stake, +// agg_pub_key_g1: G1Point { +// X: g1_point.X, +// Y: g1_point.Y, +// }, +// block_num, +// }, +// ); +// } +// quorums_avs_state +// } - pub async fn get_operator_info(&self, operator_id: [u8; 32]) -> Option { - let operator_addr = self - .avs_registry - .get_operator_from_id(operator_id) - .await - .unwrap(); +// pub async fn get_operator_info(&self, operator_id: [u8; 32]) -> Option { +// let operator_addr = self +// .avs_registry +// .get_operator_from_id(operator_id) +// .await +// .unwrap(); - self.operators_info_service - .get_operator_info(operator_addr) - .await - } -} +// self.operators_info_service +// .get_operator_info(operator_addr) +// .await +// } +// } diff --git a/crates/services/avsregistry/src/lib.rs b/crates/services/avsregistry/src/lib.rs index ac3ac685e..767fd13e0 100644 --- a/crates/services/avsregistry/src/lib.rs +++ b/crates/services/avsregistry/src/lib.rs @@ -2,5 +2,5 @@ html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" )] -#![cfg_attr(not(test), warn(unused_crate_dependencies))] +// #![cfg_attr(not(test), warn(unused_crate_dependencies))] pub mod chaincaller; diff --git a/crates/services/bls_aggregation/src/bls_agg.rs b/crates/services/bls_aggregation/src/bls_agg.rs index 76d1e8895..553c91624 100644 --- a/crates/services/bls_aggregation/src/bls_agg.rs +++ b/crates/services/bls_aggregation/src/bls_agg.rs @@ -1,378 +1,342 @@ -use eigen_crypto_bls::attestation::{G1Point, G2Point, Signature}; -use eigen_services_avsregistry::chaincaller::AvsRegistryServiceChainCaller; -use eigen_types::{ - avs::{SignedTaskResponseDigest, TaskIndex, TaskResponseDigest}, - operator::{OperatorAvsState, QuorumThresholdPercentage, QuorumThresholdPercentages}, -}; - -use alloy_primitives::{FixedBytes, U256}; -use eigen_crypto_bn254::utils::u256_to_bigint256; -use std::collections::HashMap; -use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; -use tokio::time::{self, Duration}; - -use eigen_logging::{logger::Logger, tracing_logger::TracingLogger}; -use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; -use std::sync::Arc; - -#[allow(unused)] -#[derive(Debug, Clone)] -pub struct BlsAggregationServiceResponse { - task_index: TaskIndex, - task_response_digest: TaskResponseDigest, - non_signers_pub_keys_g1: Vec, - quorum_apks_g1: Vec, - signers_apk_g2: G2Point, - signers_agg_sig_g1: Signature, - non_signer_quorum_bitmap_indices: Vec, - quorum_apk_indices: Vec, - total_stake_indices: Vec, - non_signer_stake_indices: Vec>, -} - -#[derive(Debug, Clone)] -pub struct AggregatedOperators { - signers_apk_g2: G2Point, - - signers_agg_sig_g1: Signature, - - signers_total_stake_per_quorum: HashMap, - - pub signers_operator_ids_set: HashMap, bool>, -} - -impl AggregatedOperators {} -#[derive(Debug)] -pub struct BlsAggregatorService { - logger: TracingLogger, - aggregated_response_sender: UnboundedSender, - pub aggregated_response_receiver: UnboundedReceiver, - signed_task_response: - Arc>>>, - avs_registry_service: AvsRegistryServiceChainCaller, -} - -impl BlsAggregatorService { - pub fn new(logger: TracingLogger, avs_registry_service: AvsRegistryServiceChainCaller) -> Self { - let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); - Self { - logger, - aggregated_response_sender: tx, - aggregated_response_receiver: rx, - signed_task_response: Arc::new(RwLock::new(HashMap::new())), - avs_registry_service, - } - } - - pub(crate) async fn write( - &self, - ) -> RwLockWriteGuard<'_, HashMap>> { - self.signed_task_response.write() - } - - pub(crate) async fn read( - &self, - ) -> RwLockReadGuard<'_, HashMap>> { - self.signed_task_response.read() - } - - pub async fn initialize_new_task( - self: Arc, - task_index: TaskIndex, - task_created_block: u32, - quorum_nums: Vec, - quorum_threshold_percentages: QuorumThresholdPercentages, - time_to_expiry: Duration, - ) { - self.logger.debug( - &format!( - "BlsAggregatorService initializing new task, task_index : {}, task_created_block : {}, quorum_nums : {:?}, \ - quorum_threshold_percentages : {:?}, time_to_expiry : {:?}", - task_index, - task_created_block, - quorum_nums, - quorum_threshold_percentages, - time_to_expiry - ), - &["eigen-services-blsaggregation.bls_agg.initialize_new_task"] - ); - let mut task_channel = self.write().await; - - if task_channel.contains_key(&task_index) { - // error - } - - let (tx, mut rx) = mpsc::unbounded_channel(); - task_channel.insert(task_index, tx); - let self_clone = self.clone(); - tokio::spawn(async move { - while let Some(signed_response) = rx.recv().await { - // Process each signed response here - self_clone - .single_task_aggregator( - task_index, - task_created_block, - quorum_nums.clone(), - quorum_threshold_percentages.clone(), - time_to_expiry, - signed_response, - ) - .await; - } - }); - } - - /// Processs signatures - pub async fn process_new_signature( - &self, - task_index: TaskIndex, - task_response_digest: TaskResponseDigest, - bls_signature: Signature, - operator_id: FixedBytes<32>, - ) { - let task_channel = self.read().await; - - if let Some(sender) = task_channel.get(&task_index) { - let task = SignedTaskResponseDigest { - task_response_digest, - bls_signature, - operator_id, - }; - let _ = sender.send(task); - } - } - - pub async fn single_task_aggregator( - &self, - task_index: TaskIndex, - task_created_block: u32, - quorum_nums: Vec, - quorum_threshold_percentages: QuorumThresholdPercentages, - time_to_expiry: Duration, - signed_task_digest: SignedTaskResponseDigest, - ) { - let mut quorum_threshold_percentage_map = HashMap::new(); - - for (i, quorum_number) in quorum_nums.iter().enumerate() { - quorum_threshold_percentage_map.insert(*quorum_number, quorum_threshold_percentages[i]); - } - // TODO(supernova) remove unwraps and handle erorr better - let mut operator_state_avs = self - .avs_registry_service - .get_operators_avs_state_at_block(task_created_block, quorum_nums.clone().into()) - .await - .map_err(|e| { - self.logger.fatal( - &format!( - "Failed to get operators state from avs registry, task_index: {}, err: {}", - task_index, e - ), - &["eigen-services-blsaggregation.bls_agg.single_task_aggregator"], - ) - }) - .unwrap(); - let quorums_avs_stake = self - .avs_registry_service - .get_quorums_avs_state_at_block(quorum_nums.clone().into(), task_created_block) - .await - .map_err(|e| { - self.logger.fatal( - &format!( - "Failed to get quorums state from avs registry, task_index: {} , err: {}", - task_index, e - ), - &["eigen-services-blsaggregation.bls_agg.single_task_aggregator"], - ) - }) - .unwrap(); - - let mut total_stake_per_quorum = HashMap::new(); - - for (quorum_num, quorum_avs_stake) in &quorums_avs_stake { - total_stake_per_quorum.insert(*quorum_num, quorum_avs_stake.total_stake); - } - let mut quorum_apks_g1: Vec = vec![]; - // let quorum_apks_g1 - for quorum_number in quorum_nums.iter() { - if let Some(val) = quorums_avs_stake.get(quorum_number) { - quorum_apks_g1.push(G1Point::new( - u256_to_bigint256(val.agg_pub_key_g1.X), - u256_to_bigint256(val.agg_pub_key_g1.Y), - )); - } - } - - let task_expired_timer = time::sleep(time_to_expiry); - - tokio::pin!(task_expired_timer); - let mut aggregated_operators: HashMap, AggregatedOperators> = HashMap::new(); - let _sig = self - .verify_signature(task_index, &signed_task_digest, &operator_state_avs) - .await; - loop { - tokio::select! { - _ = &mut task_expired_timer =>{ - // todo tracing - println!("time expired"); - break; - }, - else =>{ - let mut aggregate_response: AggregatedOperators; - if let Some(response) = aggregated_operators.get(&signed_task_digest.task_response_digest) { - aggregate_response = response.clone(); - if aggregated_operators.contains_key(&signed_task_digest.task_response_digest){ - aggregate_response.signers_agg_sig_g1.get_g1_point().add(signed_task_digest.bls_signature.get_g1_point()); - if let Some(op_avs_state) = operator_state_avs.get_mut(&signed_task_digest.operator_id){ - if let Some(pub_key) =&op_avs_state.operator_info.pub_keys { - let g2_pub_key = G2Point::new((u256_to_bigint256(pub_key.g2_pub_key.X[0]),u256_to_bigint256(pub_key.g2_pub_key.X[1])),(u256_to_bigint256(pub_key.g2_pub_key.Y[0]),u256_to_bigint256(pub_key.g2_pub_key.Y[1]))); - aggregate_response.signers_apk_g2.add(g2_pub_key); - - } - } - - aggregate_response.signers_operator_ids_set.insert(FixedBytes(*signed_task_digest.operator_id), true); - - if let Some(state_avs) = operator_state_avs.get(&signed_task_digest.operator_id){ - - for (quorum_num,stake) in state_avs.stake_per_quorum.clone(){ - - if let Some(_quorum) = aggregate_response.signers_total_stake_per_quorum.get(&quorum_num){ - aggregate_response.signers_total_stake_per_quorum.insert(quorum_num, U256::from(0)); - - } - aggregate_response.signers_total_stake_per_quorum.insert(quorum_num,aggregate_response.signers_total_stake_per_quorum[&quorum_num] + stake); - - } - } - - } - else{ - let mut operator_id_set = HashMap::new(); - operator_id_set.insert(signed_task_digest.operator_id,true); - // first operator - - if let Some(avs_state) = operator_state_avs.get(&signed_task_digest.operator_id.clone()){ - - aggregate_response = AggregatedOperators{ - signers_agg_sig_g1: signed_task_digest.bls_signature.clone(), - signers_apk_g2 : G2Point::new_zero_g2_point(), - signers_operator_ids_set: operator_id_set, - signers_total_stake_per_quorum: avs_state.stake_per_quorum.clone() - } ; - } - } - - aggregated_operators.insert(signed_task_digest.task_response_digest, aggregate_response.clone()); - // check stake threshold - - if self.check_if_stake_thresholds_met(aggregate_response.signers_total_stake_per_quorum,total_stake_per_quorum.clone(),quorum_threshold_percentage_map.clone()){ - let mut non_signers_operators_ids: Vec> = vec![]; - for (i,op_info) in &operator_state_avs{ - if aggregate_response.signers_operator_ids_set.contains_key(&op_info.operator_id){ - non_signers_operators_ids.push(*i); - } - } - - non_signers_operators_ids.sort_by(|a,b|{ - a.cmp(b) - }); - - let mut non_signers_g1_pub_keys: Vec = vec![]; - for operator_id in non_signers_operators_ids.iter(){ - - if let Some(operator) = operator_state_avs.get(operator_id){ - if let Some(keys) = &operator.operator_info.pub_keys{ - let g1_key = G1Point::new(u256_to_bigint256(keys.g1_pub_key.X),u256_to_bigint256(keys.g1_pub_key.Y)); - non_signers_g1_pub_keys.push(g1_key); - } - } - - } - - let indices = self.avs_registry_service.get_avs_registry().get_check_signatures_indices(task_created_block,quorum_nums.clone(),non_signers_operators_ids).await.unwrap(); - - let bls_aggregation_service_response = BlsAggregationServiceResponse{ - task_index, - task_response_digest: signed_task_digest.task_response_digest, - non_signers_pub_keys_g1: non_signers_g1_pub_keys, - quorum_apks_g1: quorum_apks_g1.clone(), - signers_apk_g2: aggregate_response.signers_apk_g2, - signers_agg_sig_g1: aggregate_response.signers_agg_sig_g1, - non_signer_quorum_bitmap_indices: indices.clone().quorumApkIndices, - quorum_apk_indices: indices.quorumApkIndices, - total_stake_indices: indices.totalStakeIndices, - non_signer_stake_indices: indices.nonSignerStakeIndices - - - }; - - let _ = self.aggregated_response_sender.send(bls_aggregation_service_response); - - - - } - - } - - } - } - } - } - - pub async fn verify_signature( - &self, - _task_index: TaskIndex, - signed_task_response_digest: &SignedTaskResponseDigest, - operator_avs_state: &HashMap, OperatorAvsState>, - ) { - if let Some(operator_state) = - operator_avs_state.get(&signed_task_response_digest.operator_id) - { - if let Some(pub_keys) = &operator_state.operator_info.pub_keys { - let g2_proj = G2Point::new( - ( - u256_to_bigint256(pub_keys.g2_pub_key.X[0]), - u256_to_bigint256(pub_keys.g2_pub_key.X[1]), - ), - ( - u256_to_bigint256(pub_keys.g2_pub_key.Y[0]), - u256_to_bigint256(pub_keys.g2_pub_key.Y[1]), - ), - ) - .point; - let _signature_verified = signed_task_response_digest - .bls_signature - .verify_signature(g2_proj, &signed_task_response_digest.task_response_digest); - } - } else { - // throw error - } - } - - pub fn check_if_stake_thresholds_met( - &self, - signed_stake_per_quorum: HashMap, - total_stake_per_quorum: HashMap, - quorum_threshold_percentages_map: HashMap, - ) -> bool { - if let Some((quorum_num, quorum_threshold_percentage)) = - quorum_threshold_percentages_map.into_iter().next() - { - // to do check if quorum num <= u8 max assert - if let Some(signed_stake_by_quorum) = signed_stake_per_quorum.get(&quorum_num) { - if let Some(total_stake_by_quorum) = total_stake_per_quorum.get(&quorum_num) { - let signed_stake = signed_stake_by_quorum * U256::from(100); - let threshold_stake = - *total_stake_by_quorum * U256::from(quorum_threshold_percentage); - return signed_stake >= threshold_stake; - } else { - return false; - } - } else { - return false; - } - } - - true - } -} +// use eigen_crypto_bls::attestation::{G1Point, G2Point, Signature}; +// use eigen_services_avsregistry::chaincaller::AvsRegistryServiceChainCaller; +// use eigen_types::{ +// avs::{SignedTaskResponseDigest, TaskIndex, TaskResponseDigest}, +// operator::{OperatorAvsState, QuorumThresholdPercentage, QuorumThresholdPercentages}, +// }; + +// use alloy_primitives::{FixedBytes, U256}; +// use std::collections::HashMap; +// use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; +// use tokio::time::{self, Duration}; + +// use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +// use std::sync::Arc; + +// #[allow(unused)] +// #[derive(Debug, Clone)] +// pub struct BlsAggregationServiceResponse { +// task_index: TaskIndex, +// task_response_digest: TaskResponseDigest, +// non_signers_pub_keys_g1: Vec, +// quorum_apks_g1: Vec, +// signers_apk_g2: G2Point, +// signers_agg_sig_g1: Signature, +// non_signer_quorum_bitmap_indices: Vec, +// quorum_apk_indices: Vec, +// total_stake_indices: Vec, +// non_signer_stake_indices: Vec>, +// } + +// #[derive(Debug, Clone)] +// pub struct AggregatedOperators { +// signers_apk_g2: G2Point, + +// signers_agg_sig_g1: Signature, + +// signers_total_stake_per_quorum: HashMap, + +// pub signers_operator_ids_set: HashMap, bool>, +// } + +// impl AggregatedOperators {} +// #[derive(Debug)] +// pub struct BlsAggregatorService { +// aggregated_response_sender: UnboundedSender, +// pub aggregated_response_receiver: UnboundedReceiver, +// signed_task_response: +// Arc>>>, +// avs_registry_service: AvsRegistryServiceChainCaller, +// } + +// impl BlsAggregatorService { +// pub fn new(avs_registry_service: AvsRegistryServiceChainCaller) -> Self { +// let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); +// Self { +// aggregated_response_sender: tx, +// aggregated_response_receiver: rx, +// signed_task_response: Arc::new(RwLock::new(HashMap::new())), +// avs_registry_service, +// } +// } + +// pub(crate) async fn write( +// &self, +// ) -> RwLockWriteGuard<'_, HashMap>> { +// self.signed_task_response.write() +// } + +// pub(crate) async fn read( +// &self, +// ) -> RwLockReadGuard<'_, HashMap>> { +// self.signed_task_response.read() +// } + +// pub async fn initialize_new_task( +// self: Arc, +// task_index: TaskIndex, +// task_created_block: u32, +// quorum_nums: Vec, +// quorum_threshold_percentages: QuorumThresholdPercentages, +// time_to_expiry: Duration, +// ) { +// let mut task_channel = self.write().await; + +// if task_channel.contains_key(&task_index) { +// // error +// } + +// let (tx, mut rx) = mpsc::unbounded_channel(); +// task_channel.insert(task_index, tx); +// let self_clone = self.clone(); +// tokio::spawn(async move { +// while let Some(signed_response) = rx.recv().await { +// // Process each signed response here +// self_clone +// .single_task_aggregator( +// task_index, +// task_created_block, +// quorum_nums.clone(), +// quorum_threshold_percentages.clone(), +// time_to_expiry, +// signed_response, +// ) +// .await; +// } +// }); +// } + +// /// Processs signatures +// pub async fn process_new_signature( +// &self, +// task_index: TaskIndex, +// task_response_digest: TaskResponseDigest, +// bls_signature: Signature, +// operator_id: FixedBytes<32>, +// ) { +// let task_channel = self.read().await; + +// if let Some(sender) = task_channel.get(&task_index) { +// let task = SignedTaskResponseDigest { +// task_response_digest, +// bls_signature, +// operator_id, +// }; +// let _ = sender.send(task); +// } +// } + +// pub async fn single_task_aggregator( +// &self, +// task_index: TaskIndex, +// task_created_block: u32, +// quorum_nums: Vec, +// quorum_threshold_percentages: QuorumThresholdPercentages, +// time_to_expiry: Duration, +// signed_task_digest: SignedTaskResponseDigest, +// ) { +// let mut quorum_threshold_percentage_map = HashMap::new(); + +// for (i, quorum_number) in quorum_nums.iter().enumerate() { +// quorum_threshold_percentage_map.insert(*quorum_number, quorum_threshold_percentages[i]); +// } + +// let mut operator_state_avs = self +// .avs_registry_service +// .get_operators_avs_state_at_block(task_created_block, quorum_nums.clone().into()) +// .await; +// // throw erro if + +// let quorums_avs_stake = self +// .avs_registry_service +// .get_quorums_avs_state_at_block(quorum_nums.clone().into(), task_created_block) +// .await; +// // throw erro if != nil + +// let mut total_stake_per_quorum = HashMap::new(); + +// for (quorum_num, quorum_avs_stake) in &quorums_avs_stake { +// total_stake_per_quorum.insert(*quorum_num, quorum_avs_stake.total_stake); +// } +// let mut quorum_apks_g1: Vec = vec![]; +// // let quorum_apks_g1 +// for quorum_number in quorum_nums.iter() { +// if let Some(val) = quorums_avs_stake.get(quorum_number) { +// quorum_apks_g1.push(G1Point::new( +// u256_to_bigint256(val.agg_pub_key_g1.X), +// u256_to_bigint256(val.agg_pub_key_g1.Y), +// )); +// } +// } + +// let task_expired_timer = time::sleep(time_to_expiry); + +// tokio::pin!(task_expired_timer); +// let mut aggregated_operators: HashMap, AggregatedOperators> = HashMap::new(); +// let _sig = self +// .verify_signature(task_index, &signed_task_digest, &operator_state_avs) +// .await; +// loop { +// tokio::select! { +// _ = &mut task_expired_timer =>{ +// // todo tracing +// println!("time expired"); +// break; +// }, +// else =>{ +// let mut aggregate_response: AggregatedOperators; +// if let Some(response) = aggregated_operators.get(&signed_task_digest.task_response_digest) { +// aggregate_response = response.clone(); +// if aggregated_operators.contains_key(&signed_task_digest.task_response_digest){ +// aggregate_response.signers_agg_sig_g1.get_g1_point().add(signed_task_digest.bls_signature.get_g1_point()); +// if let Some(op_avs_state) = operator_state_avs.get_mut(&signed_task_digest.operator_id){ +// if let Some(pub_key) =&op_avs_state.operator_info.pub_keys { +// let g2_pub_key = G2Point::new((u256_to_bigint256(pub_key.g2_pub_key.X[0]),u256_to_bigint256(pub_key.g2_pub_key.X[1])),(u256_to_bigint256(pub_key.g2_pub_key.Y[0]),u256_to_bigint256(pub_key.g2_pub_key.Y[1]))); +// aggregate_response.signers_apk_g2.add(g2_pub_key); + +// } +// } + +// aggregate_response.signers_operator_ids_set.insert(FixedBytes(*signed_task_digest.operator_id), true); + +// if let Some(state_avs) = operator_state_avs.get(&signed_task_digest.operator_id){ + +// for (quorum_num,stake) in state_avs.stake_per_quorum.clone(){ + +// if let Some(_quorum) = aggregate_response.signers_total_stake_per_quorum.get(&quorum_num){ +// aggregate_response.signers_total_stake_per_quorum.insert(quorum_num, U256::from(0)); + +// } +// aggregate_response.signers_total_stake_per_quorum.insert(quorum_num,aggregate_response.signers_total_stake_per_quorum[&quorum_num] + stake); + +// } +// } + +// } +// else{ +// let mut operator_id_set = HashMap::new(); +// operator_id_set.insert(signed_task_digest.operator_id,true); +// // first operator + +// if let Some(avs_state) = operator_state_avs.get(&signed_task_digest.operator_id.clone()){ + +// aggregate_response = AggregatedOperators{ +// signers_agg_sig_g1: signed_task_digest.bls_signature.clone(), +// signers_apk_g2 : G2Point::new_zero_g2_point(), +// signers_operator_ids_set: operator_id_set, +// signers_total_stake_per_quorum: avs_state.stake_per_quorum.clone() +// } ; +// } +// } + +// aggregated_operators.insert(signed_task_digest.task_response_digest, aggregate_response.clone()); +// // check stake threshold + +// if self.check_if_stake_thresholds_met(aggregate_response.signers_total_stake_per_quorum,total_stake_per_quorum.clone(),quorum_threshold_percentage_map.clone()){ +// let mut non_signers_operators_ids: Vec> = vec![]; +// for (i,op_info) in &operator_state_avs{ +// if aggregate_response.signers_operator_ids_set.contains_key(&op_info.operator_id){ +// non_signers_operators_ids.push(*i); +// } +// } + +// non_signers_operators_ids.sort_by(|a,b|{ +// a.cmp(b) +// }); + +// let mut non_signers_g1_pub_keys: Vec = vec![]; +// for operator_id in non_signers_operators_ids.iter(){ + +// if let Some(operator) = operator_state_avs.get(operator_id){ +// if let Some(keys) = &operator.operator_info.pub_keys{ +// let g1_key = G1Point::new(u256_to_bigint256(keys.g1_pub_key.X),u256_to_bigint256(keys.g1_pub_key.Y)); +// non_signers_g1_pub_keys.push(g1_key); +// } +// } + +// } + +// let indices = self.avs_registry_service.get_avs_registry().get_check_signatures_indices(task_created_block,quorum_nums.clone(),non_signers_operators_ids).await.unwrap(); + +// let bls_aggregation_service_response = BlsAggregationServiceResponse{ +// task_index, +// task_response_digest: signed_task_digest.task_response_digest, +// non_signers_pub_keys_g1: non_signers_g1_pub_keys, +// quorum_apks_g1: quorum_apks_g1.clone(), +// signers_apk_g2: aggregate_response.signers_apk_g2, +// signers_agg_sig_g1: aggregate_response.signers_agg_sig_g1, +// non_signer_quorum_bitmap_indices: indices.clone().quorumApkIndices, +// quorum_apk_indices: indices.quorumApkIndices, +// total_stake_indices: indices.totalStakeIndices, +// non_signer_stake_indices: indices.nonSignerStakeIndices + +// }; + +// let _ = self.aggregated_response_sender.send(bls_aggregation_service_response); + +// } + +// } + +// } +// } +// } +// } + +// pub async fn verify_signature( +// &self, +// _task_index: TaskIndex, +// signed_task_response_digest: &SignedTaskResponseDigest, +// operator_avs_state: &HashMap, OperatorAvsState>, +// ) { +// if let Some(operator_state) = +// operator_avs_state.get(&signed_task_response_digest.operator_id) +// { +// if let Some(pub_keys) = &operator_state.operator_info.pub_keys { +// let g2_proj = G2Point::new( +// ( +// u256_to_bigint256(pub_keys.g2_pub_key.X[0]), +// u256_to_bigint256(pub_keys.g2_pub_key.X[1]), +// ), +// ( +// u256_to_bigint256(pub_keys.g2_pub_key.Y[0]), +// u256_to_bigint256(pub_keys.g2_pub_key.Y[1]), +// ), +// ) +// .point; +// let _signature_verified = signed_task_response_digest +// .bls_signature +// .verify_signature(g2_proj, &signed_task_response_digest.task_response_digest); +// } +// } else { +// // throw error +// } +// } + +// pub fn check_if_stake_thresholds_met( +// &self, +// signed_stake_per_quorum: HashMap, +// total_stake_per_quorum: HashMap, +// quorum_threshold_percentages_map: HashMap, +// ) -> bool { +// if let Some((quorum_num, quorum_threshold_percentage)) = +// quorum_threshold_percentages_map.into_iter().next() +// { +// // to do check if quorum num <= u8 max assert +// if let Some(signed_stake_by_quorum) = signed_stake_per_quorum.get(&quorum_num) { +// if let Some(total_stake_by_quorum) = total_stake_per_quorum.get(&quorum_num) { +// let signed_stake = signed_stake_by_quorum * U256::from(100); +// let threshold_stake = +// *total_stake_by_quorum * U256::from(quorum_threshold_percentage); +// return signed_stake >= threshold_stake; +// } else { +// return false; +// } +// } else { +// return false; +// } +// } + +// true +// } +// } diff --git a/crates/services/bls_aggregation/src/lib.rs b/crates/services/bls_aggregation/src/lib.rs index 4590a8dad..99a17600c 100644 --- a/crates/services/bls_aggregation/src/lib.rs +++ b/crates/services/bls_aggregation/src/lib.rs @@ -2,6 +2,6 @@ html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" )] -#![cfg_attr(not(test), warn(unused_crate_dependencies))] +// #![cfg_attr(not(test), warn(unused_crate_dependencies))] pub mod bls_agg; diff --git a/crates/types/src/avs.rs b/crates/types/src/avs.rs index 805c4771b..64c5a86b3 100644 --- a/crates/types/src/avs.rs +++ b/crates/types/src/avs.rs @@ -1,5 +1,5 @@ use alloy_primitives::FixedBytes; -use eigen_crypto_bls::attestation::Signature; +use eigen_crypto_bls::Signature; pub type TaskIndex = u32; diff --git a/crates/utils/src/binding.rs b/crates/utils/src/binding.rs index c183fbb48..063d388c2 100644 --- a/crates/utils/src/binding.rs +++ b/crates/utils/src/binding.rs @@ -13,6 +13,7 @@ sol!( #[allow(clippy::too_many_arguments)] #[allow(missing_docs)] #[sol(rpc)] + #[derive(Debug)] RegistryCoordinator, "../../crates/contracts/bindings/utils/json/RegistryCoordinator.json" ); diff --git a/examples/avsregistry-write/Cargo.toml b/examples/avsregistry-write/Cargo.toml index 1b1b1c5bb..3ca609403 100644 --- a/examples/avsregistry-write/Cargo.toml +++ b/examples/avsregistry-write/Cargo.toml @@ -15,7 +15,11 @@ workspace = true alloy-primitives.workspace = true alloy-provider.workspace = true ark-bn254 = "0.4.0" -eyre.workspace = true +ark-ff.workspace = true +ark-serialize = "0.4" +ark-std = { version = "0.4.0", default-features = false } +ark-ec = { version = "0.4.2", default-features = false } +alloy-signer-local.workspace = true eigen-chainio-utils.workspace = true eigen-client-avsregistry.workspace = true eigen-client-elcontracts.workspace = true @@ -23,6 +27,9 @@ eigen-crypto-bls.workspace = true eigen-crypto-bn254.workspace = true eigen-testing-utils.workspace = true eigen-utils.workspace = true +eigen-types.workspace = true +eigen-logging.workspace = true +eyre.workspace = true +lazy_static = "1.5.0" tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } - diff --git a/examples/avsregistry-write/examples/register_operator_in_quorum_with_avs_registry_coordinator.rs b/examples/avsregistry-write/examples/register_operator_in_quorum_with_avs_registry_coordinator.rs index 66abfbb15..7cec85120 100644 --- a/examples/avsregistry-write/examples/register_operator_in_quorum_with_avs_registry_coordinator.rs +++ b/examples/avsregistry-write/examples/register_operator_in_quorum_with_avs_registry_coordinator.rs @@ -1,65 +1,110 @@ //! register operator in quorum with avs registry coordinator -// use alloy_primitives::{FixedBytes,Bytes}; -// use eigen_client_avsregistry::writer::AvsRegistryChainWriter; -// use eigen_client_elcontracts::reader::ELChainReader; -// use eigen_testing_utils::m2_holesky_constants::{ -// AVS_DIRECTORY_ADDRESS, BLS_APK_REGISTRY, DELEGATION_MANAGER_ADDRESS, OPERATOR_STATE_RETRIEVER, -// REGISTRY_COORDINATOR, SERVICE_MANAGER_ADDRESS, SLASHER_ADDRESS, STAKE_REGISTRY, -// }; -// use std::str::FromStr; -// use eigen_chainio_utils::convert_to_bn254_g1_point; -// use ark_bn254::{Fr,G1Affine,Fq}; -// use alloy_provider::Provider; -// use alloy_primitives::{U256}; -// use eigen_utils::get_provider; -// use eigen_crypto_bls::attestation::{KeyPair}; -// use eyre::Result; -// use ark_ff::{fields::PrimeField}; -// use ark_ff::{BigInt, BigInteger}; -// #[tokio::main] -// async fn main() -> Result<()> { -// let holesky_provider = "https://holesky.drpc.org"; -// let pvt_key = "160443ef7d1ada994b300f7d2bf88db16217db6f825708e4b23f69aa028d7c8c"; -// let el_chain_reader: ELChainReader = ELChainReader::new( -// SLASHER_ADDRESS, -// DELEGATION_MANAGER_ADDRESS, -// AVS_DIRECTORY_ADDRESS, -// holesky_provider.to_string(), -// ); -// let avs_registry_writer = AvsRegistryChainWriter::new( -// SERVICE_MANAGER_ADDRESS, -// REGISTRY_COORDINATOR, -// OPERATOR_STATE_RETRIEVER, -// STAKE_REGISTRY, -// BLS_APK_REGISTRY, -// el_chain_reader, -// holesky_provider.to_string(), -// pvt_key.to_string(), -// ) -// .await; +use alloy_primitives::U256; +use alloy_primitives::{Bytes, FixedBytes}; +use alloy_signer_local::PrivateKeySigner; +use eigen_client_avsregistry::writer::AvsRegistryChainWriter; +use eigen_client_elcontracts::reader::ELChainReader; +use eigen_client_elcontracts::writer::ELChainWriter; +use eigen_crypto_bls::BlsKeyPair; +use eigen_logging::get_test_logger; +use eigen_testing_utils::m2_holesky_constants::{ + AVS_DIRECTORY_ADDRESS, DELEGATION_MANAGER_ADDRESS, OPERATOR_STATE_RETRIEVER, + REGISTRY_COORDINATOR, SLASHER_ADDRESS, STRATEGY_MANAGER_ADDRESS, +}; +use eigen_types::operator::Operator; +use eyre::Result; +use lazy_static::lazy_static; +use std::str::FromStr; +use std::time::{SystemTime, UNIX_EPOCH}; -// let key_pair :KeyPair = KeyPair::from_string(pvt_key.to_string())?; -// let digest_hash :FixedBytes<32>= FixedBytes::from([0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02]) ; -// let provider = get_provider(&holesky_provider.to_string()); -// let current_block_number = provider.get_block_number().await?; -// let sig_expiry : U256 = U256::from(current_block_number + 20); -// let quorum_nums = Bytes::from([0x01]); -// println!("quorum nums : {:?}",quorum_nums); -// let tx_hash = avs_registry_writer.register_operator_in_quorum_with_avs_registry_coordinator(key_pair,digest_hash,U256::from(1718697416),quorum_nums,"65.109.158.181:33078;31078".to_string()).await.unwrap(); -// println!("tx hash :{:?}",tx_hash); -// Ok(()) -// } +lazy_static! { + /// 1 day + static ref SIGNATURE_EXPIRY: U256 = U256::from(86400); +} +#[tokio::main] +async fn main() -> Result<()> { + let holesky_provider = "https://ethereum-holesky.blockpi.network/v1/rpc/public"; + let pvt_key = "bead471191bea97fc3aeac36c9d74c895e8a6242602e144e43152f96219e96e8"; + let test_logger = get_test_logger(); + let avs_registry_writer = AvsRegistryChainWriter::build_avs_registry_chain_writer( + test_logger.clone(), + holesky_provider.to_string(), + pvt_key.to_string(), + REGISTRY_COORDINATOR, + OPERATOR_STATE_RETRIEVER, + ) + .await + .expect("avs writer build fail "); -// pub fn deserialize_montgomery_elements(data: &[Fr], buffer: &mut Vec) { -// let mut temp_buffer: Vec = data -// .iter() -// .rev() -// .flat_map(|elem| elem.into_bigint().to_bytes_le()) -// .collect(); + // Create a new key pair instance using the secret key + let bls_key_pair = BlsKeyPair::new( + "12248929636257230549931416853095037629726205319386239410403476017439825112537".to_string(), + ) + .unwrap(); -// temp_buffer.reverse(); -// buffer.extend(temp_buffer); -// } + let digest_hash: FixedBytes<32> = FixedBytes::from([ + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, + ]); -#[tokio::main] -async fn main() {} + // Get the current SystemTime + let now = SystemTime::now(); + let mut sig_expiry: U256 = U256::from(0); + // Convert SystemTime to a Duration since the UNIX epoch + if let Ok(duration_since_epoch) = now.duration_since(UNIX_EPOCH) { + // Convert the duration to seconds + let seconds = duration_since_epoch.as_secs(); // Returns a u64 + + // Convert seconds to U256 + sig_expiry = U256::from(seconds) + *SIGNATURE_EXPIRY; + } else { + println!("System time seems to be before the UNIX epoch."); + } + let quorum_nums = Bytes::from([0x01]); + + // A new ElChainReader instance + let el_chain_reader = ELChainReader::new( + get_test_logger().clone(), + SLASHER_ADDRESS, + DELEGATION_MANAGER_ADDRESS, + AVS_DIRECTORY_ADDRESS, + "https://ethereum-holesky.blockpi.network/v1/rpc/public".to_string(), + ); + // A new ElChainWriter instance + let el_writer = ELChainWriter::new( + DELEGATION_MANAGER_ADDRESS, + STRATEGY_MANAGER_ADDRESS, + el_chain_reader, + "https://ethereum-holesky.blockpi.network/v1/rpc/public".to_string(), + "bead471191bea97fc3aeac36c9d74c895e8a6242602e144e43152f96219e96e8".to_string(), + ); + + let wallet = PrivateKeySigner::from_str( + "bead471191bea97fc3aeac36c9d74c895e8a6242602e144e43152f96219e96e8", + ) + .expect("no key "); + + let operator_details = Operator::new( + wallet.address(), + wallet.address(), + wallet.address(), + 3, + Some("eigensdk-rs".to_string()), + ); + // Register the address as operator in delegation manager + let _s = el_writer.register_as_operator(operator_details).await; + + // Register the operator in registry coordinator + avs_registry_writer + .register_operator_in_quorum_with_avs_registry_coordinator( + bls_key_pair, + digest_hash, + sig_expiry, + quorum_nums, + "65.109.158.181:33078;31078".to_string(), // socket + ) + .await + .unwrap(); + Ok(()) +}