code wiki / (root) / nx_connect_e2e_client_gate.nx

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}