//! Comprehensive benchmarks for kHeavyHash mining. //! //! Benchmarks: //! - GF(2^8) multiplication tables //! - Matrix multiplication (standard vs optimized) //! - kHeavyHash stages (pre-hash, finalize, full) //! - Mining throughput (single and parallel) //! - Difficulty validation //! //! Run with: cargo bench -p synor-mining use criterion::{ black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput, }; use synor_mining::kheavyhash::{HashrateBenchmark, KHeavyHash, ParallelMiner}; use synor_mining::matrix::{gf_mul, HeavyMatrix, OptimizedMatrix}; use synor_mining::Target; // ==================== GF(2^8) Operations ==================== fn bench_gf_mul(c: &mut Criterion) { c.bench_function("gf_mul_full_table", |b| { b.iter(|| { for a in 0..=255u8 { for bb in 0..=255u8 { black_box(gf_mul(a, bb)); } } }) }); } fn bench_gf_mul_single(c: &mut Criterion) { c.bench_function("gf_mul_single", |b| { let a = 0x53u8; let bb = 0xCAu8; b.iter(|| black_box(gf_mul(a, bb))) }); } // ==================== Matrix Operations ==================== fn bench_matrix_multiply(c: &mut Criterion) { let matrix = HeavyMatrix::new(); let input = [0x42u8; 32]; c.bench_function("matrix_multiply_standard", |b| { b.iter(|| black_box(matrix.multiply(&input))) }); } fn bench_optimized_matrix_multiply(c: &mut Criterion) { let matrix = OptimizedMatrix::new(); let input = [0x42u8; 32]; c.bench_function("matrix_multiply_optimized", |b| { b.iter(|| black_box(matrix.multiply(&input))) }); } fn bench_matrix_creation(c: &mut Criterion) { c.bench_function("matrix_create_optimized", |b| { b.iter(|| black_box(OptimizedMatrix::new())) }); } fn bench_matrix_from_seed(c: &mut Criterion) { let seed = [0x42u8; 32]; c.bench_function("matrix_from_seed", |b| { b.iter(|| black_box(OptimizedMatrix::from_seed(&seed))) }); } // ==================== kHeavyHash Core ==================== fn bench_kheavyhash(c: &mut Criterion) { let hasher = KHeavyHash::new(); let header = [0x42u8; 80]; let mut group = c.benchmark_group("kheavyhash"); group.throughput(Throughput::Elements(1)); // Full hash (header + nonce -> pow_hash) group.bench_function("full_hash", |b| { let mut nonce = 0u64; b.iter(|| { let result = hasher.hash(&header, nonce); nonce = nonce.wrapping_add(1); black_box(result) }) }); // Pre-hash only (SHA3-256 of header) group.bench_function("pre_hash_only", |b| { b.iter(|| black_box(hasher.pre_hash(&header))) }); // Finalize only (Blake3 + matrix + SHA3 per nonce) let pre_hash = hasher.pre_hash(&header); group.bench_function("finalize_only", |b| { let mut nonce = 0u64; b.iter(|| { let result = hasher.finalize(&pre_hash, nonce); nonce = nonce.wrapping_add(1); black_box(result) }) }); group.finish(); } fn bench_kheavyhash_varying_headers(c: &mut Criterion) { let hasher = KHeavyHash::new(); let mut group = c.benchmark_group("kheavyhash_header_size"); for size in [32, 64, 80, 128, 256] { let header = vec![0x42u8; size]; group.throughput(Throughput::Bytes(size as u64)); group.bench_with_input(BenchmarkId::from_parameter(size), &header, |b, h| { let mut nonce = 0u64; b.iter(|| { let result = hasher.hash(h, nonce); nonce = nonce.wrapping_add(1); black_box(result) }) }); } group.finish(); } // ==================== Mining Throughput ==================== fn bench_mining_throughput(c: &mut Criterion) { let hasher = KHeavyHash::new(); let header = [0x42u8; 80]; let pre_hash = hasher.pre_hash(&header); let mut group = c.benchmark_group("mining_throughput"); for count in [100, 1000, 10000] { group.throughput(Throughput::Elements(count)); group.bench_with_input( BenchmarkId::from_parameter(count), &count, |b, &count| { b.iter(|| { for nonce in 0..count { black_box(hasher.finalize(&pre_hash, nonce)); } }) }, ); } group.finish(); } fn bench_mining_with_target(c: &mut Criterion) { let hasher = KHeavyHash::new(); let header = [0x42u8; 80]; let target = Target::max(); // Easy target for benchmarking let mut group = c.benchmark_group("mining_with_target"); group.throughput(Throughput::Elements(1)); group.bench_function("mine_easy_target", |b| { b.iter_batched( || 0u64, |start_nonce| { black_box(hasher.mine(&header, &target, start_nonce, 10000)) }, criterion::BatchSize::SmallInput, ) }); group.finish(); } // ==================== Target Validation ==================== fn bench_target_validation(c: &mut Criterion) { let hasher = KHeavyHash::new(); let header = [0x42u8; 80]; let pre_hash = hasher.pre_hash(&header); let pow = hasher.finalize(&pre_hash, 12345); let target = Target::max(); c.bench_function("target_is_met_by", |b| { b.iter(|| black_box(target.is_met_by(&pow.hash))) }); } fn bench_pow_meets_target(c: &mut Criterion) { let hasher = KHeavyHash::new(); let header = [0x42u8; 80]; let target = Target::max(); // Find a valid nonce first let pow = hasher.mine(&header, &target, 0, 10000).unwrap(); c.bench_function("pow_meets_target", |b| { b.iter(|| black_box(pow.meets_target(&target))) }); } // ==================== Parallel Mining ==================== fn bench_parallel_miner_creation(c: &mut Criterion) { let mut group = c.benchmark_group("parallel_miner_create"); for threads in [1, 2, 4, 8] { group.bench_with_input( BenchmarkId::from_parameter(threads), &threads, |b, &t| { b.iter(|| black_box(ParallelMiner::new(t))) }, ); } group.finish(); } fn bench_hashrate_measurement(c: &mut Criterion) { c.bench_function("hashrate_benchmark_100ms", |b| { let bench = HashrateBenchmark::new(); b.iter(|| black_box(bench.run(100))) }); } // ==================== Hasher Creation ==================== fn bench_hasher_creation(c: &mut Criterion) { c.bench_function("kheavyhash_new", |b| { b.iter(|| black_box(KHeavyHash::new())) }); c.bench_function("kheavyhash_with_seed", |b| { let seed = [0x42u8; 32]; b.iter(|| black_box(KHeavyHash::with_seed(&seed))) }); } // ==================== Verification ==================== fn bench_verify(c: &mut Criterion) { let hasher = KHeavyHash::new(); let header = [0x42u8; 80]; let target = Target::max(); // Find a valid nonce let pow = hasher.mine(&header, &target, 0, 10000).unwrap(); c.bench_function("verify_pow", |b| { b.iter(|| black_box(hasher.verify(&header, pow.nonce, &target))) }); } // ==================== Memory Comparison ==================== fn bench_matrix_memory(c: &mut Criterion) { // This measures the cost of matrix operations with different input patterns let matrix = OptimizedMatrix::new(); let mut group = c.benchmark_group("matrix_input_patterns"); // Zero input let zero_input = [0u8; 32]; group.bench_function("zeros", |b| { b.iter(|| black_box(matrix.multiply(&zero_input))) }); // All ones let ones_input = [0xFFu8; 32]; group.bench_function("ones", |b| { b.iter(|| black_box(matrix.multiply(&ones_input))) }); // Random pattern let random_input: [u8; 32] = { let mut arr = [0u8; 32]; for (i, byte) in arr.iter_mut().enumerate() { *byte = (i as u8).wrapping_mul(17).wrapping_add(31); } arr }; group.bench_function("random", |b| { b.iter(|| black_box(matrix.multiply(&random_input))) }); group.finish(); } // ==================== Criterion Groups ==================== criterion_group!( gf_benches, bench_gf_mul, bench_gf_mul_single, ); criterion_group!( matrix_benches, bench_matrix_multiply, bench_optimized_matrix_multiply, bench_matrix_creation, bench_matrix_from_seed, bench_matrix_memory, ); criterion_group!( kheavyhash_benches, bench_kheavyhash, bench_kheavyhash_varying_headers, bench_hasher_creation, ); criterion_group!( mining_benches, bench_mining_throughput, bench_mining_with_target, bench_hashrate_measurement, ); criterion_group!( validation_benches, bench_target_validation, bench_pow_meets_target, bench_verify, ); criterion_group!( parallel_benches, bench_parallel_miner_creation, ); criterion_main!( gf_benches, matrix_benches, kheavyhash_benches, mining_benches, validation_benches, parallel_benches );