Spaces:
Sleeping
Sleeping
| """ | |
| Shared utility functions for the ML-based cryptanalysis project. | |
| """ | |
| import numpy as np | |
| import torch | |
| import os | |
| import json | |
| import matplotlib | |
| matplotlib.use('Agg') | |
| import matplotlib.pyplot as plt | |
| import seaborn as sns | |
| # Reproducibility | |
| SEED = 42 | |
| np.random.seed(SEED) | |
| torch.manual_seed(SEED) | |
| DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu') | |
| # Project paths | |
| PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |
| def int_to_bits(val, nbits): | |
| """Convert integer to numpy bit array (MSB first).""" | |
| return np.array([(val >> i) & 1 for i in range(nbits - 1, -1, -1)], dtype=np.float32) | |
| def bits_to_int(bits): | |
| """Convert bit array back to integer.""" | |
| val = 0 | |
| for b in bits: | |
| val = (val << 1) | int(b) | |
| return val | |
| def int_to_words(val, word_size, num_words): | |
| """Convert integer to word-level array.""" | |
| mask = (1 << word_size) - 1 | |
| words = [] | |
| for i in range(num_words - 1, -1, -1): | |
| words.append((val >> (i * word_size)) & mask) | |
| return np.array(words, dtype=np.float32) | |
| def hamming_weight(val, nbits): | |
| """Compute Hamming weight of an integer.""" | |
| return bin(val & ((1 << nbits) - 1)).count('1') | |
| def xor(a, b, nbits): | |
| """XOR two integers with bit masking.""" | |
| return (a ^ b) & ((1 << nbits) - 1) | |
| def rotate_left(val, r, nbits): | |
| """Left rotation.""" | |
| return ((val << r) | (val >> (nbits - r))) & ((1 << nbits) - 1) | |
| def rotate_right(val, r, nbits): | |
| """Right rotation.""" | |
| return ((val >> r) | (val << (nbits - r))) & ((1 << nbits) - 1) | |
| def save_results(results, filepath): | |
| """Save results dictionary to JSON.""" | |
| os.makedirs(os.path.dirname(filepath), exist_ok=True) | |
| # Convert numpy types | |
| def convert(o): | |
| if isinstance(o, (np.integer,)): | |
| return int(o) | |
| if isinstance(o, (np.floating,)): | |
| return float(o) | |
| if isinstance(o, np.ndarray): | |
| return o.tolist() | |
| return o | |
| with open(filepath, 'w') as f: | |
| json.dump(results, f, indent=2, default=convert) | |
| #load results from JSON, converting lists back to numpy arrays where appropriate | |
| def load_results(filepath): | |
| """Load results dictionary from JSON.""" | |
| with open(filepath, 'r') as f: | |
| return json.load(f) | |
| def setup_plot_style(): | |
| """Set up consistent, publication-quality plot style.""" | |
| plt.style.use('seaborn-v0_8-whitegrid') | |
| plt.rcParams.update({ | |
| 'font.size': 12, | |
| 'axes.titlesize': 14, | |
| 'axes.labelsize': 12, | |
| 'xtick.labelsize': 10, | |
| 'ytick.labelsize': 10, | |
| 'legend.fontsize': 10, | |
| 'figure.figsize': (10, 6), | |
| 'figure.dpi': 150, | |
| 'savefig.dpi': 150, | |
| 'savefig.bbox': 'tight', | |
| }) | |
| # Cipher registry | |
| CIPHER_REGISTRY = {} | |
| def register_cipher(name): | |
| """Decorator to register a cipher class.""" | |
| def decorator(cls): | |
| CIPHER_REGISTRY[name] = cls | |
| return cls | |
| return decorator | |
| def get_cipher(name): | |
| """Get a cipher class by name.""" | |
| if name not in CIPHER_REGISTRY: | |
| raise ValueError(f"Unknown cipher: {name}. Available: {list(CIPHER_REGISTRY.keys())}") | |
| return CIPHER_REGISTRY[name] | |
| def list_ciphers(): | |
| """List all registered ciphers.""" | |
| return list(CIPHER_REGISTRY.keys()) | |