libertaria-stack/core/l1-identity/vector.zig

268 lines
8.7 KiB
Zig

//! Quasar Vector (RFC-0120)
//!
//! The atomic unit of communication in QVL. Replaces "transactions".
//! vectors are Events.
//!
//! Structure:
//! - Source DID (32 bytes)
//! - Target DID (32 bytes)
//! - Vector Type (2 bytes)
//! - Payload Hash (32 bytes)
//! - Payload (Optional)
//! - Signature (64 bytes) -- covers above fields
//! - Trust Path (ProofOfPath) -- hardening
//! - Entropy Proof (EntropyStamp) -- anti-spam
//! - Timestamp (SovereignTimestamp)
//! - Graphology (Meta)
//! - Nonce (8 bytes)
const std = @import("std");
const time = @import("time");
const proof_of_path = @import("proof_of_path.zig");
const soulkey = @import("soulkey.zig");
const entropy = @import("entropy.zig");
const trust_graph = @import("trust_graph.zig");
/// Vector Type (RFC-0120 S4.2)
pub const VectorType = enum(u16) {
// Communication (0x0700-0x070F)
message = 0x0700,
message_ack = 0x0701,
// Value Transfer (0x0710-0x071F) - triggers L2
value_transfer = 0x0710,
value_receipt = 0x0711,
// Credentials (0x0720-0x072F)
credential_issue = 0x0720,
credential_revoke = 0x0721,
// Trust Graph (0x0730-0x073F)
trust_grant = 0x0730,
trust_revoke = 0x0731,
trust_delegate = 0x0732,
// Anchoring (0x0740-0x074F)
anchor_commit = 0x0740,
anchor_proof = 0x0741,
// Explorer (0x0750-0x075F)
explorer_probe = 0x0750,
explorer_signal = 0x0751,
};
/// Graphology Metadata (8 bytes)
/// Measures the "shape" of the relationship
pub const GraphologyMeta = packed struct {
trust_depth: u8, // 0 = direct, 255 = void
mutual_contacts: u8, // Shared nodes (capped at 255)
path_reputation: u16, // 0-65535 scaled to 0.0-1.0
flags: GraphologyFlags, // Bit flags (4 bytes padding/flags)
};
pub const GraphologyFlags = packed struct {
first_contact: bool,
whitelisted: bool,
blacklisted: bool,
from_void: bool,
degraded_path: bool,
_pad: u27,
};
/// The Quasar Vector
pub const QuasarVector = struct {
// === Identity (64 bytes) ===
source_did: [32]u8,
target_did: [32]u8, // 0x00 for broadcast
// === Type (2 bytes) ===
vector_type: VectorType,
// === Payload ===
payload_hash: [32]u8,
payload: ?[]u8, // Optional content
// === Authentication ===
signature: [64]u8, // Ed25519 over body
trust_path: ?proof_of_path.ProofOfPath, // Optional for direct peers
entropy_stamps: std.ArrayListUnmanaged(entropy.EntropyStamp), // PoW
// === Metadata ===
created_at: time.SovereignTimestamp, // Creation time
graphology: GraphologyMeta,
nonce: u64, // Replay protection
allocator: std.mem.Allocator,
pub fn init(allocator: std.mem.Allocator) QuasarVector {
return .{
.source_did = [_]u8{0} ** 32,
.target_did = [_]u8{0} ** 32,
.vector_type = .message,
.payload_hash = [_]u8{0} ** 32,
.payload = null,
.signature = [_]u8{0} ** 64,
.trust_path = null,
.entropy_stamps = .{},
.created_at = time.SovereignTimestamp.now(),
.graphology = std.mem.zeroes(GraphologyMeta),
.nonce = std.crypto.random.int(u64), // Secure random nonce
.allocator = allocator,
};
}
pub fn deinit(self: *QuasarVector) void {
if (self.payload) |p| self.allocator.free(p);
if (self.trust_path) |*tp| tp.deinit();
self.entropy_stamps.deinit(self.allocator);
}
/// Sign the vector (Ed25519)
/// Signs: source || target || type || hash || created_at || nonce
pub fn sign(self: *QuasarVector, sk: *const soulkey.SoulKey) !void {
var msg = std.ArrayListUnmanaged(u8){};
defer msg.deinit(self.allocator);
const writer = msg.writer(self.allocator);
try writer.writeAll(&self.source_did);
try writer.writeAll(&self.target_did);
try writer.writeInt(u16, @intFromEnum(self.vector_type), .little);
try writer.writeAll(&self.payload_hash);
try writer.writeAll(&self.created_at.serialize());
try writer.writeInt(u64, self.nonce, .little);
const sig = try sk.sign(msg.items);
self.signature = sig;
}
/// Verify signature
pub fn verifySignature(self: *const QuasarVector) bool {
var msg = std.ArrayListUnmanaged(u8){};
defer msg.deinit(self.allocator);
const writer = msg.writer(self.allocator);
writer.writeAll(&self.source_did) catch return false;
writer.writeAll(&self.target_did) catch return false;
writer.writeInt(u16, @intFromEnum(self.vector_type), .little) catch return false;
writer.writeAll(&self.payload_hash) catch return false;
writer.writeAll(&self.created_at.serialize()) catch return false;
writer.writeInt(u64, self.nonce, .little) catch return false;
return soulkey.SoulKey.verify(self.source_did, msg.items, self.signature) catch false;
}
/// Full Validation Pipeline (Reality Tunnel Hook)
/// Checks: Signature, Time, Trust Path
pub fn validate(
self: *const QuasarVector,
graph: *const trust_graph.CompactTrustGraph,
) ValidationResult {
// 1. Signature Check
if (!self.verifySignature()) return .invalid_signature;
// 2. Time Check
const now = time.SovereignTimestamp.now();
switch (self.created_at.validateForVector(now)) {
.valid => {},
.too_far_future => return .future_timestamp,
.too_old => return .expired,
}
// 3. Trust Check
// If ProofOfPath provided, verify it
if (self.trust_path) |*pop| {
const verdict = pop.verify(self.target_did, self.source_did, graph);
if (verdict != .valid) return .invalid_trust_path;
} else {
// No proof provided - check direct trust
if (!graph.hasDirectTrustByDid(self.target_did, self.source_did)) {
return .unknown_sender; // Airlock rejection
}
}
return .valid;
}
pub const ValidationResult = enum {
valid,
invalid_signature,
future_timestamp,
expired,
invalid_trust_path,
unknown_sender,
};
/// Set Payload
pub fn setPayload(self: *QuasarVector, data: []const u8) !void {
if (self.payload) |p| self.allocator.free(p);
self.payload = try self.allocator.dupe(u8, data);
std.crypto.hash.Blake3.hash(data, &self.payload_hash, .{});
}
};
// ============================================================================
// TESTS
// ============================================================================
test "QuasarVector: init and sign" {
const allocator = std.testing.allocator;
// Create a keypair
var sk = try soulkey.SoulKey.generate();
var vector = QuasarVector.init(allocator);
defer vector.deinit();
vector.source_did = sk.ed25519_public;
try vector.setPayload("Hello QVL!");
// Sign
try vector.sign(&sk);
// Verify
try std.testing.expect(vector.verifySignature());
// Tamper
vector.nonce += 1;
try std.testing.expect(!vector.verifySignature());
}
test "QuasarVector: validation flow" {
const allocator = std.testing.allocator;
// Setup: Receiver trusts A. A trusts Sender.
// Sender sends vector to Receiver with ProofOfPath(R->A->S).
// 1. Keys
const k_r = try soulkey.SoulKey.generate(); // Receiver
const k_a = try soulkey.SoulKey.generate(); // Intermediary
var k_s = try soulkey.SoulKey.generate(); // Sender
// 2. Receiver's Trust Graph
var graph = try trust_graph.CompactTrustGraph.init(allocator, k_r.ed25519_public, .{});
defer graph.deinit();
try graph.grantTrust(k_a.ed25519_public, .full, .friends, 0);
// Manual edge in graph for path finding (A->S)
const a_idx = graph.getNode(k_a.ed25519_public).?;
const s_idx = try graph.getOrInsertNode(k_s.ed25519_public);
try graph.adjacency.items[a_idx].append(allocator, .{ .target_idx = s_idx, .level = .full, .visibility = .public, .expires_at = 0 });
// 3. Sender creates Vector
var vector = QuasarVector.init(allocator);
defer vector.deinit();
vector.source_did = k_s.ed25519_public;
vector.target_did = k_r.ed25519_public;
try vector.sign(&k_s);
// 4. Validation (Should fail: unknown sender, no proof)
try std.testing.expectEqual(QuasarVector.ValidationResult.unknown_sender, vector.validate(&graph));
// 5. Add Proof
const pop = try proof_of_path.ProofOfPath.construct(allocator, k_s.ed25519_public, k_r.ed25519_public, &graph);
vector.trust_path = pop;
// 6. Validation (Should pass)
try std.testing.expectEqual(QuasarVector.ValidationResult.valid, vector.validate(&graph));
}