code wiki / (root) / nx_image_search_gate.nx

nx_image_search_gate.nx source

↩ module page · 263 lines · 13261 B

1// nx_image_search_gate.nx -- the engineer's re-runnable instrument for the REUSABLE search-by-image 2// client (nx_image_search). Builds TWO isolated site fingerprint-indices from SYNTHESIZED grayscale 3// images with CONTROLLED dHash relationships, registers both in a sites TSV, writes query images to 4// /tmp, then forks+execs the REAL /tmp/nx_image_search.sov.elf over a KAT + neg-control + isolation 5// oracle. It PROVES (not asserts) the research-documented dHash properties end-to-end (image -> hash 6// -> per-site nearest): 7// row1 identical query -> right image rank 1 at Hamming 0 8// row2 +brightness query -> STILL Hamming 0 (dHash brightness invariance, Krawetz 2011) 9// row3 near-dup (block tweak) -> right image rank 1, small Hamming (<= threshold) 10// row4 precision -> a structurally-different indexed image (Hamming 64) is EXCLUDED 11// row5 isolation A + neg-ctrl -> a BETA-only image queried on ALPHA returns matches=0 (alpha cannot 12// surface content it does not hold) 13// row6 isolation B -> an image present in BOTH sites, queried on BETA, returns the BETA 14// cid and NEVER an alpha cid (client loaded the right per-site index) 15// row7 unknown site -> clean exit 1 with "unknown site" (no crash) 16// GREEN iff all 7 rows pass. Durable verdict appends to knowledge/status/image_search_gate.log. 17// license_tier: ORIGINAL 18import "nx_phash.nx" 19 20func g_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 21func g_num(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=(48 as u8);k=1}; while m>0{t[k]=((48+(m%10)) as u8);m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(1,bb,k); return 0 } 22func g_w(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 } 23func g_wn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=(48 as u8);k=1}; while m>0{t[k]=((48+(m%10)) as u8);m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(fd,bb,k); return 0 } 24func g_strlen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 25 26func g_write_file(path: *u8, data: *u8) -> i64 { 27 let fd: i64=sys_openat_wr(path, 0x1a4) 28 if fd<0 { return 0-1 } 29 sys_write(fd, data, g_strlen(data)) 30 sys_close(fd) 31 return 0 32} 33func g_write_gray(path: *u8, buf: *u8, n: i64) -> i64 { 34 let fd: i64=sys_openat_wr(path, 0x1a4) 35 if fd<0 { return 0-1 } 36 sys_write(fd, buf, n) 37 sys_close(fd) 38 return 0 39} 40func g_read_small(path: *u8, buf: *u8, cap: i64) -> i64 { 41 let fd: i64=sys_openat_rd(path) 42 if fd<0 { return 0 } 43 var total: i64=0 44 var nrd: i64=sys_read(fd, buf, cap) 45 while nrd>0 { total=total+nrd; if total>=cap { nrd=0 } else { nrd=sys_read(fd, ((buf as i64)+total) as *u8, cap-total) } } 46 sys_close(fd) 47 return total 48} 49 50// emit one i64 as 16 lowercase-hex chars (high nibble first); &0xF masks sign-extension cleanly 51func g_hexemit(fd: i64, v: i64) -> i64 { 52 let buf: *u8=sys_mmap(16) 53 var i: i64=0 54 while i<16 { 55 let shift: i64=(15-i)*4 56 let nib: i64=(v>>shift)&0xF 57 var c: i64=0 58 if nib<10 { c=48+nib } else { c=87+nib } 59 buf[i]=c as u8 60 i=i+1 61 } 62 sys_write(fd, buf, 16) 63 return 0 64} 65 66// synthesize a grayscale image. kind 0=horizontal gradient up (dHash all-0), 1=gradient down 67// (dHash all-1), 3=period-4 vertical stripes (~24 bits set, far from both). bright adds a uniform 68// offset (clamped) to exercise dHash's brightness invariance. 69func g_synth(buf: *u8, w: i64, h: i64, kind: i64, bright: i64) -> i64 { 70 var y: i64=0 71 while y<h { 72 var x: i64=0 73 while x<w { 74 var v: i64=0 75 if kind==0 { v=x*4 } 76 if kind==1 { v=(w-1-x)*4 } 77 if kind==3 { v=(x&2)*30 } 78 v=v+bright 79 if v<0 { v=0 } 80 if v>255 { v=255 } 81 buf[y*w+x]=v as u8 82 x=x+1 83 } 84 y=y+1 85 } 86 return 0 87} 88 89// append one fp-index row: cid<TAB>dhash_hex<TAB>ahash_hex 90func g_emit_idx_row(fd: i64, cid: *u8, buf: *u8, w: i64, h: i64) -> i64 { 91 let d: i64=nx_phash_dhash(buf, w, h) 92 let a: i64=nx_phash_ahash(buf, w, h) 93 sys_write(fd, cid, g_strlen(cid)); sys_write(fd, "\t" as *u8, 1) 94 g_hexemit(fd, d); sys_write(fd, "\t" as *u8, 1) 95 g_hexemit(fd, a); sys_write(fd, "\n" as *u8, 1) 96 return 0 97} 98 99// fork+exec the real client, capturing stdout to out_path; return its exit code. 100func g_run(sites: *u8, site: *u8, qpath: *u8, ws: *u8, hs: *u8, ths: *u8, out_path: *u8) -> i64 { 101 let pid: i64=sys_fork() 102 if pid==0 { 103 let out: i64=sys_openat_wr(out_path, 0x1a4) 104 if out>=0 { sys_dup3(out, 1, 0) } 105 let argv: *i64=sys_mmap(8*8) as *i64 106 argv[0]="/tmp/nx_image_search.sov.elf" as *u8 as i64 107 argv[1]=sites as i64; argv[2]=site as i64; argv[3]=qpath as i64 108 argv[4]=ws as i64; argv[5]=hs as i64; argv[6]=ths as i64; argv[7]=0 109 let envp: *i64=sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0 110 sys_execve("/tmp/nx_image_search.sov.elf" as *u8, argv, envp) 111 sys_exit(127) 112 } 113 let st: *i64=sys_mmap(16) as *i64 114 sys_wait4(pid, st, 0) 115 if (st[0]&0x7f)!=0 { return 128+(st[0]&0x7f) } 116 return (st[0]>>8)&0xff 117} 118 119func g_find(hay: *u8, n: i64, needle: *u8) -> i64 { 120 let nl: i64=g_strlen(needle) 121 if nl==0 { return 0-1 } 122 var i: i64=0 123 while i+nl<=n { 124 var j: i64=0; var hit: i64=1 125 while j<nl { if hay[i+j]!=needle[j] { hit=0; j=nl } else { j=j+1 } } 126 if hit==1 { return i } 127 i=i+1 128 } 129 return 0-1 130} 131func g_contains(hay: *u8, n: i64, needle: *u8) -> i64 { if g_find(hay,n,needle)>=0 { return 1 } return 0 } 132func g_rank_of(buf: *u8, n: i64, expected: *u8) -> i64 { 133 let at: i64=g_find(buf, n, expected) 134 if at<0 { return 0 } 135 var ls: i64=at 136 while ls>0 { if buf[ls-1]==(10 as u8) { ls=0-ls } else { ls=ls-1 } } 137 if ls<0 { ls=0-ls } 138 let hash_at: i64=g_find(((buf as i64)+ls) as *u8, at-ls+1, "#" as *u8) 139 if hash_at<0 { return 0 } 140 var p: i64=ls+hash_at+1 141 var rank: i64=0 142 while p<n { let c: i64=buf[p] as i64; if c>=48 { if c<=57 { rank=rank*10+(c-48); p=p+1 } else { p=n } } else { p=n } } 143 return rank 144} 145 146func main() -> i64 { 147 g_puts("=== IMAGE SEARCH GATE (reusable search-by-image: dHash KAT + brightness-invariance + precision + isolation + unknown-site) ===\n" as *u8) 148 let W: i64=16 149 let H: i64=16 150 let N: i64=256 151 152 // synthesize the corpus + query images 153 let up: *u8=sys_mmap(N); g_synth(up, W, H, 0, 0) 154 let down: *u8=sys_mmap(N); g_synth(down, W, H, 1, 0) 155 let mid: *u8=sys_mmap(N); g_synth(mid, W, H, 3, 0) 156 let bright: *u8=sys_mmap(N); g_synth(bright, W, H, 0, 40) 157 let near: *u8=sys_mmap(N); g_synth(near, W, H, 0, 0) 158 var by: i64=2 159 while by<5 { var bx: i64=2; while bx<5 { near[by*W+bx]=63 as u8; bx=bx+1 } by=by+1 } 160 161 // measured dHash benchmark (print every value -- honest-perf cardinal) 162 let d_up: i64=nx_phash_dhash(up, W, H) 163 g_puts(" dHash(up..down)=" as *u8); g_num(nx_simhash_hamming(d_up, nx_phash_dhash(down, W, H))) 164 g_puts(" dHash(up..mid)=" as *u8); g_num(nx_simhash_hamming(d_up, nx_phash_dhash(mid, W, H))) 165 g_puts(" dHash(up..bright)=" as *u8); g_num(nx_simhash_hamming(d_up, nx_phash_dhash(bright, W, H))) 166 g_puts(" dHash(up..near)=" as *u8); g_num(nx_simhash_hamming(d_up, nx_phash_dhash(near, W, H))) 167 g_puts("\n" as *u8) 168 169 // write query images 170 g_write_gray("/tmp/q_up.gray" as *u8, up, N) 171 g_write_gray("/tmp/q_upbright.gray" as *u8, bright, N) 172 g_write_gray("/tmp/q_upnear.gray" as *u8, near, N) 173 g_write_gray("/tmp/q_mid.gray" as *u8, mid, N) 174 175 // build ALPHA index {/A/up, /A/down} 176 let fa: i64=sys_openat_wr("/tmp/img_alpha.idx" as *u8, 0x1a4) 177 if fa>=0 { 178 g_emit_idx_row(fa, "/A/up" as *u8, up, W, H) 179 g_emit_idx_row(fa, "/A/down" as *u8, down, W, H) 180 sys_close(fa) 181 } 182 // build BETA index {/B/up (same image, different site), /B/mid (beta-only)} 183 let fb: i64=sys_openat_wr("/tmp/img_beta.idx" as *u8, 0x1a4) 184 if fb>=0 { 185 g_emit_idx_row(fb, "/B/up" as *u8, up, W, H) 186 g_emit_idx_row(fb, "/B/mid" as *u8, mid, W, H) 187 sys_close(fb) 188 } 189 g_write_file("/tmp/img_sites.tsv" as *u8, 190 "alpha\t/tmp/img_alpha.idx\thttps://site-a\nbeta\t/tmp/img_beta.idx\thttps://site-b\n" as *u8) 191 192 let sites: *u8="/tmp/img_sites.tsv" as *u8 193 let outp: *u8="/tmp/img_gate_out.txt" as *u8 194 let obuf: *u8=sys_mmap(65536) 195 let ws: *u8="16" as *u8 196 let hs: *u8="16" as *u8 197 let ths: *u8="10" as *u8 198 199 var pass: i64=0 200 let rows: i64=7 201 202 // row1: identical -> /A/up rank 1, ham 0 203 g_run(sites, "alpha" as *u8, "/tmp/q_up.gray" as *u8, ws, hs, ths, outp) 204 let n1: i64=g_read_small(outp, obuf, 65536) 205 let rk1: i64=g_rank_of(obuf, n1, "/A/up" as *u8) 206 let h0_1: i64=g_contains(obuf, n1, "ham=0" as *u8) 207 g_puts(" row1 identical -> rank " as *u8); g_num(rk1); g_puts(" ham0? " as *u8); g_num(h0_1) 208 if rk1==1 { if h0_1==1 { pass=pass+1; g_puts(" PASS\n" as *u8) } else { g_puts(" FAIL\n" as *u8) } } else { g_puts(" FAIL\n" as *u8) } 209 210 // row2: +brightness -> /A/up rank 1, STILL ham 0 (invariance) 211 g_run(sites, "alpha" as *u8, "/tmp/q_upbright.gray" as *u8, ws, hs, ths, outp) 212 let n2: i64=g_read_small(outp, obuf, 65536) 213 let rk2: i64=g_rank_of(obuf, n2, "/A/up" as *u8) 214 let h0_2: i64=g_contains(obuf, n2, "ham=0" as *u8) 215 g_puts(" row2 +brightness -> rank " as *u8); g_num(rk2); g_puts(" ham0? " as *u8); g_num(h0_2) 216 if rk2==1 { if h0_2==1 { pass=pass+1; g_puts(" PASS (brightness-invariant)\n" as *u8) } else { g_puts(" FAIL\n" as *u8) } } else { g_puts(" FAIL\n" as *u8) } 217 218 // row3: near-dup -> /A/up rank 1 (small ham, within threshold) 219 g_run(sites, "alpha" as *u8, "/tmp/q_upnear.gray" as *u8, ws, hs, ths, outp) 220 let n3: i64=g_read_small(outp, obuf, 65536) 221 let rk3: i64=g_rank_of(obuf, n3, "/A/up" as *u8) 222 g_puts(" row3 near-dup -> rank " as *u8); g_num(rk3) 223 if rk3==1 { pass=pass+1; g_puts(" PASS (near-dup found)\n" as *u8) } else { g_puts(" FAIL\n" as *u8) } 224 225 // row4: precision -> only the similar image is within threshold (down at ham 64 excluded) 226 g_run(sites, "alpha" as *u8, "/tmp/q_up.gray" as *u8, ws, hs, ths, outp) 227 let n4: i64=g_read_small(outp, obuf, 65536) 228 let m1_4: i64=g_contains(obuf, n4, "matches=1" as *u8) 229 g_puts(" row4 precision -> matches=1? " as *u8); g_num(m1_4) 230 if m1_4==1 { pass=pass+1; g_puts(" PASS (dissimilar excluded)\n" as *u8) } else { g_puts(" FAIL\n" as *u8) } 231 232 // row5: isolation A + neg-control -> beta-only image on alpha returns matches=0 233 g_run(sites, "alpha" as *u8, "/tmp/q_mid.gray" as *u8, ws, hs, ths, outp) 234 let n5: i64=g_read_small(outp, obuf, 65536) 235 let m0_5: i64=g_contains(obuf, n5, "matches=0" as *u8) 236 g_puts(" row5 isolation-A -> matches=0? " as *u8); g_num(m0_5) 237 if m0_5==1 { pass=pass+1; g_puts(" PASS (alpha blind to beta-only content)\n" as *u8) } else { g_puts(" FAIL\n" as *u8) } 238 239 // row6: isolation B -> up exists in BOTH; querying beta returns /B/up and NEVER an /A/ cid 240 g_run(sites, "beta" as *u8, "/tmp/q_up.gray" as *u8, ws, hs, ths, outp) 241 let n6: i64=g_read_small(outp, obuf, 65536) 242 let rk6: i64=g_rank_of(obuf, n6, "/B/up" as *u8) 243 let leakA: i64=g_contains(obuf, n6, "/A/" as *u8) 244 g_puts(" row6 isolation-B -> /B/up rank " as *u8); g_num(rk6); g_puts(" leak(/A/)? " as *u8); g_num(leakA) 245 if rk6==1 { if leakA==0 { pass=pass+1; g_puts(" PASS (beta returns its own, no alpha leak)\n" as *u8) } else { g_puts(" FAIL (LEAK!)\n" as *u8) } } else { g_puts(" FAIL\n" as *u8) } 246 247 // row7: unknown site -> clean exit 1 + message 248 let rc7: i64=g_run(sites, "ghost" as *u8, "/tmp/q_up.gray" as *u8, ws, hs, ths, outp) 249 let n7: i64=g_read_small(outp, obuf, 65536) 250 let unk7: i64=g_contains(obuf, n7, "unknown site" as *u8) 251 g_puts(" row7 unknown site -> exit " as *u8); g_num(rc7); g_puts(" msg? " as *u8); g_num(unk7) 252 if rc7==1 { if unk7==1 { pass=pass+1; g_puts(" PASS (clean unknown-site fail)\n" as *u8) } else { g_puts(" FAIL\n" as *u8) } } else { g_puts(" FAIL\n" as *u8) } 253 254 g_puts("----\nIMAGE-SEARCH-GATE rows=" as *u8); g_num(rows); g_puts(" pass=" as *u8); g_num(pass); g_puts("\n" as *u8) 255 let lg: i64=sys_openat_append("knowledge/status/image_search_gate.log" as *u8, 0x1a4) 256 if lg>=0 { 257 g_w(lg, "IMAGE-SEARCH-GATE rows=" as *u8); g_wn(lg, rows); g_w(lg, " pass=" as *u8); g_wn(lg, pass) 258 if pass==rows { g_w(lg, " verdict=GREEN\n" as *u8) } else { g_w(lg, " verdict=RED\n" as *u8) } 259 sys_close(lg) 260 } 261 if pass==rows { g_puts("IMAGE-SEARCH-GATE GREEN\n" as *u8); sys_exit(0); return 0 } 262 g_puts("IMAGE-SEARCH-GATE RED\n" as *u8); sys_exit(1); return 1 263}