nx_connect_e2e_client_gate.nx source
↩ module page · 94 lines · 5893 B
1// nx_connect_e2e_client_gate.nx -- proves the emitted FULL-E2E client: BOTH sovereign wasms ship, keys
2// are AGREED (X25519) not typed, keygen + publish is public-half-only, only ciphertext is POSTed, and the
3// recipient DECRYPT view exists and renders via textContent (XSS-safe by construction). Structural proof
4// on the emitted bytes; crypto CORRECTNESS is separately proven on the same artifacts by
5// nx_media_crypt_wasm_gate 3/3 (RFC 8439) and nx_connect_keyx_vm_gate 5/5 (RFC 7748 6.1 DH agreement).
6// license_tier: ORIGINAL expect_exit: 0
7import "nx_syscalls.nx"
8import "nx_connect_e2e_client.nx"
9
10func w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
11func slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
12func has(h: *u8, hn: i64, nd: *u8) -> i64 {
13 let nl: i64=slen(nd); if nl==0 { return 0 }
14 var i: i64=0
15 while i+nl<=hn { var k: i64=0; var hit: i64=1; while k<nl { if h[i+k]!=nd[k] { hit=0; k=nl } else { k=k+1 } } if hit==1 { return 1 } i=i+1 }
16 return 0
17}
18func ck(pass: i64, label: *u8, fails: *i64) -> i64 {
19 w(" " as *u8); w(label); w(": " as *u8)
20 if pass==1 { w("PASS\n" as *u8) } else { w("FAIL\n" as *u8); fails[0]=fails[0]+1 }
21 return 0
22}
23
24func main() -> i64 {
25 let fails: *i64 = sys_mmap(16) as *i64
26 fails[0]=0
27 w("=== nx_connect_e2e_client_gate -- FULL-E2E client: agreed keys + sealed send + decrypting inbox ===\n" as *u8)
28 let dst: *u8 = sys_mmap(262144)
29 let n: i64 = ce_emit_html("Q0hBQ0hBUExDSA" as *u8, 14, "WDI1NTE5UExDSA" as *u8, 14, dst) // placeholder b64s
30
31 // T1: ships BOTH sovereign wasms (cipher + key agreement) with the standard loader
32 var t1: i64=1
33 if has(dst, n, "const BC='Q0hBQ0hBUExDSA'" as *u8)==0 { t1=0 }
34 if has(dst, n, "const BX='WDI1NTE5UExDSA'" as *u8)==0 { t1=0 }
35 if has(dst, n, "WebAssembly.instantiate(ub(BC))" as *u8)==0 { t1=0 }
36 if has(dst, n, "WebAssembly.instantiate(ub(BX))" as *u8)==0 { t1=0 }
37 ck(t1, "T1 embeds BOTH sovereign wasms (ChaCha20 + X25519) with standard instantiate loaders" as *u8, fails)
38
39 // T2: keys are AGREED via the exported X25519 scalarmult -- and no key <input> exists any more
40 var t2:i64=1
41 if has(dst, n, "exX.nx_x25519_scalarmult(" as *u8)==0 { t2=0 }
42 if has(dst, n, "sharedKey(" as *u8)==0 { t2=0 }
43 if has(dst, n, "Conversation key (hex" as *u8)==1 { t2=0 } // the typed-key era must be GONE
44 ck(t2, "T2 conversation key is X25519-AGREED (exported scalarmult); the typed-key input is gone" as *u8, fails)
45
46 // T3: keygen publishes ONLY the public half; the private key never appears in any fetch body
47 var t3:i64=1
48 if has(dst, n, "crypto.getRandomValues" as *u8)==0 { t3=0 }
49 if has(dst, n, "localStorage" as *u8)==0 { t3=0 }
50 if has(dst, n, "body:'n='+n+'&p='+pub" as *u8)==0 { t3=0 } // publishes name + PUBLIC key
51 if has(dst, n, "'&p='+priv" as *u8)==1 { t3=0 }
52 if has(dst, n, "body:'n='+n+'&p='+hx(myPriv" as *u8)==1 { t3=0 }
53 ck(t3, "T3 keygen: private half stays in localStorage; only the PUBLIC key is published" as *u8, fails)
54
55 // T4: sealed send -- the POST body carries from/to/seq + ciphertext hex; never the plaintext element
56 var t4:i64=1
57 if has(dst, n, "body:'from='+n+'&to='+to+'&seq='+seq+'&ct='+ct" as *u8)==0 { t4=0 }
58 if has(dst, n, "getElementById('m').value" as *u8)==0 { t4=0 }
59 if has(dst, n, "body:document.getElementById('m')" as *u8)==1 { t4=0 }
60 if has(dst, n, "'&msg='" as *u8)==1 { t4=0 }
61 ck(t4, "T4 ESCAPE holds: POST carries from/to/seq/ciphertext only; plaintext never leaves the browser" as *u8, fails)
62
63 // T5: the recipient DECRYPT view exists: fetches the routed inbox, re-derives, renders via textContent
64 var t5:i64=1
65 if has(dst, n, "fetch('/connect/sealed?u='+n)" as *u8)==0 { t5=0 }
66 if has(dst, n, "sharedKey(priv,m.p)" as *u8)==0 { t5=0 }
67 if has(dst, n, "ccrypt(key,m.s,uh(m.ct))" as *u8)==0 { t5=0 }
68 if has(dst, n, "tx.textContent=new TextDecoder().decode(pt)" as *u8)==0 { t5=0 }
69 if has(dst, n, "innerHTML" as *u8)==1 { t5=0 } // decrypted text must never become markup
70 ck(t5, "T5 decrypt view: routed inbox fetched, key re-derived, plaintext rendered via textContent (never innerHTML)" as *u8, fails)
71
72 // T6: crypto lives in WASM, not JS -- no cipher or curve arithmetic reimplemented in the last mile
73 var t6:i64=1
74 if has(dst, n, "quarterround" as *u8)==1 { t6=0 }
75 if has(dst, n, "0x61707865" as *u8)==1 { t6=0 }
76 if has(dst, n, "function chacha" as *u8)==1 { t6=0 }
77 if has(dst, n, "19687" as *u8)==1 { t6=0 }
78 if has(dst, n, "121665" as *u8)==1 { t6=0 }
79 ck(t6, "T6 no crypto reimplemented in JS (cipher + curve are the sovereign wasms; JS only marshals)" as *u8, fails)
80
81 // T7: honesty stays on the page -- the TOFU gap is STATED, not hidden
82 var t7:i64=1
83 if has(dst, n, "TOFU gap" as *u8)==0 { t7=0 }
84 if has(dst, n, "<main id=\"main\">" as *u8)==0 { t7=0 } // a11y landmark (the owed seq780 fix)
85 ck(t7, "T7 honest framing on-page (TOFU gap stated) + main landmark present" as *u8, fails)
86
87 w(" emitted bytes=" as *u8)
88 let nb: *u8=sys_mmap(28); var m: i64=n; var kk: i64=0; if m==0{nb[0]=48 as u8;kk=1} while m>0{nb[kk]=(48+(m%10)) as u8;m=m/10;kk=kk+1} let bb: *u8=sys_mmap(28); var j: i64=0; while j<kk{bb[j]=nb[kk-1-j];j=j+1} sys_write(1,bb,kk)
89 w("\n fails=" as *u8); m=fails[0]; kk=0; let t2b: *u8=sys_mmap(28); if m==0{t2b[0]=48 as u8;kk=1} while m>0{t2b[kk]=(48+(m%10)) as u8;m=m/10;kk=kk+1} let b2: *u8=sys_mmap(28); j=0; while j<kk{b2[j]=t2b[kk-1-j];j=j+1} sys_write(1,b2,kk); w("\n" as *u8)
90 if fails[0]==0 { w("VERDICT: verdict=GREEN (full-E2E client: agreed keys, ciphertext-only wire, client-side decrypt view)\n" as *u8); sys_exit(0) }
91 w("VERDICT: verdict=RED\n" as *u8)
92 sys_exit(1)
93 return 1
94}