From cc68e4f9a25be5a6af6efc9f15bdf928ec692b83 Mon Sep 17 00:00:00 2001 From: Markus Maiwald Date: Sat, 31 Jan 2026 03:47:14 +0100 Subject: [PATCH] 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. --- build.zig | 32 +++++++++++++++ l0-transport/quarantine.zig | 78 +++++++++++++++++++++++++++++++++++++ l1-identity/slash.zig | 66 +++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 l0-transport/quarantine.zig create mode 100644 l1-identity/slash.zig diff --git a/build.zig b/build.zig index 7427e42..51d6520 100644 --- a/build.zig +++ b/build.zig @@ -126,6 +126,23 @@ pub fn build(b: *std.Build) void { }); 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 // ======================================================================== @@ -221,6 +238,19 @@ pub fn build(b: *std.Build) void { l1_did_tests.linkLibC(); 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 // 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_prekey_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_pqxdh_tests.step); test_step.dependOn(&run_utcp_tests.step); diff --git a/l0-transport/quarantine.zig b/l0-transport/quarantine.zig new file mode 100644 index 0000000..b4191d3 --- /dev/null +++ b/l0-transport/quarantine.zig @@ -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)); +} diff --git a/l1-identity/slash.zig b/l1-identity/slash.zig new file mode 100644 index 0000000..ef54d87 --- /dev/null +++ b/l1-identity/slash.zig @@ -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 +}