Skip to content

Commit

Permalink
Merge pull request #202 from NethermindEth/mu/bls-service
Browse files Browse the repository at this point in the history
Use blst crate for bls-service
  • Loading branch information
mikhailUshakoff authored Jan 8, 2025
2 parents 414069b + 649fa23 commit 6d2668a
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 220 deletions.
134 changes: 8 additions & 126 deletions Node/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 1 addition & 4 deletions Node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,11 @@ bincode = "1.3"
serde_bytes = "0.11"
clap = "4.5"
futures-util = "0.3"
ethereum_ssz = "0.7"
ethereum_ssz_derive = "0.7"
bls_on_arkworks = "0.3.0"
num-bigint = "0.4.6"
rand = "0.8"
tree_hash = "0.6.0"
tree_hash_derive = "0.6.0"
reth-primitives = { git = "https://github.com/paradigmxyz/reth", rev = "5dd5555c5c7d8e43420e273e7005b8af63a847a5" }
blst = "0.3"

[dev-dependencies]
mockall_double = "0.3"
Expand Down
102 changes: 39 additions & 63 deletions Node/src/bls/mod.rs
Original file line number Diff line number Diff line change
@@ -1,98 +1,74 @@
use alloy::primitives::U256;
use anyhow::Error;
use bls::types::{G1AffinePoint, G2AffinePoint, PublicKey, SecretKey, Signature};
use bls_on_arkworks as bls;
use ethereum_consensus::crypto::{PublicKey as EthereumPublicKey, SecretKey as EthereumSecretKey};
use ethereum_consensus::primitives::BlsSignature;
use num_bigint::BigUint;

use blst::min_pk::{PublicKey, SecretKey, Signature};
#[cfg(test)]
#[cfg(not(feature = "use_mock"))]
use rand_core::{OsRng, RngCore};

pub struct BLSService {
pk: PublicKey,
sk: SecretKey,
eth_secret_key: EthereumSecretKey,
eth_public_key: EthereumPublicKey,
}

impl BLSService {
pub fn new(private_key: &str) -> Result<Self, Error> {
let pk_bytes = alloy::hex::decode(private_key)
.map_err(|e| anyhow::anyhow!("BLSService: failed to decode private key: {}", e))?;
let sk = bls::os2ip(&pk_bytes);
let public_key = bls::sk_to_pk(sk);

let eth_secret_key = EthereumSecretKey::try_from(private_key.to_string())
.map_err(|e| anyhow::anyhow!("Invalid secret key: {:?}", e))?;
let eth_public_key = eth_secret_key.public_key();

tracing::info!(
"BLSService: public key: {}",
hex::encode(public_key.clone())
);

Ok(Self {
pk: public_key,
sk,
eth_public_key,
eth_secret_key,
})
.map_err(|e| anyhow::anyhow!("BLSService: failed to decode secret key: {}", e))?;
let sk = SecretKey::from_bytes(&pk_bytes).map_err(|e| {
anyhow::anyhow!(
"BLSService: failed to create secret key from bytes: {:?}",
e
)
})?;
let pk = sk.sk_to_pk();

Ok(Self { pk, sk })
}

#[cfg(test)]
#[cfg(not(feature = "use_mock"))]
pub fn generate_key() -> Self {
pub fn generate_key() -> Result<Self, Error> {
let mut ikm = [0u8; 64];
OsRng.fill_bytes(&mut ikm);

let sk = bls::keygen(&ikm.to_vec());
let pk = bls::sk_to_pk(sk);

let eth_secret_key = EthereumSecretKey::random(&mut OsRng).unwrap();
let eth_public_key = eth_secret_key.public_key();

Self {
pk,
sk,
eth_public_key,
eth_secret_key,
}
}
let sk = SecretKey::key_gen(&ikm.to_vec(), &[])
.map_err(|e| anyhow::anyhow!("BLSService: failed to generate secret key: {:?}", e))?;
let pk = sk.sk_to_pk();

pub fn sign(&self, message: &Vec<u8>, dst: &Vec<u8>) -> Signature {
bls::sign(self.sk, message, dst).unwrap()
Ok(Self { pk, sk })
}

pub fn sign_as_point(&self, message: &Vec<u8>, dst: &Vec<u8>) -> G2AffinePoint {
let sign = self.sign(message, dst);
bls::signature_to_point(&sign).unwrap()
pub fn sign(&self, message: &[u8], dst: &[u8]) -> Signature {
self.sk.sign(message, dst, &[])
}

pub fn biguint_to_u256_array(biguint: BigUint) -> [U256; 2] {
let s = format!("{:0>96x}", biguint);
let res1 = U256::from_str_radix(&s[0..32], 16).unwrap();
let res2 = U256::from_str_radix(&s[32..96], 16).unwrap();

fn to_contract_layout(value: &[u8; 48]) -> [U256; 2] {
let mut buffer = [0u8; 32];
buffer[16..32].copy_from_slice(&value[0..16]);
let res1: alloy::primitives::Uint<256, 4> = U256::from_be_bytes::<32>(buffer);
let res2: alloy::primitives::Uint<256, 4> =
U256::from_be_bytes::<32>(value[16..48].try_into().unwrap());
[res1, res2]
}

#[cfg(test)]
#[cfg(not(feature = "use_mock"))]
pub fn get_public_key_compressed(&self) -> PublicKey {
self.pk.clone()
}

pub fn get_public_key(&self) -> G1AffinePoint {
bls::pubkey_to_point(&self.pk).unwrap()
pub fn pubkey_to_g1_point(&self) -> [[U256; 2]; 2] {
let pk = self.get_public_key().serialize();
let x = Self::to_contract_layout(pk[0..48].try_into().unwrap());
let y = Self::to_contract_layout(pk[48..96].try_into().unwrap());
[x, y]
}

pub fn get_ethereum_public_key(&self) -> EthereumPublicKey {
self.eth_public_key.clone()
pub fn signature_to_g2_point(&self, signature: &Signature) -> [[U256; 2]; 4] {
let signature = signature.serialize();
let x = Self::to_contract_layout(signature[0..48].try_into().unwrap());
let x_i = Self::to_contract_layout(signature[48..96].try_into().unwrap());
let y = Self::to_contract_layout(signature[96..144].try_into().unwrap());
let y_i = Self::to_contract_layout(signature[144..192].try_into().unwrap());
[x, x_i, y, y_i]
}

pub fn sign_with_ethereum_secret_key(&self, message: &[u8]) -> Result<BlsSignature, Error> {
let signature = self.eth_secret_key.sign(message);
Ok(signature)
pub fn get_public_key(&self) -> PublicKey {
self.pk
}
}
Loading

0 comments on commit 6d2668a

Please sign in to comment.