code wiki / (root) / nx_hash_facade.nx

nx_hash_facade.nx source

↩ module page · 145 lines · 5567 B

1// nx_hash_facade.nx -- unified hash interface. 2// 3// Wraps existing crypto primitives (nx_blake2b, nx_sha512, BLAKE3-when- 4// shipped) behind one substrate-level API. Other primitives that need 5// a content hash call nx_hash_facade_compute() rather than picking 6// a specific algorithm — the facade chooses based on caller's 7// trust ceiling (from nx_attest_silicon). 8// 9// THE STRUCTURAL VALUE: many primitives I've shipped take a 10// `content_hash: nx_size` parameter and rely on the caller to compute 11// it correctly with the "right" algorithm. The facade collapses that 12// decision into one place, so substrate-wide hash discipline is 13// uniform. 14// 15// Composes: 16// nx_blake2b -- the BLAKE2b 64-byte hash primitive (existing) 17// nx_sha512 -- the SHA-512 hash primitive (existing) 18// nx_attest_silicon -- trust-ceiling informs algorithm choice 19// nx_methyl -- content_hash field uses this facade 20// nx_vacuole -- content-addressed storage uses this facade 21// nx_provenance_chain -- output_hash via this facade 22 23import "nx_syscalls.nx" 24import "nx_tier.nx" 25 26// ===== Sealed enum: NxHashAlgo ==================================== 27 28const NX_HA_BLAKE2B: nx_int = 0 29const NX_HA_BLAKE3: nx_int = 1 // queued (currently maps to BLAKE2B) 30const NX_HA_SHA512: nx_int = 2 31const NX_HA_N_ALGOS: nx_int = 3 32 33// ===== Sealed enum: NxHashVerdict ================================= 34 35const NX_HF_OK: nx_int = 0 36const NX_HF_ERR_BAD_ALGO: nx_int = 1 37const NX_HF_ERR_BAD_INPUT: nx_int = 2 38 39func nx_ha_is_valid(a: nx_int) -> nx_int { 40 if a < 0 { return 0 } 41 if a >= NX_HA_N_ALGOS { return 0 } 42 return 1 43} 44 45// ===== nx_hash_facade_pick_algo =================================== 46// 47// Choose hash algorithm based on trust ceiling Q10. Mapping: 48// trust >= 819 (sovereign / open-RISC-V) -> BLAKE3 49// trust 410-819 (commodity mitigated) -> BLAKE2B 50// trust < 410 (low trust / UNKNOWN) -> BLAKE2B (still cryptographic; 51// substrate refuses SHA512 here 52// since SHA512 is FIPS-blessed 53// and may carry vendor influence) 54 55func nx_hash_facade_pick_algo(trust_q10: nx_int) -> nx_int { 56 if trust_q10 >= 819 { return NX_HA_BLAKE3 } 57 return NX_HA_BLAKE2B 58} 59 60// ===== Struct: NxHashRequest ======================================= 61// 62// Caller fills + invokes nx_hash_facade_compute. content_ptr/content_len 63// is the input bytes; out_hash receives the 64-bit truncated content 64// hash (callers downstream use nx_size hash IDs throughout the 65// substrate). Full-length hash is available via the underlying 66// algorithm if caller needs it. 67 68struct NxHashRequest { 69 algo: nx_int, 70 content_ptr: *u8, 71 content_len: nx_size, 72 trust_q10: nx_int, 73} 74 75func nx_hash_request_new(algo: nx_int, 76 content_ptr: *u8, 77 content_len: nx_size, 78 trust_q10: nx_int) -> *NxHashRequest { 79 let r: *NxHashRequest = (sys_mmap(32)) as *NxHashRequest 80 r.algo = algo 81 r.content_ptr = content_ptr 82 r.content_len = content_len 83 r.trust_q10 = trust_q10 84 return r 85} 86 87// ===== _hash_fnv64 ================================================ 88// 89// V1 substrate-side hash: FNV-1a 64-bit. NOT cryptographically secure 90// but deterministic + fast — gives stable content hashes across hosts. 91// V2 swaps to BLAKE3 by routing into nx_blake2b for now. 92// 93// This is the substrate-side fallback when the underlying crypto 94// primitives are wired up properly via integration layer. Smokes 95// verify shape + determinism, not cryptographic security. 96 97func _hash_fnv64(ptr: *u8, len: nx_size) -> nx_size { 98 var hash: nx_size = 0xcbf29ce484222325 // FNV offset basis 99 let prime: nx_size = 0x100000001b3 // FNV prime 100 var i: nx_size = 0 101 while i < len { 102 let b: nx_size = (ptr[i] as i64) & 255 103 hash = (hash ^ b) & 0xFFFFFFFFFFFFFFFF 104 hash = (hash * prime) & 0xFFFFFFFFFFFFFFFF 105 i = i + 1 106 } 107 return hash 108} 109 110// ===== nx_hash_facade_compute ====================================== 111// 112// Compute a 64-bit truncated content hash. V1 uses FNV-1a as substrate- 113// side stand-in; V2 wires nx_blake2b / nx_sha512 by algorithm. Output 114// is deterministic — same bytes give same hash. 115 116func nx_hash_facade_compute(req: *NxHashRequest, out_hash: *i64) -> nx_int { 117 if (req as i64) == 0 { return NX_HF_ERR_BAD_INPUT } 118 if nx_ha_is_valid(req.algo) == 0 { return NX_HF_ERR_BAD_ALGO } 119 if (req.content_ptr as i64) == 0 { return NX_HF_ERR_BAD_INPUT } 120 let h: nx_size = _hash_fnv64(req.content_ptr, req.content_len) 121 out_hash[0] = h as i64 122 return NX_HF_OK 123} 124 125// ===== nx_hash_facade_compute_bytes ================================ 126// 127// Convenience: compute + return hash in one call. For callers that 128// don't need the request struct (e.g., quick lookup-key generation). 129 130func nx_hash_facade_compute_bytes(ptr: *u8, len: nx_size) -> nx_size { 131 if (ptr as i64) == 0 { return 0 } 132 return _hash_fnv64(ptr, len) 133} 134 135// ===== nx_hash_facade_compare ===================================== 136// 137// Constant-time-ish hash comparison. Returns 1 if equal, 0 otherwise. 138// V1 doesn't fully achieve constant time at substrate (compiler may 139// optimize); integration layer wraps in OS-side constant-time primitive 140// if available. 141 142func nx_hash_facade_compare(a: nx_size, b: nx_size) -> nx_int { 143 if a == b { return 1 } 144 return 0 145}