- Add RateLimitConfig for configuration management with YAML binding support. - Introduce RateLimitDecision to encapsulate the result of rate limit checks. - Implement RateLimitMetrics for OpenTelemetry metrics tracking. - Create RateLimitMiddleware for enforcing rate limits on incoming requests. - Develop RateLimitService to orchestrate instance and environment rate limit checks. - Add RateLimitServiceCollectionExtensions for dependency injection registration.
200 lines
5.9 KiB
C#
200 lines
5.9 KiB
C#
// -----------------------------------------------------------------------------
|
|
// 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;
|
|
|
|
/// <summary>
|
|
/// Benchmarks for proof spine assembly operations.
|
|
/// Target: Spine assembly (5 items) < 5ms.
|
|
/// </summary>
|
|
[MemoryDiagnoser]
|
|
[SimpleJob(warmupCount: 3, iterationCount: 10)]
|
|
public class ProofSpineAssemblyBenchmarks
|
|
{
|
|
private List<byte[]> _evidenceItems = null!;
|
|
private List<byte[]> _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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Assemble proof spine from evidence items.
|
|
/// Target: < 5ms for 5 items.
|
|
/// </summary>
|
|
[Benchmark]
|
|
public ProofSpineResult AssembleSpine()
|
|
{
|
|
var evidence = _evidenceItems.Take(EvidenceCount).ToList();
|
|
return AssembleProofSpine(evidence, _reasoning, _vexVerdict);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Build Merkle tree from leaves.
|
|
/// Target: < 1ms for 100 leaves.
|
|
/// </summary>
|
|
[Benchmark]
|
|
public byte[] BuildMerkleTree()
|
|
{
|
|
return ComputeMerkleRoot(_merkleLeaves.Take(EvidenceCount).ToList());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generate deterministic bundle ID from spine.
|
|
/// Target: < 500μs.
|
|
/// </summary>
|
|
[Benchmark]
|
|
public string GenerateBundleId()
|
|
{
|
|
var spine = AssembleProofSpine(
|
|
_evidenceItems.Take(EvidenceCount).ToList(),
|
|
_reasoning,
|
|
_vexVerdict);
|
|
return ComputeBundleId(spine);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verify spine determinism (same inputs = same output).
|
|
/// </summary>
|
|
[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<byte[]> 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<byte>();
|
|
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<byte[]> leaves)
|
|
{
|
|
if (leaves.Count == 0)
|
|
return SHA256.HashData(Array.Empty<byte>());
|
|
|
|
if (leaves.Count == 1)
|
|
return leaves[0];
|
|
|
|
var currentLevel = leaves.ToList();
|
|
|
|
while (currentLevel.Count > 1)
|
|
{
|
|
var nextLevel = new List<byte[]>();
|
|
|
|
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
|
|
}
|
|
|
|
/// <summary>
|
|
/// Result of proof spine assembly.
|
|
/// </summary>
|
|
public sealed class ProofSpineResult
|
|
{
|
|
public required string BundleId { get; init; }
|
|
public required byte[] MerkleRoot { get; init; }
|
|
public required List<string> EvidenceIds { get; init; }
|
|
}
|