code wiki / (root) / nx_crispr.nx

nx_crispr.nx source

↩ module page · 223 lines · 8134 B

1// nx_crispr.nx -- adaptive signature memory (Tier-1 immune). 2// 3// Biology: CRISPR-Cas is the bacterial adaptive immune system. When 4// a virus infects, bacteria capture a fragment of viral DNA as a 5// "spacer" in their CRISPR array; on next encounter, Cas enzymes 6// match the spacer and cleave the virus. Substrate equivalent: when 7// nx_pamp detects a hit, nx_crispr remembers its content-addressed 8// signature; on next encounter the lookup is O(1) and the response 9// can fire WITHOUT re-running pamp's expensive scanners. 10// 11// THIS COMPLETES THE LEARN-FROM-EXPERIENCE LOOP. nx_pamp is the 12// pattern recognition; nx_crispr is the memory. Together they 13// implement adaptive innate immunity. Per [[feedback-unified-immune- 14// architecture-three-tier]] the signature DB grows across encounters 15// and (V2) shares via peer mesh so every Nishi cell benefits from 16// every Nishi cell's incident history. 17// 18// Composes: 19// nx_pamp -- supplier of new signatures to remember 20// nx_xenocell -- the source of confirmed-hostile events 21// nx_decoy -- decoy hits become CRISPR entries since they prove 22// someone read the decoy 23// nx_evict_journal -- pre-existing forensic substrate; CRISPR 24// complements (pamp_journal is event log, 25// crispr is THE SIGNATURE INDEX) 26// 27// V1 ships a fixed-capacity ring of spacer entries. V2 makes it 28// peer-sharable (content-addressed merkle tree) so the community 29// shares intrusion intelligence without leaking specifics. 30// 31// Gap list (V1 honest perf verdict): 32// - linear-scan lookup; V2 builds hash index for O(1) 33// - no automatic expiration of stale spacers 34// - no peer-mesh federation 35// - no signature-class grouping (every spacer treated independently) 36// 37// genealogy_id: cardinal_2026-05-19_tier_1_innate_immune_microbial + 38// biology_CRISPR_Cas_adaptive_immunity 39// lineage_id: substrate_crispr_v1 40// 41// nx_safety_envelope: 42// intended_use: "Adaptive memory of confirmed attacker 43// signatures; cheap second-encounter matching" 44// sil_target: SIL2 45// evidence: [append_only_invariant, 46// content_addressed_lookup] 47// verdict: NOT_YET_EVALUATED 48 49import "nx_syscalls.nx" 50import "nx_tier.nx" 51import "nx_pamp.nx" 52 53// ===== Sealed enum: NxCrisprVerdict =============================== 54 55const NX_CRISPR_OK: nx_int = 0 56const NX_CRISPR_ERR_FULL: nx_int = 1 57const NX_CRISPR_HIT: nx_int = 2 // signature matched 58const NX_CRISPR_MISS: nx_int = 3 // signature not in DB 59 60// ===== Struct: NxCrisprSpacer ===================================== 61// 62// One row per confirmed attacker signature. kind aliases NX_PAMP_* 63// constants (or caller's own taxonomy for non-PAMP-detected events). 64// content_hash is BLAKE3 (or equivalent) of the offending byte 65// region. first_seen_us + last_seen_us bracket the attack window; 66// hit_count tracks recurrence. 67 68struct NxCrisprSpacer { 69 kind: nx_int, 70 content_hash: nx_size, 71 first_seen_us: nx_size, 72 last_seen_us: nx_size, 73 hit_count: nx_int, 74} 75 76// ===== Struct: NxCrisprArray ====================================== 77// 78// Bacterial CRISPR array = ordered list of spacers. Append-only ring; 79// when at capacity, oldest entries roll out (caller queries count vs 80// capacity to detect history loss). 81 82struct NxCrisprArray { 83 spacers: *NxCrisprSpacer, 84 capacity: nx_size, 85 head: nx_size, 86 count: nx_size, 87} 88 89const NX_CRISPR_SPACER_BYTES: nx_size = 40 90const NX_CRISPR_DEFAULT_CAPACITY: nx_size = 256 91 92// ===== Constructor =============================================== 93 94func nx_crispr_new(capacity: nx_size) -> *NxCrisprArray { 95 let a: *NxCrisprArray = (sys_mmap(32)) as *NxCrisprArray 96 let bytes: nx_size = capacity * NX_CRISPR_SPACER_BYTES 97 a.spacers = (sys_mmap(bytes)) as *NxCrisprSpacer 98 a.capacity = capacity 99 a.head = 0 100 a.count = 0 101 return a 102} 103 104// ===== _crispr_at ================================================ 105 106func _crispr_at(a: *NxCrisprArray, idx: nx_size) -> *NxCrisprSpacer { 107 return (a.spacers as i64 + (idx as i64) * NX_CRISPR_SPACER_BYTES) as *NxCrisprSpacer 108} 109 110// ===== nx_crispr_match =========================================== 111// 112// Linear-scan check: is (kind, content_hash) already in the array? 113// Returns NX_CRISPR_HIT and (via out_idx) the spacer index if found; 114// NX_CRISPR_MISS otherwise. Caller can then call nx_crispr_touch to 115// update last_seen + hit_count. 116 117func nx_crispr_match(a: *NxCrisprArray, 118 kind: nx_int, 119 content_hash: nx_size, 120 out_idx: *i64) -> nx_int { 121 var live: nx_size = a.count 122 if live > a.capacity { live = a.capacity } 123 var i: nx_size = 0 124 while i < live { 125 let s: *NxCrisprSpacer = _crispr_at(a, i) 126 if s.kind == kind { 127 if s.content_hash == content_hash { 128 out_idx[0] = i as i64 129 return NX_CRISPR_HIT 130 } 131 } 132 i = i + 1 133 } 134 out_idx[0] = -1 135 return NX_CRISPR_MISS 136} 137 138// ===== nx_crispr_remember ======================================== 139// 140// Append a new spacer (first-time observation). If the signature 141// already exists, this is a no-op; caller should have checked with 142// nx_crispr_match first. We re-check to keep idempotency. 143 144func nx_crispr_remember(a: *NxCrisprArray, 145 kind: nx_int, 146 content_hash: nx_size, 147 now_us: nx_size) -> nx_int { 148 if nx_pamp_kind_is_valid(kind) == 0 { 149 // allow non-pamp kinds too (caller's taxonomy may extend) 150 } 151 let probe: *i64 = (sys_mmap(8)) as *i64 152 let m: nx_int = nx_crispr_match(a, kind, content_hash, probe) 153 if m == NX_CRISPR_HIT { 154 // Already known; touch instead. 155 let idx: nx_size = probe[0] as nx_size 156 let s: *NxCrisprSpacer = _crispr_at(a, idx) 157 s.last_seen_us = now_us 158 s.hit_count = s.hit_count + 1 159 return NX_CRISPR_OK 160 } 161 let slot: *NxCrisprSpacer = _crispr_at(a, a.head) 162 slot.kind = kind 163 slot.content_hash = content_hash 164 slot.first_seen_us = now_us 165 slot.last_seen_us = now_us 166 slot.hit_count = 1 167 a.head = a.head + 1 168 if a.head >= a.capacity { a.head = 0 } 169 a.count = a.count + 1 170 return NX_CRISPR_OK 171} 172 173// ===== nx_crispr_touch =========================================== 174// 175// Caller already knows the spacer index (from a prior match). Update 176// last_seen and increment hit_count. Used in the hot path: pamp fires 177// -> crispr_match returns HIT -> crispr_touch updates -> response 178// fires using the cached signature. 179 180func nx_crispr_touch(a: *NxCrisprArray, idx: nx_size, now_us: nx_size) -> nx_int { 181 if idx >= a.capacity { return NX_CRISPR_OK } 182 let s: *NxCrisprSpacer = _crispr_at(a, idx) 183 s.last_seen_us = now_us 184 s.hit_count = s.hit_count + 1 185 return NX_CRISPR_OK 186} 187 188// ===== nx_crispr_count_kind ====================================== 189// 190// How many distinct signatures of a given kind are remembered? Used 191// for trend analysis: "homoglyph attacks remembered = 247" suggests 192// active campaign. 193 194func nx_crispr_count_kind(a: *NxCrisprArray, kind: nx_int) -> nx_int { 195 var hits: nx_int = 0 196 var live: nx_size = a.count 197 if live > a.capacity { live = a.capacity } 198 var i: nx_size = 0 199 while i < live { 200 let s: *NxCrisprSpacer = _crispr_at(a, i) 201 if s.kind == kind { hits = hits + 1 } 202 i = i + 1 203 } 204 return hits 205} 206 207// ===== nx_crispr_total_hits ====================================== 208// 209// Sum of hit_count across all spacers. Indicator of how often the 210// substrate has matched repeats (high = adaptive immunity is working). 211 212func nx_crispr_total_hits(a: *NxCrisprArray) -> nx_int { 213 var sum: nx_int = 0 214 var live: nx_size = a.count 215 if live > a.capacity { live = a.capacity } 216 var i: nx_size = 0 217 while i < live { 218 let s: *NxCrisprSpacer = _crispr_at(a, i) 219 sum = sum + s.hit_count 220 i = i + 1 221 } 222 return sum 223}