#!/usr/bin/env python3 """ Multi-Network Bitcoin Wallet Manager Supports mainnet, testnet, and regtest with comprehensive security validation """ import json import hashlib import re import datetime from typing import Dict, List, Optional, Any, Union from dataclasses import dataclass from enum import Enum class BitcoinNetwork(Enum): """Supported Bitcoin networks""" MAINNET = "mainnet" TESTNET = "testnet" REGTEST = "regtest" @dataclass class NetworkConfig: """Network-specific configuration""" name: str rpc_port: int default_port: int magic_bytes: str seed_nodes: List[str] address_prefix: str script_prefix: str # Network configurations NETWORK_CONFIGS = { BitcoinNetwork.MAINNET: NetworkConfig( name="mainnet", rpc_port=8332, default_port=8333, magic_bytes="f9beb4d9", seed_nodes=["seed.bitcoin.sipa.be", "dnsseed.bluematt.me"], address_prefix="00", script_prefix="05" ), BitcoinNetwork.TESTNET: NetworkConfig( name="testnet", rpc_port=18332, default_port=18333, magic_bytes="0b110907", seed_nodes=["testnet-seed.bitcoin.jonasschnelli.ch"], address_prefix="6f", script_prefix="c4" ), BitcoinNetwork.REGTEST: NetworkConfig( name="regtest", rpc_port=18443, default_port=18444, magic_bytes="fabfb5da", seed_nodes=[], address_prefix="6f", script_prefix="c4" ) } class SecurityValidator: """Security validation utilities""" @staticmethod def validate_address_format(address: str, network: BitcoinNetwork) -> bool: """Validate Bitcoin address format for specific network""" if not address: return False # Check length ranges for different address types if len(address) < 26 or len(address) > 90: # Increased max for bech32 return False # Base58 characters check (for legacy addresses) base58_alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' try: # Bech32 addresses (bc1...) if address.startswith('bc1'): # Basic bech32 validation - should start with bc1 and contain valid characters bech32_chars = '023456789acdefghjklmnpqrstuvwxyz' for char in address[3:]: if char not in bech32_chars: return False return True # Legacy addresses - check base58 characters for char in address: if char not in base58_alphabet: return False # Check network-specific prefixes if network == BitcoinNetwork.MAINNET: return address.startswith(('1', '3')) # P2PKH or P2SH elif network == BitcoinNetwork.TESTNET: return address.startswith(('m', 'n', '2')) # Testnet prefixes elif network == BitcoinNetwork.REGTEST: return address.startswith(('m', 'n', '2')) # Regtest uses testnet prefixes except Exception: return False return False @staticmethod def validate_private_key_format(private_key: str) -> bool: """Validate private key WIF format""" if not private_key or len(private_key) < 30 or len(private_key) > 52: return False # Base58 validation alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' for char in private_key: if char not in alphabet: return False return True @staticmethod def validate_rpc_credentials(username: str, password: str) -> Dict[str, Any]: """Validate RPC connection credentials""" result = { "valid": False, "issues": [], "strength": "weak" } if not username or len(username) < 8: result["issues"].append("Username must be at least 8 characters") if not password or len(password) < 16: result["issues"].append("Password must be at least 16 characters") else: # Check password strength has_upper = any(c.isupper() for c in password) has_lower = any(c.islower() for c in password) has_digit = any(c.isdigit() for c in password) has_special = any(c in "!@#$%^&*()_+-=[]{}|;:,.<>?" for c in password) if all([has_upper, has_lower, has_digit, has_special]): result["strength"] = "strong" elif sum([has_upper, has_lower, has_digit, has_special]) >= 3: result["strength"] = "medium" result["valid"] = len(result["issues"]) == 0 return result class MultiNetworkWalletManager: """Multi-network Bitcoin wallet manager with security validation""" def __init__(self, network: BitcoinNetwork = BitcoinNetwork.MAINNET): self.network = network self.config = NETWORK_CONFIGS[network] self.validator = SecurityValidator() self.connected = False self.wallet_info = None def validate_network_config(self) -> Dict[str, Any]: """Validate network configuration""" validation = { "network": self.network.value, "valid": True, "issues": [] } # Check required config fields required_fields = ["rpc_port", "default_port", "magic_bytes"] for field in required_fields: if not getattr(self.config, field): validation["valid"] = False validation["issues"].append(f"Missing {field} in network config") # Validate port ranges if self.config.rpc_port <= 0 or self.config.rpc_port > 65535: validation["valid"] = False validation["issues"].append(f"Invalid RPC port: {self.config.rpc_port}") return validation def simulate_connection(self, rpc_user: str, rpc_pass: str) -> Dict[str, Any]: """Simulate Bitcoin Core RPC connection for demo purposes""" # Validate credentials first cred_check = self.validator.validate_rpc_credentials(rpc_user, rpc_pass) if not cred_check["valid"]: return { "success": False, "error": "Invalid RPC credentials", "issues": cred_check["issues"] } # Simulate connection validation network_validation = self.validate_network_config() if not network_validation["valid"]: return { "success": False, "error": "Invalid network configuration", "issues": network_validation["issues"] } # Simulate successful connection self.connected = True return { "success": True, "network": self.network.value, "rpc_port": self.config.rpc_port, "connection_time": datetime.datetime.now().isoformat(), "server_version": "Bitcoin Core 30.2.0" } def create_wallet(self, wallet_name: str, passphrase: Optional[str] = None) -> Dict[str, Any]: """Create new wallet with security validation""" if not self.connected: return {"success": False, "error": "Not connected to Bitcoin Core"} # Validate wallet name if not wallet_name or len(wallet_name) < 1: return {"success": False, "error": "Invalid wallet name"} if len(wallet_name) > 100: return {"success": False, "error": "Wallet name too long"} # Check for invalid characters if re.search(r'[<>:"/\\|?*]', wallet_name): return {"success": False, "error": "Wallet name contains invalid characters"} # Validate passphrase if provided if passphrase: if len(passphrase) < 8: return {"success": False, "error": "Passphrase too short (min 8 characters)"} # Simulate wallet creation wallet_data = { "success": True, "wallet_name": wallet_name, "network": self.network.value, "created_at": datetime.datetime.now().isoformat(), "encrypted": passphrase is not None, "addresses": { "receiving": self._generate_test_address("receive"), "change": self._generate_test_address("change") } } self.wallet_info = wallet_data return wallet_data def _generate_test_address(self, address_type: str) -> str: """Generate test address for demonstration""" prefix = { BitcoinNetwork.MAINNET: "1", BitcoinNetwork.TESTNET: "m", BitcoinNetwork.REGTEST: "2" }[self.network] # Generate deterministic test address base = f"{address_type}{self.network.value}{datetime.datetime.now().isoformat()}" hash_val = hashlib.sha256(base.encode()).hexdigest()[:26] return prefix + hash_val def import_private_key(self, private_key: str, label: Optional[str] = None) -> Dict[str, Any]: """Import private key with security validation""" if not self.connected: return {"success": False, "error": "Not connected to Bitcoin Core"} # Validate private key format if not self.validator.validate_private_key_format(private_key): return {"success": False, "error": "Invalid private key format"} # Validate label if provided if label and len(label) > 100: return {"success": False, "error": "Label too long"} # Simulate import address = self._generate_test_address("imported") return { "success": True, "address": address, "label": label or f"imported_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}", "network": self.network.value, "import_time": datetime.datetime.now().isoformat() } def get_network_info(self) -> Dict[str, Any]: """Get detailed network information""" return { "network": self.network.value, "config": { "rpc_port": self.config.rpc_port, "default_port": self.config.default_port, "magic_bytes": self.config.magic_bytes, "address_prefix": self.config.address_prefix, "script_prefix": self.config.script_prefix }, "connected": self.connected, "supported_features": [ "multi_wallet", "rpc_encryption", "bip39_mnemonic", "bech32_addresses" ] } def switch_network(self, new_network: BitcoinNetwork) -> Dict[str, Any]: """Switch to different Bitcoin network""" if self.connected: return { "success": False, "error": "Cannot switch network while connected. Disconnect first." } old_network = self.network self.network = new_network self.config = NETWORK_CONFIGS[new_network] return { "success": True, "from_network": old_network.value, "to_network": new_network.value, "switch_time": datetime.datetime.now().isoformat() } def demo_multinet_usage(): """Demonstrate multi-network wallet manager usage""" print("=== Multi-Network Bitcoin Wallet Manager Demo ===\n") # Test all networks networks = [BitcoinNetwork.MAINNET, BitcoinNetwork.TESTNET, BitcoinNetwork.REGTEST] for network in networks: print(f"--- Testing {network.value.upper()} ---") manager = MultiNetworkWalletManager(network) # Show network info info = manager.get_network_info() print(f"Network: {info['network']}") print(f"RPC Port: {info['config']['rpc_port']}") print(f"Address Prefix: {info['config']['address_prefix']}") # Validate configuration validation = manager.validate_network_config() print(f"Config Valid: {validation['valid']}") # Simulate connection conn_result = manager.simulate_connection("starlight_ai_agent", "SecurePassword123!@#") print(f"Connection: {conn_result['success']}") if conn_result['success']: # Create wallet wallet_result = manager.create_wallet("demo_wallet", "strong_passphrase") print(f"Wallet Created: {wallet_result['success']}") if wallet_result['success']: print(f"Receive Address: {wallet_result['addresses']['receiving']}") print() if __name__ == "__main__": demo_multinet_usage()