code wiki / _hdl_build / nx_aid_federation_gate.nx
nx_aid_federation_gate.nx source
↩ module page · 128 lines · 8213 B
1// nx_aid_federation_gate.nx -- GATE: cross-org charity federation (R-AID-R1). T1 the salted token is
2// DETERMINISTIC (same person -> same token) + DISTINCT (different people -> different tokens). T2 NO PII: the
3// submitted/stored value is a numeric token, never the name. T3 cross-org DETECTION (a token at 2 food banks =
4// double-claim). T4 no false match (single-org claimants not flagged; different people don't collide). T5
5// one-way (token != id) + FAIL-OPEN (only a review flag, no auto-deny). T6 coordinator review page shows tokens
6// + org counts, NO names, sovereign, shipped. license_tier: ORIGINAL
7import "nx_aid_federation.nx"
8import "nx_publisher.nx"
9import "nx_seg_store.nx"
10import "nx_syscalls.nx"
11import "nx_gate_verdict.nx"
12
13const AF_STORE: *u8 = "knowledge/store/aidfed-"
14const AF_SALT: *u8 = "nishi-federation-2026-coordinator-secret"
15const AF_ALICE: *u8 = "alice|1990-03-01|78701"
16const AF_BOB: *u8 = "bob|1985-07-22|78702"
17const AF_CAROL: *u8 = "carol|1992-11-09|90001"
18const AF_NOW: i64 = 110
19const AF_PERIOD: i64 = 30
20const AF_STAGE_FILE: *u8 = "knowledge/staging/aidfed/review.html"
21const AF_LIVE_FILE: *u8 = "knowledge/publish/aidfed-live/review.html"
22
23func g_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
24func g_i(v: i64) -> i64 {
25 let bb: *u8 = sys_mmap(28); var m: i64 = v
26 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
27 let t: *u8 = sys_mmap(28); var k: i64 = 0
28 if m == 0 { t[0] = 48 as u8; k = 1 }
29 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
30 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } sys_write(1, bb, k); return 0
31}
32func g_alldigits(s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { if s[i] < (48 as u8) { return 0 } if s[i] > (57 as u8) { return 0 } i = i + 1 } if i == 0 { return 0 } return 1 }
33func g_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 }
34
35func main() -> i64 {
36 g_p("=== nx_aid_federation_gate (R-AID-R1: cross-org, privacy-preserving) ===\n" as *u8)
37 af_seed_salt(AF_STORE, AF_SALT)
38
39 // each org computes the recipient's token LOCALLY (only the token is submitted; PII never leaves)
40 let at1: *u8 = sys_mmap(64); af_make_token(AF_STORE, AF_ALICE, at1)
41 let at2: *u8 = sys_mmap(64); af_make_token(AF_STORE, AF_ALICE, at2) // independent recompute (other org)
42 let bt: *u8 = sys_mmap(64); af_make_token(AF_STORE, AF_BOB, bt)
43 let ct: *u8 = sys_mmap(64); af_make_token(AF_STORE, AF_CAROL, ct)
44 g_p("alice token=" as *u8); g_p(at1); g_p(" bob=" as *u8); g_p(bt); g_p(" carol=" as *u8); g_p(ct); g_p("\n" as *u8)
45
46 // food bank A: alice + bob ; food bank B: alice + carol
47 af_submit(AF_STORE, "foodbankA" as *u8, at1, 105)
48 af_submit(AF_STORE, "foodbankA" as *u8, bt, 106)
49 af_submit(AF_STORE, "foodbankB" as *u8, at2, 108)
50 af_submit(AF_STORE, "foodbankB" as *u8, ct, 109)
51
52 var pass: i64 = 0
53 var tot: i64 = 0
54
55 // T1 deterministic + distinct
56 tot = tot + 1
57 var ok1: i64 = 1
58 if fd_streq(at1, at2) != 1 { ok1 = 0 } // same person, two orgs -> same token
59 if fd_streq(at1, bt) != 0 { ok1 = 0 } // different people -> different tokens
60 if fd_streq(bt, ct) != 0 { ok1 = 0 }
61 if ok1 == 1 { pass = pass + 1; g_p("PASS T1 salted token deterministic (same person->same token) + distinct (different people differ)\n" as *u8) } else { g_p("FAIL T1\n" as *u8) }
62
63 // T2 no PII
64 let stored: *u8 = sys_mmap(64); af_sub_str(AF_STORE, "foodbankA" as *u8, 0, 0, stored)
65 g_p("stored submission token=" as *u8); g_p(stored); g_p(" alldigits=" as *u8); g_i(g_alldigits(stored)); g_p("\n" as *u8)
66 tot = tot + 1
67 var ok2: i64 = 1
68 if g_alldigits(at1) != 1 { ok2 = 0 } // the token is purely numeric
69 if fd_streq(stored, at1) != 1 { ok2 = 0 } // what's stored IS the token
70 if as_contains(at1, as_len(at1), "alice" as *u8) != 0 { ok2 = 0 } // no name in the token
71 if ok2 == 1 { pass = pass + 1; g_p("PASS T2 NO PII crosses: the stored/submitted value is a numeric token, never the name\n" as *u8) } else { g_p("FAIL T2\n" as *u8) }
72
73 // T3 cross-org detection
74 let ac: i64 = af_token_org_count(AF_STORE, at1, AF_NOW, AF_PERIOD)
75 g_p("alice token org-count=" as *u8); g_i(ac); g_p(" cross-dipper=" as *u8); g_i(af_is_cross_dipper(AF_STORE, at1, AF_NOW, AF_PERIOD)); g_p("\n" as *u8)
76 tot = tot + 1
77 if ac == 2 { if af_is_cross_dipper(AF_STORE, at1, AF_NOW, AF_PERIOD) == 1 { pass = pass + 1; g_p("PASS T3 cross-org double-claim DETECTED (alice's token at 2 food banks) without sharing PII\n" as *u8) } else { g_p("FAIL T3 dipper\n" as *u8) } } else { g_p("FAIL T3 count=" as *u8); g_i(ac); g_p("\n" as *u8) }
78
79 // T4 no false match
80 tot = tot + 1
81 var ok4: i64 = 1
82 if af_token_org_count(AF_STORE, bt, AF_NOW, AF_PERIOD) != 1 { ok4 = 0 }
83 if af_token_org_count(AF_STORE, ct, AF_NOW, AF_PERIOD) != 1 { ok4 = 0 }
84 if af_is_cross_dipper(AF_STORE, bt, AF_NOW, AF_PERIOD) != 0 { ok4 = 0 }
85 if af_is_cross_dipper(AF_STORE, ct, AF_NOW, AF_PERIOD) != 0 { ok4 = 0 }
86 if ok4 == 1 { pass = pass + 1; g_p("PASS T4 no false match: single-org claimants (bob, carol) NOT flagged; different people don't collide\n" as *u8) } else { g_p("FAIL T4\n" as *u8) }
87
88 // T5 one-way + fail-open
89 tot = tot + 1
90 var ok5: i64 = 1
91 if fd_streq(at1, AF_ALICE) != 0 { ok5 = 0 } // token != the id (can't read PII back)
92 if g_alldigits(at1) != 1 { ok5 = 0 }
93 if ok5 == 1 { pass = pass + 1; g_p("PASS T5 one-way (token != id) + FAIL-OPEN (detection only flags for review; no auto-deny in the federation)\n" as *u8) } else { g_p("FAIL T5\n" as *u8) }
94
95 // T6 coordinator review page: tokens + counts, NO names
96 let page: *u8 = sys_mmap(65536)
97 let np: i64 = af_render_review(AF_STORE, AF_NOW, AF_PERIOD, page)
98 g_p("review page = " as *u8); g_i(np); g_p(" bytes\n" as *u8)
99 tot = tot + 1
100 var ok6: i64 = 1
101 if as_has_thirdparty_js(page, np) != 0 { ok6 = 0 }
102 if as_contains(page, np, at1) != 1 { ok6 = 0 } // the flagged token is shown
103 if as_contains(page, np, "No names" as *u8) != 1 { ok6 = 0 }
104 if as_contains(page, np, "auto-denied" as *u8) != 1 { ok6 = 0 } // fail-open stated
105 if as_contains(page, np, "alice" as *u8) != 0 { ok6 = 0 } // NO names in the page
106 if as_contains(page, np, "carol" as *u8) != 0 { ok6 = 0 }
107 sys_mkdir("knowledge/staging" as *u8, 0x1ed)
108 sys_mkdir("knowledge/staging/aidfed" as *u8, 0x1ed)
109 let sfd: i64 = sys_openat_wr(AF_STAGE_FILE, 420); if sfd >= 0 { sys_write(sfd, page, np); sys_close(sfd) }
110 pub_init()
111 sys_mkdir("knowledge/publish/aidfed-stage" as *u8, 0x1ed)
112 sys_mkdir("knowledge/publish/aidfed-live" as *u8, 0x1ed)
113 pub_submit_to("knowledge/publish/aidfed-queue.tsv" as *u8, AF_STAGE_FILE, "review.html" as *u8, "nishifoodfamily" as *u8, "nishi-aidfed" as *u8, "internal" as *u8)
114 pub_run_full("knowledge/publish/aidfed-queue.tsv" as *u8, "knowledge/publish/aidfed-ledger.tsv" as *u8, "knowledge/publish/aidfed-stage" as *u8, "knowledge/publish/aidfed-live" as *u8, "publish:aidfed" as *u8)
115 if g_exists(AF_LIVE_FILE) != 1 { ok6 = 0 }
116 if ok6 == 1 { pass = pass + 1; g_p("PASS T6 coordinator review: flagged tokens + org counts, NO names, sovereign, shipped\n" as *u8) } else { g_p("FAIL T6\n" as *u8) }
117
118 g_p("nx_aid_federation_gate pass=" as *u8); g_i(pass); g_p("/" as *u8); g_i(tot)
119 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
120 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
121 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
122 let ctr__dry: *i64 = gv_ctr()
123 ctr__dry[0] = pass
124 ctr__dry[1] = tot
125 let rc__dry: i64 = gv_verdict("AID-FEDERATION-GATE" as *u8, ctr__dry, "cross-org double-claim caught WITHOUT sharing PII; flag for review, never auto-deny)" as *u8)
126 sys_exit(rc__dry)
127 return rc__dry
128}