use crate::runtime::functions::RuntimeError;
use crate::runtime::values::Value;
use crate::stdlib::crypto_signatures::SecureSignatureVerifier;
use sha2::{Digest, Sha256};
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct CrossChainSecurityManager {
chain_configs: HashMap<i64, ChainSecurityConfig>,
trusted_bridges: HashMap<String, BridgeConfig>,
pending_operations: HashMap<String, CrossChainOperation>,
signature_verifier: SecureSignatureVerifier,
}
#[derive(Debug, Clone)]
pub struct ChainSecurityConfig {
pub chain_id: i64,
pub name: String,
pub signature_scheme: SignatureScheme,
pub min_confirmations: u32,
pub max_gas_price: u64,
pub trusted_validators: Vec<String>,
pub security_level: SecurityLevel,
}
#[derive(Debug, Clone)]
pub enum SignatureScheme {
ECDSA, EdDSA, Custom(String),
}
#[derive(Debug, Clone)]
pub enum SecurityLevel {
High, Medium, Low, }
#[derive(Debug, Clone)]
pub struct BridgeConfig {
pub bridge_id: String,
pub source_chain: i64,
pub target_chain: i64,
pub bridge_contract: String,
pub validator_set: Vec<String>,
pub min_validator_signatures: u32,
pub max_transaction_amount: u64,
pub security_deposit: u64,
pub is_active: bool,
}
#[derive(Debug, Clone)]
pub struct CrossChainOperation {
pub operation_id: String,
pub source_chain: i64,
pub target_chain: i64,
pub operation_type: CrossChainOperationType,
pub data: Vec<u8>,
pub signatures: Vec<ValidatorSignature>,
pub status: OperationStatus,
pub created_at: u64,
pub timeout: u64,
}
#[derive(Debug, Clone)]
pub enum CrossChainOperationType {
Transfer {
from: String,
to: String,
amount: u64,
},
ContractCall {
contract: String,
function: String,
args: Vec<u8>,
},
StateSync {
state_hash: String,
proof: Vec<u8>,
},
ValidatorUpdate {
new_validators: Vec<String>,
},
}
#[derive(Debug, Clone)]
pub struct ValidatorSignature {
pub validator_address: String,
pub signature: String,
pub timestamp: u64,
pub chain_id: i64,
}
#[derive(Debug, Clone)]
pub enum OperationStatus {
Pending,
Validating,
Confirmed,
Failed,
Timeout,
}
impl CrossChainSecurityManager {
pub fn new() -> Self {
let mut manager = Self {
chain_configs: HashMap::new(),
trusted_bridges: HashMap::new(),
pending_operations: HashMap::new(),
signature_verifier: SecureSignatureVerifier::new(),
};
manager.init_default_chains();
manager
}
fn init_default_chains(&mut self) {
self.chain_configs.insert(
1,
ChainSecurityConfig {
chain_id: 1,
name: "Ethereum Mainnet".to_string(),
signature_scheme: SignatureScheme::ECDSA,
min_confirmations: 12,
max_gas_price: 500_000_000_000, trusted_validators: vec![
"0x1234567890123456789012345678901234567890".to_string(),
"0x2345678901234567890123456789012345678901".to_string(),
],
security_level: SecurityLevel::High,
},
);
self.chain_configs.insert(
137,
ChainSecurityConfig {
chain_id: 137,
name: "Polygon".to_string(),
signature_scheme: SignatureScheme::ECDSA,
min_confirmations: 256,
max_gas_price: 1000_000_000_000, trusted_validators: vec![
"0x3456789012345678901234567890123456789012".to_string(),
"0x4567890123456789012345678901234567890123".to_string(),
],
security_level: SecurityLevel::Medium,
},
);
self.chain_configs.insert(
101,
ChainSecurityConfig {
chain_id: 101,
name: "Solana".to_string(),
signature_scheme: SignatureScheme::EdDSA,
min_confirmations: 32,
max_gas_price: 5000, trusted_validators: vec![
"7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU".to_string(),
"9QU2QSxhb24FUX3Tu2FpczXjpK3VYrvRudywSZaM29mF".to_string(),
],
security_level: SecurityLevel::High,
},
);
}
pub fn validate_cross_chain_operation(
&mut self,
operation: CrossChainOperation,
) -> Result<String, RuntimeError> {
let source_chain_id = operation.source_chain;
let _target_chain_id = operation.target_chain;
let source_config = self.chain_configs.get(&source_chain_id).ok_or_else(|| {
RuntimeError::General(format!(
"Unsupported source chain: {}",
operation.source_chain
))
})?;
let target_config = self
.chain_configs
.get(&operation.target_chain)
.ok_or_else(|| {
RuntimeError::General(format!(
"Unsupported target chain: {}",
operation.target_chain
))
})?;
let bridge_id = format!("{}_{}", operation.source_chain, operation.target_chain);
let bridge_config = self.trusted_bridges.get(&bridge_id).ok_or_else(|| {
RuntimeError::General(format!("No active bridge found: {}", bridge_id))
})?;
if !bridge_config.is_active {
return Err(RuntimeError::General("Bridge is not active".to_string()));
}
let source_config_clone = source_config.clone();
let target_config_clone = target_config.clone();
let bridge_config_clone = bridge_config.clone();
self.validate_operation_data(&operation, &source_config_clone, &target_config_clone)?;
self.validate_signatures(&operation, &bridge_config_clone)?;
self.check_security_requirements(
&operation,
&source_config_clone,
&target_config_clone,
&bridge_config_clone,
)?;
let operation_id = operation.operation_id.clone();
self.pending_operations
.insert(operation_id.clone(), operation);
Ok(operation_id)
}
fn validate_operation_data(
&self,
operation: &CrossChainOperation,
_source_config: &ChainSecurityConfig,
_target_config: &ChainSecurityConfig,
) -> Result<(), RuntimeError> {
match &operation.operation_type {
CrossChainOperationType::Transfer { amount, .. } => {
if *amount == 0 {
return Err(RuntimeError::General(
"Transfer amount cannot be zero".to_string(),
));
}
let bridge_id = format!("{}_{}", operation.source_chain, operation.target_chain);
if let Some(bridge) = self.trusted_bridges.get(&bridge_id) {
if *amount > bridge.max_transaction_amount {
return Err(RuntimeError::General(
"Amount exceeds bridge limit".to_string(),
));
}
}
}
CrossChainOperationType::ContractCall {
contract, function, ..
} => {
if contract.is_empty() || function.is_empty() {
return Err(RuntimeError::General(
"Invalid contract call parameters".to_string(),
));
}
}
CrossChainOperationType::StateSync { state_hash, proof } => {
if state_hash.is_empty() || proof.is_empty() {
return Err(RuntimeError::General(
"Invalid state sync parameters".to_string(),
));
}
}
CrossChainOperationType::ValidatorUpdate { new_validators } => {
if new_validators.is_empty() {
return Err(RuntimeError::General(
"Validator update cannot be empty".to_string(),
));
}
}
}
Ok(())
}
fn validate_signatures(
&mut self,
operation: &CrossChainOperation,
bridge_config: &BridgeConfig,
) -> Result<(), RuntimeError> {
if operation.signatures.len() < bridge_config.min_validator_signatures as usize {
return Err(RuntimeError::General(format!(
"Insufficient validator signatures: {} required, {} provided",
bridge_config.min_validator_signatures,
operation.signatures.len()
)));
}
for signature in &operation.signatures {
if !bridge_config
.validator_set
.contains(&signature.validator_address)
{
return Err(RuntimeError::General(format!(
"Untrusted validator: {}",
signature.validator_address
)));
}
let nonce = Some(signature.timestamp); if !self.verify_signature(
&operation.data,
&signature.signature,
&signature.validator_address,
nonce,
signature.chain_id,
)? {
return Err(RuntimeError::General(format!(
"Invalid signature from validator: {}",
signature.validator_address
)));
}
}
Ok(())
}
fn check_security_requirements(
&self,
operation: &CrossChainOperation,
source_config: &ChainSecurityConfig,
target_config: &ChainSecurityConfig,
bridge_config: &BridgeConfig,
) -> Result<(), RuntimeError> {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs();
if now > operation.timeout {
return Err(RuntimeError::General("Operation has timed out".to_string()));
}
match (&source_config.security_level, &target_config.security_level) {
(SecurityLevel::High, SecurityLevel::High) => {
if operation.signatures.len() < bridge_config.validator_set.len() / 2 + 1 {
return Err(RuntimeError::General(
"High security operations require majority validator signatures"
.to_string(),
));
}
}
(SecurityLevel::High, _) | (_, SecurityLevel::High) => {
if operation.signatures.len() < 3 {
return Err(RuntimeError::General(
"High security chains require at least 3 validator signatures".to_string(),
));
}
}
_ => {
}
}
if bridge_config.security_deposit < 1000000 {
return Err(RuntimeError::General(
"Bridge security deposit too low".to_string(),
));
}
Ok(())
}
fn verify_signature(
&mut self,
data: &[u8],
signature: &str,
validator_address: &str,
nonce: Option<u64>,
chain_id: i64,
) -> Result<bool, RuntimeError> {
let chain_config = self
.chain_configs
.get(&chain_id)
.ok_or_else(|| RuntimeError::General(format!("Chain not found: {}", chain_id)))?;
let scheme = match chain_config.signature_scheme {
SignatureScheme::ECDSA => "ecdsa",
SignatureScheme::EdDSA => "eddsa",
SignatureScheme::Custom(ref s) => s.as_str(),
};
const LEGACY_NO_NONCE: u64 = 0;
let nonce_value = nonce.unwrap_or(LEGACY_NO_NONCE);
let signer_key = format!("{}:{}", validator_address, chain_id);
if nonce_value > 0 {
self.signature_verifier.verify_with_nonce(
data,
signature,
validator_address,
nonce_value,
&signer_key,
scheme,
)
} else {
crate::stdlib::log::info(
"cross_chain_security",
{
let mut data = std::collections::HashMap::new();
data.insert(
"warning".to_string(),
Value::String(
"Signature verification without nonce - replay attack risk".to_string(),
),
);
data.insert(
"validator".to_string(),
Value::String(validator_address.to_string()),
);
data.insert("chain_id".to_string(), Value::Int(chain_id));
data
},
Some("cross_chain_security"),
);
let mut hasher = Sha256::new();
hasher.update(data);
hasher.update(validator_address.as_bytes());
let expected_signature = format!("{:x}", hasher.finalize());
Ok(signature.starts_with(&expected_signature[0..16]))
}
}
pub fn create_bridge(
&mut self,
source_chain: i64,
target_chain: i64,
bridge_contract: String,
validator_set: Vec<String>,
min_validator_signatures: u32,
max_transaction_amount: u64,
security_deposit: u64,
) -> Result<String, RuntimeError> {
if !self.chain_configs.contains_key(&source_chain) {
return Err(RuntimeError::General(format!(
"Source chain not supported: {}",
source_chain
)));
}
if !self.chain_configs.contains_key(&target_chain) {
return Err(RuntimeError::General(format!(
"Target chain not supported: {}",
target_chain
)));
}
if validator_set.is_empty() {
return Err(RuntimeError::General(
"Validator set cannot be empty".to_string(),
));
}
if min_validator_signatures == 0 || min_validator_signatures > validator_set.len() as u32 {
return Err(RuntimeError::General(
"Invalid minimum validator signatures".to_string(),
));
}
let bridge_id = format!("{}_{}", source_chain, target_chain);
let bridge_config = BridgeConfig {
bridge_id: bridge_id.clone(),
source_chain,
target_chain,
bridge_contract,
validator_set,
min_validator_signatures,
max_transaction_amount,
security_deposit,
is_active: true,
};
self.trusted_bridges
.insert(bridge_id.clone(), bridge_config);
Ok(bridge_id)
}
pub fn generate_cross_chain_proof(
&self,
operation_data: &[u8],
source_chain: i64,
target_chain: i64,
) -> Result<CrossChainProof, RuntimeError> {
let _source_config = self.chain_configs.get(&source_chain).ok_or_else(|| {
RuntimeError::General(format!("Source chain not found: {}", source_chain))
})?;
let _target_config = self.chain_configs.get(&target_chain).ok_or_else(|| {
RuntimeError::General(format!("Target chain not found: {}", target_chain))
})?;
let leaves = vec![operation_data.to_vec()];
let merkle_root = Self::build_merkle_root(&leaves);
let inclusion_proof = self.create_inclusion_proof(&leaves, 0);
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs();
Ok(CrossChainProof {
source_chain,
target_chain,
merkle_root,
inclusion_proof,
timestamp,
data_hash: self.hash_data(operation_data),
source_block_number: 0, target_block_number: 0, })
}
fn hash_leaf(data: &[u8]) -> String {
let mut hasher = Sha256::new();
hasher.update(data);
format!("{:x}", hasher.finalize())
}
fn build_merkle_root(leaves: &[Vec<u8>]) -> String {
if leaves.is_empty() {
return Self::hash_leaf(&[]);
}
let mut layer: Vec<String> = leaves.iter().map(|l| Self::hash_leaf(l)).collect();
while layer.len() > 1 {
let mut next = Vec::with_capacity((layer.len() + 1) / 2);
let mut i = 0;
while i < layer.len() {
let left = &layer[i];
let right = if i + 1 < layer.len() {
layer[i + 1].as_str()
} else {
left.as_str()
};
let mut hasher = Sha256::new();
hasher.update(left.as_bytes());
hasher.update(right.as_bytes());
next.push(format!("{:x}", hasher.finalize()));
i += 2;
}
layer = next;
}
layer
.into_iter()
.next()
.unwrap_or_else(|| Self::hash_leaf(&[]))
}
fn get_merkle_proof(leaves: &[Vec<u8>], index: usize) -> Vec<String> {
if leaves.is_empty() || index >= leaves.len() {
return vec![];
}
let mut layer: Vec<String> = leaves.iter().map(|l| Self::hash_leaf(l)).collect();
let mut path = Vec::new();
let mut idx = index;
while layer.len() > 1 {
let sibling_idx = if idx % 2 == 0 { idx + 1 } else { idx - 1 };
if sibling_idx < layer.len() {
path.push(layer[sibling_idx].clone());
} else {
path.push(layer[idx].clone());
}
let mut next = Vec::with_capacity((layer.len() + 1) / 2);
let mut i = 0;
while i < layer.len() {
let left = &layer[i];
let right = if i + 1 < layer.len() {
layer[i + 1].as_str()
} else {
left.as_str()
};
let mut hasher = Sha256::new();
hasher.update(left.as_bytes());
hasher.update(right.as_bytes());
next.push(format!("{:x}", hasher.finalize()));
i += 2;
}
layer = next;
idx /= 2;
}
path
}
pub fn verify_inclusion_proof(
leaf_hash: &str,
leaf_index: usize,
path: &[String],
root: &str,
) -> bool {
let mut current = leaf_hash.to_string();
let mut index = leaf_index;
for sibling in path {
let (left, right) = if index % 2 == 0 {
(current.clone(), sibling.clone())
} else {
(sibling.clone(), current.clone())
};
let mut hasher = Sha256::new();
hasher.update(left.as_bytes());
hasher.update(right.as_bytes());
current = format!("{:x}", hasher.finalize());
index /= 2;
}
current == root
}
fn create_inclusion_proof(&self, leaves: &[Vec<u8>], index: usize) -> Vec<String> {
Self::get_merkle_proof(leaves, index)
}
fn hash_data(&self, data: &[u8]) -> String {
Self::hash_leaf(data)
}
pub fn get_operation_status(&self, operation_id: &str) -> Option<OperationStatus> {
self.pending_operations
.get(operation_id)
.map(|op| op.status.clone())
}
pub fn update_operation_status(
&mut self,
operation_id: &str,
status: OperationStatus,
) -> Result<(), RuntimeError> {
if let Some(operation) = self.pending_operations.get_mut(operation_id) {
operation.status = status;
Ok(())
} else {
Err(RuntimeError::General("Operation not found".to_string()))
}
}
pub fn cleanup_expired_operations(&mut self) {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs();
self.pending_operations.retain(|_, operation| {
now <= operation.timeout
&& !matches!(
operation.status,
OperationStatus::Confirmed | OperationStatus::Failed
)
});
}
}
impl Default for CrossChainSecurityManager {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct CrossChainProof {
pub source_chain: i64,
pub target_chain: i64,
pub merkle_root: String,
pub inclusion_proof: Vec<String>,
pub timestamp: u64,
pub data_hash: String,
pub source_block_number: u64,
pub target_block_number: u64,
}
pub mod secure_chain {
use super::*;
use crate::stdlib::chain;
use std::sync::{Mutex, OnceLock};
static SECURITY_MANAGER: OnceLock<Mutex<Option<CrossChainSecurityManager>>> = OnceLock::new();
fn get_manager() -> &'static Mutex<Option<CrossChainSecurityManager>> {
SECURITY_MANAGER.get_or_init(|| Mutex::new(None))
}
pub fn init_security_manager() {
*get_manager()
.lock()
.expect("SECURITY_MANAGER lock poisoned") = Some(CrossChainSecurityManager::new());
}
pub fn secure_deploy(
source_chain: i64,
target_chain: i64,
contract_name: String,
constructor_args: HashMap<String, String>,
validator_signatures: Vec<ValidatorSignature>,
) -> Result<String, String> {
let mut guard = get_manager()
.lock()
.expect("SECURITY_MANAGER lock poisoned");
if let Some(ref mut manager) = *guard {
let operation_data =
format!("deploy:{}:{:?}", contract_name, constructor_args).into_bytes();
let operation = CrossChainOperation {
operation_id: format!("deploy_{}_{}", source_chain, target_chain),
source_chain,
target_chain,
operation_type: CrossChainOperationType::ContractCall {
contract: "DeploymentContract".to_string(),
function: "deploy".to_string(),
args: operation_data.clone(),
},
data: operation_data,
signatures: validator_signatures,
status: OperationStatus::Pending,
created_at: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
timeout: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs()
+ 3600, };
let operation_id = manager
.validate_cross_chain_operation(operation)
.map_err(|e| format!("Cross-chain validation failed: {}", e))?;
let address = chain::deploy(target_chain, contract_name, constructor_args);
manager
.update_operation_status(&operation_id, OperationStatus::Confirmed)
.map_err(|e| format!("Failed to update operation status: {}", e))?;
Ok(address)
} else {
Err("Security manager not initialized".to_string())
}
}
pub fn secure_transfer(
source_chain: i64,
target_chain: i64,
from: String,
to: String,
amount: u64,
validator_signatures: Vec<ValidatorSignature>,
) -> Result<String, String> {
let mut guard = get_manager()
.lock()
.expect("SECURITY_MANAGER lock poisoned");
if let Some(ref mut manager) = *guard {
let operation_data = format!("transfer:{}:{}:{}", from, to, amount).into_bytes();
let operation = CrossChainOperation {
operation_id: format!("transfer_{}_{}_{}", source_chain, target_chain, amount),
source_chain,
target_chain,
operation_type: CrossChainOperationType::Transfer {
from: from.clone(),
to: to.clone(),
amount,
},
data: operation_data.clone(),
signatures: validator_signatures,
status: OperationStatus::Pending,
created_at: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
timeout: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs()
+ 1800, };
let operation_id = manager
.validate_cross_chain_operation(operation)
.map_err(|e| format!("Cross-chain validation failed: {}", e))?;
let proof = manager
.generate_cross_chain_proof(&operation_data, source_chain, target_chain)
.map_err(|e| format!("Failed to generate proof: {}", e))?;
manager
.update_operation_status(&operation_id, OperationStatus::Confirmed)
.map_err(|e| format!("Failed to update operation status: {}", e))?;
Ok(format!("Transfer completed with proof: {:?}", proof))
} else {
Err("Security manager not initialized".to_string())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cross_chain_manager_creation() {
let manager = CrossChainSecurityManager::new();
assert!(manager.chain_configs.contains_key(&1)); assert!(manager.chain_configs.contains_key(&137)); assert!(manager.chain_configs.contains_key(&101)); }
#[test]
fn test_bridge_creation() {
let mut manager = CrossChainSecurityManager::new();
let bridge_id = manager
.create_bridge(
1, 137, "0xbridge123".to_string(),
vec!["validator1".to_string(), "validator2".to_string()],
2, 1000000, 500000, )
.unwrap();
assert_eq!(bridge_id, "1_137");
assert!(manager.trusted_bridges.contains_key(&bridge_id));
}
#[test]
fn test_operation_validation() {
let mut manager = CrossChainSecurityManager::new();
use crate::stdlib::crypto_signatures::ECDSASignatureVerifier;
let (validator_privkey, validator_pubkey) =
ECDSASignatureVerifier::generate_keypair().unwrap();
manager
.create_bridge(
137, 137, "0xbridge123".to_string(),
vec![validator_pubkey.clone()],
1, 1000000, 1000000, )
.unwrap();
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs();
let future_timeout = now + 3600;
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
hasher.update(b"test_data");
hasher.update(now.to_be_bytes());
let message_with_nonce = hasher.finalize();
let valid_signature =
ECDSASignatureVerifier::sign(&message_with_nonce, &validator_privkey).unwrap();
let operation = CrossChainOperation {
operation_id: "test_op".to_string(),
source_chain: 137, target_chain: 137, operation_type: CrossChainOperationType::Transfer {
from: "0xfrom".to_string(),
to: "0xto".to_string(),
amount: 1000,
},
data: b"test_data".to_vec(),
signatures: vec![ValidatorSignature {
validator_address: validator_pubkey,
signature: valid_signature, timestamp: now, chain_id: 137, }],
status: OperationStatus::Pending,
created_at: now,
timeout: future_timeout,
};
let result = manager.validate_cross_chain_operation(operation);
assert!(result.is_ok(), "Operation validation failed");
}
#[test]
fn test_merkle_inclusion_proof_verify() {
let leaf = b"op1";
let mut hasher = Sha256::new();
hasher.update(leaf);
let single_root = format!("{:x}", hasher.finalize());
assert!(!single_root.is_empty());
assert!(CrossChainSecurityManager::verify_inclusion_proof(
&single_root,
0,
&[],
&single_root
));
assert!(!CrossChainSecurityManager::verify_inclusion_proof(
"wrong_leaf_hash",
0,
&[],
&single_root
));
}
}