// ----------------------------------------------------------------------------- // ProofSpineAssemblyBenchmarks.cs // Sprint: SPRINT_0501_0001_0001_proof_evidence_chain_master // Task: PROOF-MASTER-0005 // Description: Benchmarks for proof spine assembly and Merkle tree operations // ----------------------------------------------------------------------------- using System.Security.Cryptography; using BenchmarkDotNet.Attributes; namespace StellaOps.Bench.ProofChain.Benchmarks; /// /// Benchmarks for proof spine assembly operations. /// Target: Spine assembly (5 items) < 5ms. /// [MemoryDiagnoser] [SimpleJob(warmupCount: 3, iterationCount: 10)] public class ProofSpineAssemblyBenchmarks { private List _evidenceItems = null!; private List _merkleLeaves = null!; private byte[] _reasoning = null!; private byte[] _vexVerdict = null!; [Params(1, 5, 10, 50)] public int EvidenceCount { get; set; } [GlobalSetup] public void Setup() { // Generate evidence items of varying sizes _evidenceItems = Enumerable.Range(0, 100) .Select(i => { var data = new byte[1024 + (i * 100)]; // 1KB to ~10KB RandomNumberGenerator.Fill(data); return data; }) .ToList(); // Merkle tree leaves _merkleLeaves = Enumerable.Range(0, 100) .Select(_ => { var leaf = new byte[32]; RandomNumberGenerator.Fill(leaf); return leaf; }) .ToList(); // Reasoning and verdict _reasoning = new byte[2048]; RandomNumberGenerator.Fill(_reasoning); _vexVerdict = new byte[512]; RandomNumberGenerator.Fill(_vexVerdict); } /// /// Assemble proof spine from evidence items. /// Target: < 5ms for 5 items. /// [Benchmark] public ProofSpineResult AssembleSpine() { var evidence = _evidenceItems.Take(EvidenceCount).ToList(); return AssembleProofSpine(evidence, _reasoning, _vexVerdict); } /// /// Build Merkle tree from leaves. /// Target: < 1ms for 100 leaves. /// [Benchmark] public byte[] BuildMerkleTree() { return ComputeMerkleRoot(_merkleLeaves.Take(EvidenceCount).ToList()); } /// /// Generate deterministic bundle ID from spine. /// Target: < 500μs. /// [Benchmark] public string GenerateBundleId() { var spine = AssembleProofSpine( _evidenceItems.Take(EvidenceCount).ToList(), _reasoning, _vexVerdict); return ComputeBundleId(spine); } /// /// Verify spine determinism (same inputs = same output). /// [Benchmark] public bool VerifyDeterminism() { var evidence = _evidenceItems.Take(EvidenceCount).ToList(); var spine1 = AssembleProofSpine(evidence, _reasoning, _vexVerdict); var spine2 = AssembleProofSpine(evidence, _reasoning, _vexVerdict); return spine1.BundleId == spine2.BundleId; } #region Implementation private static ProofSpineResult AssembleProofSpine( List evidence, byte[] reasoning, byte[] vexVerdict) { // 1. Generate evidence IDs var evidenceIds = evidence .OrderBy(e => Convert.ToHexString(SHA256.HashData(e))) // Deterministic ordering .Select(e => SHA256.HashData(e)) .ToList(); // 2. Build Merkle tree var merkleRoot = ComputeMerkleRoot(evidenceIds); // 3. Compute reasoning ID var reasoningId = SHA256.HashData(reasoning); // 4. Compute verdict ID var verdictId = SHA256.HashData(vexVerdict); // 5. Assemble bundle content var bundleContent = new List(); bundleContent.AddRange(merkleRoot); bundleContent.AddRange(reasoningId); bundleContent.AddRange(verdictId); // 6. Compute bundle ID var bundleId = SHA256.HashData(bundleContent.ToArray()); return new ProofSpineResult { BundleId = $"sha256:{Convert.ToHexString(bundleId).ToLowerInvariant()}", MerkleRoot = merkleRoot, EvidenceIds = evidenceIds.Select(e => $"sha256:{Convert.ToHexString(e).ToLowerInvariant()}").ToList() }; } private static byte[] ComputeMerkleRoot(List leaves) { if (leaves.Count == 0) return SHA256.HashData(Array.Empty()); if (leaves.Count == 1) return leaves[0]; var currentLevel = leaves.ToList(); while (currentLevel.Count > 1) { var nextLevel = new List(); for (int i = 0; i < currentLevel.Count; i += 2) { if (i + 1 < currentLevel.Count) { // Hash pair var combined = new byte[currentLevel[i].Length + currentLevel[i + 1].Length]; currentLevel[i].CopyTo(combined, 0); currentLevel[i + 1].CopyTo(combined, currentLevel[i].Length); nextLevel.Add(SHA256.HashData(combined)); } else { // Odd node - promote nextLevel.Add(currentLevel[i]); } } currentLevel = nextLevel; } return currentLevel[0]; } private static string ComputeBundleId(ProofSpineResult spine) { return spine.BundleId; } #endregion } /// /// Result of proof spine assembly. /// public sealed class ProofSpineResult { public required string BundleId { get; init; } public required byte[] MerkleRoot { get; init; } public required List EvidenceIds { get; init; } }