use std::path::PathBuf;
use crate::keys::{
error::{KeyError, KeyResult},
get_bls_key_path,
storage::{read_key_file, write_key_file},
};
use ark_bn254::{Fr, G1Projective};
use ark_ec::PrimeGroup;
use ark_ff::{BigInteger, PrimeField, UniformRand};
use newton_crypto_bls::BlsKeyPair;
use rand_core::OsRng;
use rust_bls_bn254::keystores::base_keystore::Keystore;
use tracing::{debug, info};
use alloy::primitives::{B256, U256};
pub fn load_bls_key_from_path(path: &str) -> KeyResult<BlsKeyPair> {
debug!("Loading BLS key: {}", path);
let hex_key = read_key_file(&PathBuf::from(path))?;
let hex_key = hex_key.strip_prefix("0x").unwrap_or(&hex_key);
let key_bytes = hex::decode(hex_key).map_err(KeyError::HexDecode)?;
let fr_key: String = key_bytes.iter().map(|&b| b as char).collect();
let key_pair = BlsKeyPair::new(fr_key)
.map_err(|e| KeyError::BlsKeypair(eyre::eyre!("Failed to create BLS keypair: {}", e)))?;
debug!("Loaded BLS key: {}", path);
Ok(key_pair)
}
pub fn get_bls_public_from_path(path: &str) -> KeyResult<G1Projective> {
let hex_key = read_key_file(&PathBuf::from(path))?;
let hex_key = hex_key.strip_prefix("0x").unwrap_or(&hex_key);
let key_bytes = hex::decode(hex_key).map_err(KeyError::HexDecode)?;
let sk = Fr::from_le_bytes_mod_order(&key_bytes);
let pk = G1Projective::generator().mul_bigint((sk).into_bigint());
Ok(pk)
}
pub fn load_bls_key_from_keystore(keystore_path: &str, keystore_password: &str) -> KeyResult<BlsKeyPair> {
let keystore = Keystore::from_file(keystore_path)
.map_err(|e| KeyError::InvalidKey(format!("Failed to load BLS keystore: {}", e)))?
.decrypt(keystore_password)
.map_err(|e| KeyError::InvalidKey(format!("Failed to decrypt BLS keystore: {}", e)))?;
let key_bytes: Vec<u8> = keystore;
let big_int = num_bigint::BigUint::from_bytes_be(&key_bytes);
let decimal_key = big_int.to_string();
BlsKeyPair::new(decimal_key).map_err(|e| KeyError::BlsKeypair(eyre::eyre!("Failed to create BLS keypair: {}", e)))
}
pub fn load_operator_bls_key(bls_private_key: &str) -> KeyResult<BlsKeyPair> {
BlsKeyPair::new(bls_private_key.to_string())
.map_err(|e| KeyError::BlsKeypair(eyre::eyre!("Failed to create BLS keypair: {}", e)))
}
#[cfg(test)]
mod tests {
use crate::keys::ecdsa::load_operator_ecdsa_key;
use super::*;
use crate::{
newton_prover_task_manager::{INewtonPolicy, INewtonProverTaskManager::TaskResponse, NewtonMessage},
r#newton_prover_task_manager::NewtonProverTaskManager,
};
use alloy::{
primitives::{keccak256, Address, Bytes, B256, U256},
sol_types::SolValue,
};
use newton_crypto_bn254::utils::verify_message;
#[test]
fn test_load_operator_keys_and_verify_signature() {
let bls_private_key = "5665911737697037570291183107345399045458787373029916535446553888385923852145";
let ecdsa_private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
let bls_keypair = load_operator_bls_key(bls_private_key).expect("Failed to load BLS key");
info!("Successfully loaded BLS key");
let ecdsa_signer = load_operator_ecdsa_key(ecdsa_private_key).expect("Failed to load ECDSA key");
info!("Successfully loaded ECDSA key");
info!("ECDSA Address: {}", ecdsa_signer.address());
let task_response = TaskResponse {
taskId: B256::from([1u8; 32]),
policyClient: Address::from([2u8; 20]),
policyId: B256::from([3u8; 32]),
policyAddress: Address::from([4u8; 20]),
intent: NewtonMessage::Intent {
from: Address::from([5u8; 20]),
to: Address::from([6u8; 20]),
value: U256::from(1000),
data: [0x01, 0x02, 0x03].into(),
chainId: U256::from(1),
functionSignature: [0x04, 0x05].into(),
},
intentSignature: Bytes::default(),
evaluationResult: [0x01].into(), policyTaskData: NewtonMessage::PolicyTaskData {
policyId: B256::from([3u8; 32]),
policyAddress: Address::from([4u8; 20]),
policy: Bytes::default(),
policyData: vec![],
},
policyConfig: INewtonPolicy::PolicyConfig {
policyParams: Bytes::default(),
expireAfter: 0,
},
initializationTimestamp: U256::ZERO,
};
let encoded_response = task_response.abi_encode();
info!("Encoded response length: {}", encoded_response.len());
let message_hash = keccak256(&encoded_response);
info!("Message hash: {:?}", message_hash);
let signature = bls_keypair.sign_message(&message_hash.into());
info!("Successfully signed message with BLS key");
let is_valid = verify_message(
bls_keypair.public_key_g2().g2(),
&message_hash,
signature.g1_point().g1(),
);
assert!(is_valid, "BLS signature verification failed");
info!(" BLS signature verification successful");
let public_key_g1 = bls_keypair.public_key().g1();
info!("BLS Public Key G1: {:?}", public_key_g1);
let public_key_g2 = bls_keypair.public_key_g2().g2();
info!("BLS Public Key G2: {:?}", public_key_g2);
}
#[test]
fn test_load_bls_key_with_different_formats() {
let bls_private_key = "5665911737697037570291183107345399045458787373029916535446553888385923852145";
let keypair1 = load_operator_bls_key(bls_private_key).expect("Failed to load BLS key");
let pk1 = keypair1.public_key().g1();
info!("Public key loaded successfully: {:?}", pk1);
let keypair2 = load_operator_bls_key(bls_private_key).expect("Failed to load BLS key second time");
let pk2 = keypair2.public_key().g1();
assert_eq!(pk1, pk2, "Public keys should be identical for the same private key");
}
#[test]
fn test_multiple_message_signatures() {
let bls_private_key = "5665911737697037570291183107345399045458787373029916535446553888385923852145";
let bls_keypair = load_operator_bls_key(bls_private_key).expect("Failed to load BLS key");
let messages = [B256::from([1u8; 32]), B256::from([2u8; 32]), B256::from([255u8; 32])];
for (i, message) in messages.iter().enumerate() {
let signature = bls_keypair.sign_message(&(*message).into());
let is_valid = verify_message(bls_keypair.public_key_g2().g2(), message, signature.g1_point().g1());
assert!(is_valid, "Message {} verification failed", i);
info!(" Message {} signature verified", i);
}
}
#[test]
fn test_verify_operator_bls_keys_sepolia_stagef() {
use ark_ec::AffineRepr;
use newton_crypto_bls::convert_to_g1_point;
fn compute_operator_id(g1: ark_bn254::G1Affine) -> B256 {
let g1_point = convert_to_g1_point(g1).expect("Failed to convert G1 point");
let mut encoded = Vec::with_capacity(64);
encoded.extend_from_slice(&g1_point.X.to_be_bytes::<32>());
encoded.extend_from_slice(&g1_point.Y.to_be_bytes::<32>());
keccak256(&encoded)
}
let operators = [
(
"Operator 1 (0x0B26205c99A7669cCC6Dfe4D95CaCC5BfE62e2fe)",
"3437392234444159768111770309164609957102690468096034096776626309734712123977",
"0xfd8c33b1612b4bccb01926d9ff26aa56ac768bb493346adeec36b2538b51e8c1",
"3921767720995179277909625244037822258046941948782863550120879716817940452717",
"9466587799414527615865516490417180554460539059429958111726479271529872103751",
),
(
"Operator 2 (0x84C2662C0359dA7ac2101c7392ab767A4A80Cf96)",
"7019086643264615414456756527632272354703097262265640370649595594745347218247",
"0x03f232d0b0d939f8987208c7196f46bcd79310137277480595e140bab0b8a2f0",
"5785384538136481768800205166274937495894624497780844126780399836164351973025",
"21407700507482687489947338356096094467844731053681107079477243210556238999880",
),
(
"Operator 2 (0x6FAf85Dda4e07300418beDc31AF6621383de65E8)",
"17338602372173648149501880755323073193946756536467840304826772396306052737333",
"0xfe0742d124d105dcfb28b845a89035e7c92de3ff36d32606caf2099017a31974",
"13185909042843528655162451917016584196037912218358625181215090182994157198053",
"13575221952311471737620708106833236715951854541195392557376226506693517828827",
),
];
println!("\n=== BLS Key Derivation Verification ===\n");
for (name, bls_private_key, expected_op_id, expected_g1_x, expected_g1_y) in operators {
println!("Verifying: {}", name);
println!(" BLS Private Key: {}", bls_private_key);
let keypair = load_operator_bls_key(bls_private_key).expect("Failed to load BLS key");
let g1 = keypair.public_key().g1();
let (g1_x, g1_y) = if let (Some(x), Some(y)) = (g1.x(), g1.y()) {
(x.to_string(), y.to_string())
} else {
("infinity".to_string(), "infinity".to_string())
};
let g2 = keypair.public_key_g2().g2();
let g2_coords = if let (Some(x), Some(y)) = (g2.x(), g2.y()) {
format!("X_c0={}, X_c1={}, Y_c0={}, Y_c1={}", x.c0, x.c1, y.c0, y.c1)
} else {
"infinity".to_string()
};
let derived_op_id = compute_operator_id(keypair.public_key().g1());
let derived_op_id_hex = format!("0x{}", hex::encode(derived_op_id.as_slice()));
println!(" Derived G1_X: {}", g1_x);
println!(" Derived G1_Y: {}", g1_y);
println!(" Derived G2: {}", g2_coords);
println!(" Derived Operator ID: {}", derived_op_id_hex);
println!(" Expected Operator ID: {}", expected_op_id);
let g1_x_matches = g1_x == expected_g1_x;
let g1_y_matches = g1_y == expected_g1_y;
let op_id_matches = derived_op_id_hex.to_lowercase() == expected_op_id.to_lowercase();
println!(" G1_X matches: {}", g1_x_matches);
println!(" G1_Y matches: {}", g1_y_matches);
println!(" Operator ID matches: {}", op_id_matches);
if g1_x_matches && g1_y_matches && op_id_matches {
println!(" ✓ VERIFIED: Private key derives to on-chain G1 pubkey\n");
} else {
println!(" ✗ MISMATCH: Private key does NOT derive to on-chain G1 pubkey!");
println!(" Expected G1_X: {}", expected_g1_x);
println!(" Expected G1_Y: {}", expected_g1_y);
println!();
}
}
}
#[test]
fn test_verify_g2_aggregation() {
use ark_ec::{AffineRepr, CurveGroup};
let op1_bls_key = "3437392234444159768111770309164609957102690468096034096776626309734712123977";
let op1_keypair = load_operator_bls_key(op1_bls_key).expect("Failed to load Operator 1 BLS key");
let op2_bls_key = "7019086643264615414456756527632272354703097262265640370649595594745347218247";
let op2_keypair = load_operator_bls_key(op2_bls_key).expect("Failed to load Operator 2 BLS key");
let op1_g2 = op1_keypair.public_key_g2().g2();
let op2_g2 = op2_keypair.public_key_g2().g2();
let aggregated_g2 = (op1_g2 + op2_g2).into_affine();
println!("\n=== G2 Aggregation Verification ===\n");
if let (Some(x), Some(y)) = (op1_g2.x(), op1_g2.y()) {
println!("Operator 1 G2:");
println!(" X_c0 = {}", x.c0);
println!(" X_c1 = {}", x.c1);
println!(" Y_c0 = {}", y.c0);
println!(" Y_c1 = {}", y.c1);
}
if let (Some(x), Some(y)) = (op2_g2.x(), op2_g2.y()) {
println!("\nOperator 2 G2:");
println!(" X_c0 = {}", x.c0);
println!(" X_c1 = {}", x.c1);
println!(" Y_c0 = {}", y.c0);
println!(" Y_c1 = {}", y.c1);
}
if let (Some(x), Some(y)) = (aggregated_g2.x(), aggregated_g2.y()) {
println!("\nExpected Aggregated G2 (Op1 + Op2):");
println!(" X_c0 = {}", x.c0);
println!(" X_c1 = {}", x.c1);
println!(" Y_c0 = {}", y.c0);
println!(" Y_c1 = {}", y.c1);
let logged_x_c0 = "14353610553595172534056806588837466963076630321468849559816767082177709710634";
let logged_x_c1 = "8614678016146218371314685919997481237934655769445601302232162555523220039328";
let logged_y_c0 = "11923179702360463644198799684718882158376252611210558687905593530626203466916";
let logged_y_c1 = "21202544982869411316901470582335588974306682123429582574592263080885762817812";
println!("\nLogged Aggregated G2 (from Datadog):");
println!(" X_c0 = {}", logged_x_c0);
println!(" X_c1 = {}", logged_x_c1);
println!(" Y_c0 = {}", logged_y_c0);
println!(" Y_c1 = {}", logged_y_c1);
let x_c0_match = x.c0.to_string() == logged_x_c0;
let x_c1_match = x.c1.to_string() == logged_x_c1;
let y_c0_match = y.c0.to_string() == logged_y_c0;
let y_c1_match = y.c1.to_string() == logged_y_c1;
println!("\nComparison:");
println!(" X_c0 matches: {}", x_c0_match);
println!(" X_c1 matches: {}", x_c1_match);
println!(" Y_c0 matches: {}", y_c0_match);
println!(" Y_c1 matches: {}", y_c1_match);
if x_c0_match && x_c1_match && y_c0_match && y_c1_match {
println!("\n✓ AGGREGATED G2 IS CORRECT");
} else {
println!("\n✗ AGGREGATED G2 MISMATCH - BN254 pairing will fail!");
}
}
}
}