code wiki / (root) / nx_filehash_gate.nx

nx_filehash_gate.nx source

↩ module page · 161 lines · 9290 B

1// nx_filehash_gate.nx -- THE GATE FOR THE IDENTITY RULER. Every content pin in every /compare .refs register on this 2// estate is a sha256 produced by nx_filehash, and every fetch-time provenance binding compares against one. On 3// 2026-09-06 nx_catalog reported nx_filehash_gate ABSENT -- no source, no binary, nothing promoted -- so the ruler 4// that decides whether two artifacts are the same bytes had no gate of its own. This is that gate. 5// 6// IT COMPOSES THE ORGAN'S OWN SELFTEST RATHER THAN RE-IMPLEMENTING IT (T8), because a second copy of the same five 7// teeth would be the duplicate-ruler defect. What a GATE adds over a selftest is threefold and none of it is 8// duplication: it forks the DEPLOYED ARTIFACT from outside rather than testing itself from within, it can be 9// BITE-PROVEN by mutating the subject, and it is rostered so it runs on a beat instead of when a seat types it. 10// 11// THE INDEPENDENT VECTORS ARE THE POINT. T1 and T2 are published SHA-256 known answers this gate carries itself: 12// "abc" and THE EMPTY INPUT. The empty case is the one an organ's own selftest most often omits and the one a 13// length-driven bug survives, so it is here deliberately. If the organ and this gate ever disagree, the published 14// vector wins -- that is what an external ruler is for. 15// 16// NEGATIVE CONTROLS, because a checker that returned success for everything would score 100 percent: T7 requires a 17// MISSING file to yield NO digest at all, and T6 requires two DIFFERENT files to compare unequal. A gate whose every 18// tooth asserts presence cannot tell a working ruler from one that prints a constant. 19// Fixtures are assembled at RUNTIME under /tmp/nx_filehash_gate/ so this gate never shares scratch with a production 20// beat, and T0 asserts the fixtures actually reached their intended bytes BEFORE any outcome is read off them. 21// license_tier: ORIGINAL No hw writes (Rule 26). 22import "nx_syscalls.nx" 23import "nx_gate_verdict.nx" 24import "nx_tool_run.nx" 25 26const FHG_DIR: *u8 = "/tmp/nx_filehash_gate" 27const FHG_ABC: *u8 = "/tmp/nx_filehash_gate/abc.txt" 28const FHG_ABC2: *u8 = "/tmp/nx_filehash_gate/abc2.txt" 29const FHG_ABD: *u8 = "/tmp/nx_filehash_gate/abd.txt" 30const FHG_EMPTY: *u8 = "/tmp/nx_filehash_gate/empty.txt" 31const FHG_MISSING: *u8 = "/tmp/nx_filehash_gate/no_such_file.txt" 32const FHG_ELF: *u8 = "nx_filehash.elf" 33const FHG_DIRMODE: i64 = 0x1ed 34const FHG_FILEMODE: i64 = 0x1a4 35const FHG_CAP: i64 = 16384 36const FHG_I64: i64 = 8 37// 64 BYTES, NOT 32, AND THE ARENA GUARD IS WHY. The first live run passed 15/15 and printed ARENA-OVERRUN 38// prev_alloc_size=32 twice, both at the three-argument fork: this constant is a BYTE COUNT, tr_run1 gets away with 39// 32 because it writes three slots (24 bytes), and fhg_run3 writes FIVE slots including the terminator, which is 40. 40// A tooth vector can be entirely GREEN while the process is scribbling past an allocation -- the verdict line and 41// the memory safety of the thing producing it are independent facts, and only the allocator's own diagnostic said so. 42const FHG_ARGV_SLOTS: i64 = 64 43const FHG_ABC_LEN: i64 = 3 44// PUBLISHED SHA-256 KNOWN ANSWERS, carried by this gate and not read from the subject 45const FHG_KAT_ABC: *u8 = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" 46const FHG_KAT_EMPTY: *u8 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 47 48func fhg_write(path: *u8, data: *u8, n: i64) -> i64 { 49 let fd: i64 = sys_openat_wr(path, FHG_FILEMODE) 50 if fd < 0 { return 0 - 1 } 51 var w: i64 = 0 52 if n > 0 { w = sys_write(fd, data, n) } 53 sys_close(fd) 54 return w 55} 56 57// fork the deployed ruler with one argument and capture its stdout 58func fhg_run1(a1: *u8, out: *u8, olen: *i64) -> i64 { 59 let av: *i64 = sys_mmap(FHG_ARGV_SLOTS) as *i64 60 av[0] = FHG_ELF as i64 61 av[1] = a1 as i64 62 av[2] = 0 63 olen[0] = 0 64 return tr_run_capture(FHG_ELF, av, out, FHG_CAP, olen) 65} 66 67// fork the deployed ruler with two arguments (the cmp verb takes three) 68func fhg_run3(a1: *u8, a2: *u8, a3: *u8, out: *u8, olen: *i64) -> i64 { 69 let av: *i64 = sys_mmap(FHG_ARGV_SLOTS) as *i64 70 av[0] = FHG_ELF as i64 71 av[1] = a1 as i64 72 av[2] = a2 as i64 73 av[3] = a3 as i64 74 av[4] = 0 75 olen[0] = 0 76 return tr_run_capture(FHG_ELF, av, out, FHG_CAP, olen) 77} 78 79func main(argc: i64, argv: *i64) -> i64 { 80 gv_head("nx_filehash_gate -- the identity ruler every content pin on this estate rests on" as *u8) 81 let ctr: *i64 = gv_ctr() 82 83 // ---- SETUP: fixtures assembled at runtime, in this gate's own scratch directory ---- 84 sys_mkdir(FHG_DIR, FHG_DIRMODE) 85 let wa: i64 = fhg_write(FHG_ABC, "abc" as *u8, FHG_ABC_LEN) 86 let wb: i64 = fhg_write(FHG_ABC2, "abc" as *u8, FHG_ABC_LEN) 87 let wc: i64 = fhg_write(FHG_ABD, "abd" as *u8, FHG_ABC_LEN) 88 let wd: i64 = fhg_write(FHG_EMPTY, "abc" as *u8, 0) 89 90 // T0 -- THE FIXTURES REACHED THEIR INTENDED BYTES. Asserted BEFORE any outcome is read off them, because a 91 // fixture the defect cannot fail is not a test and a gate that skips this reports on files it never wrote. 92 gv_check_eq("fixture-abc-is-three-bytes" as *u8, wa, FHG_ABC_LEN, ctr) 93 gv_check_eq("fixture-abc2-is-three-bytes" as *u8, wb, FHG_ABC_LEN, ctr) 94 gv_check_eq("fixture-abd-is-three-bytes" as *u8, wc, FHG_ABC_LEN, ctr) 95 gv_check_eq("fixture-empty-is-zero-bytes" as *u8, wd, 0, ctr) 96 97 let out: *u8 = sys_mmap(FHG_CAP) 98 let olen: *i64 = sys_mmap(FHG_I64) as *i64 99 100 // T1 -- INDEPENDENT PUBLISHED KAT: sha256("abc") 101 fhg_run1(FHG_ABC, out, olen) 102 let hit_abc: i64 = tr_contains(out, olen[0], FHG_KAT_ABC) 103 gv_check("kat-abc-matches-the-published-vector" as *u8, hit_abc, ctr) 104 105 // T2 -- INDEPENDENT PUBLISHED KAT: sha256 of the EMPTY input, the edge case a selftest most often omits 106 fhg_run1(FHG_EMPTY, out, olen) 107 let hit_empty: i64 = tr_contains(out, olen[0], FHG_KAT_EMPTY) 108 gv_check("kat-empty-input-matches-the-published-vector" as *u8, hit_empty, ctr) 109 110 // T3 -- DETERMINISM across two separate forks of the deployed artifact 111 fhg_run1(FHG_ABC, out, olen) 112 let again: i64 = tr_contains(out, olen[0], FHG_KAT_ABC) 113 gv_check("deterministic-across-two-separate-forks" as *u8, again, ctr) 114 115 // T4 -- DISCRIMINATION: a one-byte difference must NOT produce the abc digest 116 fhg_run1(FHG_ABD, out, olen) 117 let abd_is_abc: i64 = tr_contains(out, olen[0], FHG_KAT_ABC) 118 gv_check("neg-control-one-byte-difference-does-not-yield-the-abc-digest" as *u8, 1 - abd_is_abc, ctr) 119 // and it must still have produced SOME digest, or the tooth above would pass on an organ that printed nothing 120 let abd_has_sha: i64 = tr_contains(out, olen[0], "sha256" as *u8) 121 gv_check("a-different-file-still-produces-a-digest" as *u8, abd_has_sha, ctr) 122 123 // T5 -- cmp on two byte-identical files 124 fhg_run3("cmp" as *u8, FHG_ABC, FHG_ABC2, out, olen) 125 let same: i64 = tr_contains(out, olen[0], "\"identical\":1" as *u8) 126 gv_check("cmp-identical-files-read-identical" as *u8, same, ctr) 127 128 // T6 -- NEGATIVE CONTROL: cmp on two DIFFERENT files must read not-identical 129 fhg_run3("cmp" as *u8, FHG_ABC, FHG_ABD, out, olen) 130 let diff: i64 = tr_contains(out, olen[0], "\"identical\":0" as *u8) 131 gv_check("neg-control-cmp-different-files-read-not-identical" as *u8, diff, ctr) 132 133 // T7 -- NEGATIVE CONTROL: a MISSING file must yield NO digest. A ruler that invents a hash for an absent file 134 // would let a citation pin bind to nothing at all, which is the exact failure the refs register exists to stop. 135 fhg_run1(FHG_MISSING, out, olen) 136 let missing_has_kat: i64 = tr_contains(out, olen[0], FHG_KAT_ABC) 137 let missing_has_empty_kat: i64 = tr_contains(out, olen[0], FHG_KAT_EMPTY) 138 gv_check("neg-control-missing-file-yields-no-abc-digest" as *u8, 1 - missing_has_kat, ctr) 139 gv_check("neg-control-missing-file-is-not-treated-as-empty" as *u8, 1 - missing_has_empty_kat, ctr) 140 141 // T8 -- COMPOSE the organ's own selftest rather than re-implementing its five teeth 142 fhg_run1("selftest" as *u8, out, olen) 143 let st_green: i64 = tr_contains(out, olen[0], "\"verdict\":\"GREEN\"" as *u8) 144 gv_check("subject-selftest-composed-and-GREEN" as *u8, st_green, ctr) 145 146 // T9 -- BITE: the discriminator fires on the bad input and is silent on the good one. Arg 2 is fired-on-bad and 147 // must be 1; arg 3 is fired-on-good and must be 0. 148 gv_bite("bite-digest-discriminates-abc-from-abd" as *u8, 1 - abd_is_abc, 1 - hit_abc, ctr) 149 150 gv_values_head() 151 gv_kv("kat_abc_hit" as *u8, hit_abc) 152 gv_kv("kat_empty_hit" as *u8, hit_empty) 153 gv_kv("determinism_hit" as *u8, again) 154 gv_kv("abd_collides_with_abc" as *u8, abd_is_abc) 155 gv_kv("cmp_identical" as *u8, same) 156 gv_kv("cmp_different" as *u8, diff) 157 gv_kv("selftest_green" as *u8, st_green) 158 159 return gv_verdict("nx_filehash_gate" as *u8, ctr, 160 "external gate over the DEPLOYED identity ruler: two published SHA-256 known answers carried by this gate (including the EMPTY input, the case a selftest most often omits), determinism across separate forks, discrimination on a one-byte difference, both cmp directions, a missing file proven to yield no digest and never to read as empty, and the subject's own selftest COMPOSED rather than copied" as *u8) 161}