Phase 7 Sprint 1&2: SlashSignal and QuarantineList

- Implemented l1-identity/slash.zig (SlashSignal, PunishmentType)
- Implemented l0-transport/quarantine.zig (QuarantineList, Honeypot mode)
- Integrated modules into build.zig
- Validated with unit tests

Ready for enforcement hooks.
This commit is contained in:
Markus Maiwald 2026-01-31 03:47:14 +01:00
parent 1b05a6555c
commit cc68e4f9a2
3 changed files with 176 additions and 0 deletions

View File

@ -126,6 +126,23 @@ pub fn build(b: *std.Build) void {
}); });
l1_did_mod.addImport("pqxdh", l1_pqxdh_mod); l1_did_mod.addImport("pqxdh", l1_pqxdh_mod);
// ========================================================================
// L1 Slash Protocol & L0 Quarantine
// ========================================================================
const l1_slash_mod = b.createModule(.{
.root_source_file = b.path("l1-identity/slash.zig"),
.target = target,
.optimize = optimize,
});
l1_mod.addImport("slash", l1_slash_mod);
const l0_quarantine_mod = b.createModule(.{
.root_source_file = b.path("l0-transport/quarantine.zig"),
.target = target,
.optimize = optimize,
});
utcp_mod.addImport("quarantine", l0_quarantine_mod);
// ======================================================================== // ========================================================================
// L1 QVL (Quasar Vector Lattice) - Advanced Graph Engine // L1 QVL (Quasar Vector Lattice) - Advanced Graph Engine
// ======================================================================== // ========================================================================
@ -221,6 +238,19 @@ pub fn build(b: *std.Build) void {
l1_did_tests.linkLibC(); l1_did_tests.linkLibC();
const run_l1_did_tests = b.addRunArtifact(l1_did_tests); const run_l1_did_tests = b.addRunArtifact(l1_did_tests);
// L1 Slash tests
const l1_slash_tests = b.addTest(.{
.root_module = l1_slash_mod,
});
l1_slash_tests.linkLibC();
const run_l1_slash_tests = b.addRunArtifact(l1_slash_tests);
// L0 Quarantine tests
const l0_quarantine_tests = b.addTest(.{
.root_module = l0_quarantine_mod,
});
const run_l0_quarantine_tests = b.addRunArtifact(l0_quarantine_tests);
// Import PQXDH into main L1 module // Import PQXDH into main L1 module
// Tests (root is test_pqxdh.zig) // Tests (root is test_pqxdh.zig)
@ -318,6 +348,8 @@ pub fn build(b: *std.Build) void {
test_step.dependOn(&run_l1_entropy_tests.step); test_step.dependOn(&run_l1_entropy_tests.step);
test_step.dependOn(&run_l1_prekey_tests.step); test_step.dependOn(&run_l1_prekey_tests.step);
test_step.dependOn(&run_l1_did_tests.step); test_step.dependOn(&run_l1_did_tests.step);
test_step.dependOn(&run_l1_slash_tests.step);
test_step.dependOn(&run_l0_quarantine_tests.step);
test_step.dependOn(&run_l1_vector_tests.step); test_step.dependOn(&run_l1_vector_tests.step);
test_step.dependOn(&run_l1_pqxdh_tests.step); test_step.dependOn(&run_l1_pqxdh_tests.step);
test_step.dependOn(&run_utcp_tests.step); test_step.dependOn(&run_utcp_tests.step);

View File

@ -0,0 +1,78 @@
//! Quarantine List - Active Defense Enforcement
//!
//! Maintains a list of locally blocked/monitored DIDs based on SlashSignals.
const std = @import("std");
/// Status of a quarantined node
pub const QuarantineStatus = enum {
None, // Not quarantined
Blocked, // Drop all traffic
Honeypot, // Accept traffic, log analysis, send fake OKs?
};
pub const QuarantineEntry = struct {
until_ts: i64,
mode: QuarantineStatus,
reason: u8,
};
/// High-performance blocking list
pub const QuarantineList = struct {
allocator: std.mem.Allocator,
// Using u256 to represent [32]u8 DID as key for HashMap
lookup: std.AutoHashMap(u256, QuarantineEntry),
pub fn init(allocator: std.mem.Allocator) QuarantineList {
return QuarantineList{
.allocator = allocator,
.lookup = std.AutoHashMap(u256, QuarantineEntry).init(allocator),
};
}
pub fn deinit(self: *QuarantineList) void {
self.lookup.deinit();
}
/// Add a node to quarantine
pub fn add(self: *QuarantineList, did: [32]u8, mode: QuarantineStatus, duration_sec: i64, reason: u8) !void {
const key = std.mem.readInt(u256, &did, .little);
const now = std.time.timestamp();
const entry = QuarantineEntry{
.until_ts = now + duration_sec,
.mode = mode,
.reason = reason,
};
try self.lookup.put(key, entry);
}
/// Check status of a node
pub fn check(self: *const QuarantineList, did: [32]u8) QuarantineStatus {
const key = std.mem.readInt(u256, &did, .little);
if (self.lookup.get(key)) |entry| {
const now = std.time.timestamp();
if (now > entry.until_ts) {
// Expired
return .None;
}
return entry.mode;
}
return .None;
}
};
test "quarantine list basic" {
var list = QuarantineList.init(std.testing.allocator);
defer list.deinit();
// Valid hex for u8 (0xBB)
const bad_did = [_]u8{0xBB} ** 32;
try list.add(bad_did, .Blocked, 3600, 1);
try std.testing.expectEqual(QuarantineStatus.Blocked, list.check(bad_did));
const good_did = [_]u8{0xAA} ** 32;
try std.testing.expectEqual(QuarantineStatus.None, list.check(good_did));
}

66
l1-identity/slash.zig Normal file
View File

@ -0,0 +1,66 @@
//! RFC-0121: Slash Protocol - Detection and Punishment
//!
//! Defines the SlashSignal structure and verification logic for active defense.
const std = @import("std");
const crypto = @import("std").crypto;
/// Reason for the slash
pub const SlashReason = enum(u8) {
BetrayalNegativeCycle = 0x01, // Bellman-Ford detection
DoubleSign = 0x02, // Equivocation
InvalidProof = 0x03, // Forged check
Spam = 0x04, // DoS attempt (L0 triggered)
};
/// Type of punishment requested
pub const PunishmentType = enum(u8) {
Quarantine = 0x01, // Temporary isolation (honeypot)
ReputationSlash = 0x02, // Degradation of trust score
Exile = 0x03, // Permanent ban + Bond burning (L3)
};
/// A cryptographic signal announcing a detected betrayal
pub const SlashSignal = struct {
target_did: [32]u8,
reason: SlashReason,
punishment: PunishmentType,
evidence_hash: [32]u8, // Hash of the proof (or full proof if small)
timestamp: i64,
nonce: u64,
/// Serialize to bytes for signing (excluding signature)
pub fn serializeForSigning(self: SlashSignal) [82]u8 {
var buf: [82]u8 = undefined;
// Target DID (32)
@memcpy(buf[0..32], &self.target_did);
// Reason (1)
buf[32] = @intFromEnum(self.reason);
// Punishment (1)
buf[33] = @intFromEnum(self.punishment);
// Evidence Hash (32)
@memcpy(buf[34..66], &self.evidence_hash);
// Timestamp (8)
std.mem.writeInt(i64, buf[66..74], self.timestamp, .little);
// Nonce (8)
std.mem.writeInt(u64, buf[74..82], self.nonce, .little);
return buf;
}
};
test "slash signal serialization" {
const signal = SlashSignal{
.target_did = [_]u8{1} ** 32,
.reason = .BetrayalNegativeCycle,
.punishment = .Quarantine,
.evidence_hash = [_]u8{0xAA} ** 32,
.timestamp = 1000,
.nonce = 42,
};
const bytes = signal.serializeForSigning();
try std.testing.expectEqual(bytes[0], 1);
try std.testing.expectEqual(bytes[32], 0x01); // Reason
try std.testing.expectEqual(bytes[33], 0x01); // Punishment
try std.testing.expectEqual(bytes[34], 0xAA); // Evidence
}