code wiki / _hdl_build / nx_tor_ntor_gate.nx
nx_tor_ntor_gate.nx source
↩ module page · 128 lines · 10739 B
1// nx_tor_ntor_gate.nx -- GATE for the sovereign Tor ntor handshake (tor-spec §5.1.4).
2// WHAT THIS PROVES (and what it does NOT):
3// PART A PRIMITIVE KATs, byte-exact vs on-disk RFC vectors (spot-checks copied verbatim from
4// nx_x25519_test.nx's own verified assertions): x25519 RFC 7748 §5.2 + §6.1 base-point; and
5// hmac_sha256 RFC 4231 TC1 (first 8 bytes confirmed by nx_hmac.nx). These anchor ntor's DH + MAC.
6// PART B ntor COMPOSITION correctness: client init derives X == RFC 7748 §6.1 Alice pubkey (pubkey
7// derivation anchored); a full two-sided handshake AGREES (client AUTH verifies + client and
8// server derive identical 92-byte circuit keys); deterministic across reruns.
9// PART C fail-closed negatives: tampered Y / AUTH / onion-key B / ID each make the client REJECT.
10// HONEST BOUNDARY (printed below, not hidden): two-sided agreement proves the ntor CONSTRUCTION (tweaks,
11// concat order, KDF wiring) but a mirrored x25519 bug would agree on both sides -- so it is NOT proof of
12// byte-exact interop with the live Tor network. That needs (1) Tor's own published ntor vector (absent
13// in-tree; zero external calls this run) and (2) the x25519 base-point scalar-pattern fix documented in
14// nx_x25519_test.nx. anon_is_anonymizing() stays 0 until a full circuit works. license_tier: ORIGINAL expect_exit: 0
15import "nx_syscalls.nx"
16import "nx_x25519.nx" // x25519(scalar,u,out) raw -- for the RFC 7748 KATs
17import "nx_x25519_ephemeral.nx" // x25519_base_point
18import "nx_hmac.nx" // hmac_sha256 -- for the RFC 4231 KAT
19import "nx_tor_ntor.nx" // the handshake under test
20
21func g_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
22func g_n(v: i64) -> i64 { var m: i64=v; if m<0{g_w("-" as *u8);m=0-m} let t:*u8=sys_mmap(24); 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} let o:*u8=sys_mmap(24); var i:i64=0; while i<k{o[i]=t[k-1-i];i=i+1} sys_write(1,o,k); return 0 }
23func g_fw(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 }
24func g_fn(fd: i64, v: i64) -> i64 { var m: i64=v; let t:*u8=sys_mmap(24); 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} let o:*u8=sys_mmap(24); var i:i64=0; while i<k{o[i]=t[k-1-i];i=i+1} sys_write(fd,o,k); return 0 }
25func g_row(id: *u8, ok: i64, pass: *i64, tot: *i64) -> i64 { tot[0]=tot[0]+1; g_w(" " as *u8); g_w(id); if ok==1 { g_w(": OK\n" as *u8); pass[0]=pass[0]+1 } else { g_w(": FAIL\n" as *u8) } return 0 }
26func g_eq(a: *u8, b: *u8, n: i64) -> i64 { var i: i64=0; while i<n { if a[i]!=b[i] { return 0 } i=i+1 } return 1 }
27
28func main() -> i64 {
29 let pass: *i64 = sys_mmap(8) as *i64; pass[0]=0
30 let tot: *i64 = sys_mmap(8) as *i64; tot[0]=0
31 g_w("=== NX-TOR-NTOR GATE (tor-spec 5.1.4 ntor/CREATE2: RFC primitive KATs + two-sided handshake + negatives) ===\n" as *u8)
32 g_w("-- PART A: primitive KATs (byte-exact vs on-disk RFC vectors) --\n" as *u8)
33
34 // A1: x25519 RFC 7748 5.2 test-1 (assertions copied verbatim from nx_x25519_test.nx)
35 let k: *u8 = sys_mmap(64)
36 k[0]=0xa5;k[1]=0x46;k[2]=0xe3;k[3]=0x6b;k[4]=0xf0;k[5]=0x52;k[6]=0x7c;k[7]=0x9d;k[8]=0x3b;k[9]=0x16;k[10]=0x15;k[11]=0x4b;k[12]=0x82;k[13]=0x46;k[14]=0x5e;k[15]=0xdd;k[16]=0x62;k[17]=0x14;k[18]=0x4c;k[19]=0x0a;k[20]=0xc1;k[21]=0xfc;k[22]=0x5a;k[23]=0x18;k[24]=0x50;k[25]=0x6a;k[26]=0x22;k[27]=0x44;k[28]=0xba;k[29]=0x44;k[30]=0x9a;k[31]=0xc4
37 let u: *u8 = sys_mmap(64)
38 u[0]=0xe6;u[1]=0xdb;u[2]=0x68;u[3]=0x67;u[4]=0x58;u[5]=0x30;u[6]=0x30;u[7]=0xdb;u[8]=0x35;u[9]=0x94;u[10]=0xc1;u[11]=0xa4;u[12]=0x24;u[13]=0xb1;u[14]=0x5f;u[15]=0x7c;u[16]=0x72;u[17]=0x66;u[18]=0x24;u[19]=0xec;u[20]=0x26;u[21]=0xb3;u[22]=0x35;u[23]=0x3b;u[24]=0x10;u[25]=0xa9;u[26]=0x03;u[27]=0xa6;u[28]=0xd0;u[29]=0xab;u[30]=0x1c;u[31]=0x4c
39 let ko: *u8 = sys_mmap(64)
40 x25519(k, u, ko)
41 var a1: i64 = 1
42 if (ko[0]&0xff)!=0xc3 { a1=0 }
43 if (ko[1]&0xff)!=0xda { a1=0 }
44 if (ko[7]&0xff)!=0x90 { a1=0 }
45 if (ko[15]&0xff)!=0x4f { a1=0 }
46 if (ko[23]&0xff)!=0xf7 { a1=0 }
47 if (ko[31]&0xff)!=0x52 { a1=0 }
48 g_row("A1 x25519 RFC 7748 5.2 KAT (DH primitive) == c3da..52" as *u8, a1, pass, tot)
49
50 // A2: x25519 RFC 7748 6.1 base-point: X25519(Alice_priv, 9) == Alice_pub 8520..6a
51 let ap: *u8 = sys_mmap(64)
52 ap[0]=0x77;ap[1]=0x07;ap[2]=0x6d;ap[3]=0x0a;ap[4]=0x73;ap[5]=0x18;ap[6]=0xa5;ap[7]=0x7d;ap[8]=0x3c;ap[9]=0x16;ap[10]=0xc1;ap[11]=0x72;ap[12]=0x51;ap[13]=0xb2;ap[14]=0x66;ap[15]=0x45;ap[16]=0xdf;ap[17]=0x4c;ap[18]=0x2f;ap[19]=0x87;ap[20]=0xeb;ap[21]=0xc0;ap[22]=0x99;ap[23]=0x2a;ap[24]=0xb1;ap[25]=0x77;ap[26]=0xfb;ap[27]=0xa5;ap[28]=0x1d;ap[29]=0xb9;ap[30]=0x2c;ap[31]=0x2a
53 let bp: *u8 = sys_mmap(64); x25519_base_point(bp)
54 let apub: *u8 = sys_mmap(64); x25519(ap, bp, apub)
55 var a2: i64 = 1
56 if (apub[0]&0xff)!=0x85 { a2=0 }
57 if (apub[31]&0xff)!=0x6a { a2=0 }
58 g_row("A2 x25519 RFC 7748 6.1 base-point KAT (pubkey derivation) == 8520..6a" as *u8, a2, pass, tot)
59
60 // A3: hmac_sha256 RFC 4231 TC1: key=0x0b*20, msg="Hi There" -> b0344c61d8db3853.. (8 bytes on disk in nx_hmac.nx)
61 let hk: *u8 = sys_mmap(20); var hi: i64=0; while hi<20 { hk[hi]=0x0b as u8; hi=hi+1 }
62 let ht: *u8 = sys_mmap(32); hmac_sha256(hk, 20, "Hi There" as *u8, 8, ht)
63 let he: *u8 = sys_mmap(8); he[0]=0xb0;he[1]=0x34;he[2]=0x4c;he[3]=0x61;he[4]=0xd8;he[5]=0xdb;he[6]=0x38;he[7]=0x53
64 var a3: i64 = 0; if g_eq(ht, he, 8)==1 { a3=1 }
65 g_row("A3 hmac_sha256 RFC 4231 TC1 KAT (MAC/KDF primitive) == b0344c61d8db3853" as *u8, a3, pass, tot)
66
67 g_w("-- PART B: ntor composition (two-sided handshake, fixed keys) --\n" as *u8)
68 // fixed deterministic inputs
69 let id: *u8 = sys_mmap(20); var ii: i64=0; while ii<20 { id[ii]=ii as u8; ii=ii+1 } // ID = 00..13
70 let bpriv: *u8 = sys_mmap(32) // server onion secret = RFC 7748 6.1 Bob priv (recognizable fixed scalar)
71 bpriv[0]=0x5d;bpriv[1]=0xab;bpriv[2]=0x08;bpriv[3]=0x7e;bpriv[4]=0x62;bpriv[5]=0x4a;bpriv[6]=0x8a;bpriv[7]=0x4b;bpriv[8]=0x79;bpriv[9]=0xe1;bpriv[10]=0x7f;bpriv[11]=0x8b;bpriv[12]=0x83;bpriv[13]=0x80;bpriv[14]=0x0e;bpriv[15]=0xe6;bpriv[16]=0x6f;bpriv[17]=0x3b;bpriv[18]=0xb1;bpriv[19]=0x29;bpriv[20]=0x26;bpriv[21]=0x18;bpriv[22]=0xb6;bpriv[23]=0xfd;bpriv[24]=0x1c;bpriv[25]=0x2f;bpriv[26]=0x8b;bpriv[27]=0x27;bpriv[28]=0xff;bpriv[29]=0x88;bpriv[30]=0xe0;bpriv[31]=0xeb
72 let bpub: *u8 = sys_mmap(32); x25519_keypair_public(bpriv, bpub) // B = b*G (server onion pubkey)
73 let xpriv: *u8 = sys_mmap(32); var xi: i64=0; while xi<32 { xpriv[xi]=ap[xi]; xi=xi+1 } // client eph = Alice priv (base-point good)
74 let ypriv: *u8 = sys_mmap(32); var yi: i64=0; while yi<32 { ypriv[yi]=(0x40+yi) as u8; yi=yi+1 } // server eph = fixed 40..5f
75
76 let xpub: *u8 = sys_mmap(32); let skin: *u8 = sys_mmap(128)
77 ntor_client_init(id, bpub, xpriv, xpub, skin)
78 // B1: X derived by ntor == RFC 7748 6.1 Alice pubkey (8520..6a)
79 var b1: i64 = 1; if (xpub[0]&0xff)!=0x85 { b1=0 } if (xpub[31]&0xff)!=0x6a { b1=0 }
80 g_row("B1 ntor_client_init X == RFC 7748 Alice pubkey (pubkey derivation anchored)" as *u8, b1, pass, tot)
81
82 // server responds
83 let ypub: *u8 = sys_mmap(32); let auth_s: *u8 = sys_mmap(32); let keys_s: *u8 = sys_mmap(96)
84 let sr: i64 = ntor_server_respond(id, bpub, bpriv, xpub, ypriv, ypub, auth_s, keys_s)
85 // client finishes
86 let ks_c: *u8 = sys_mmap(32); let keys_c: *u8 = sys_mmap(96)
87 let cr: i64 = ntor_client_finish(id, bpub, xpriv, xpub, ypub, auth_s, ks_c, keys_c)
88 var b2: i64 = 0; if sr==0 { if cr==0 { b2=1 } }
89 g_row("B2 two-sided handshake: server responds + client AUTH verifies (returns OK)" as *u8, b2, pass, tot)
90 var b3: i64 = 0; if g_eq(keys_c, keys_s, 92)==1 { b3=1 }
91 g_row("B3 client + server derive IDENTICAL 92-byte circuit keys (Df|Db|Kf|Kb|KH)" as *u8, b3, pass, tot)
92
93 // B4 determinism: rerun the whole handshake -> identical keys
94 let ypub2: *u8 = sys_mmap(32); let auth2: *u8 = sys_mmap(32); let keys_s2: *u8 = sys_mmap(96)
95 ntor_server_respond(id, bpub, bpriv, xpub, ypriv, ypub2, auth2, keys_s2)
96 var b4: i64 = 0; if g_eq(keys_s2, keys_s, 92)==1 { if g_eq(auth2, auth_s, 32)==1 { b4=1 } }
97 g_row("B4 determinism: identical fixed inputs -> identical keys + AUTH across runs" as *u8, b4, pass, tot)
98
99 g_w("-- PART C: fail-closed negatives (client MUST reject) --\n" as *u8)
100 // C1 tampered Y
101 let yt: *u8 = sys_mmap(32); var c1i: i64=0; while c1i<32 { yt[c1i]=ypub[c1i]; c1i=c1i+1 } yt[0]=(yt[0]^1) as u8
102 let kk: *u8 = sys_mmap(32); let kj: *u8 = sys_mmap(96)
103 var c1: i64 = 0; if ntor_client_finish(id, bpub, xpriv, xpub, yt, auth_s, kk, kj) != 0 { c1=1 }
104 g_row("C1 tampered SERVER_PK (Y) -> client REJECTS" as *u8, c1, pass, tot)
105 // C2 tampered AUTH
106 let at: *u8 = sys_mmap(32); var c2i: i64=0; while c2i<32 { at[c2i]=auth_s[c2i]; c2i=c2i+1 } at[0]=(at[0]^1) as u8
107 var c2: i64 = 0; if ntor_client_finish(id, bpub, xpriv, xpub, ypub, at, kk, kj) != 0 { c2=1 }
108 g_row("C2 tampered AUTH tag -> client REJECTS" as *u8, c2, pass, tot)
109 // C3 wrong onion key B'
110 let bt: *u8 = sys_mmap(32); var c3i: i64=0; while c3i<32 { bt[c3i]=bpub[c3i]; c3i=c3i+1 } bt[0]=(bt[0]^1) as u8
111 var c3: i64 = 0; if ntor_client_finish(id, bt, xpriv, xpub, ypub, auth_s, kk, kj) != 0 { c3=1 }
112 g_row("C3 wrong server onion key B -> client REJECTS" as *u8, c3, pass, tot)
113 // C4 tampered ID
114 let it: *u8 = sys_mmap(20); var c4i: i64=0; while c4i<20 { it[c4i]=id[c4i]; c4i=c4i+1 } it[0]=(it[0]^1) as u8
115 var c4: i64 = 0; if ntor_client_finish(it, bpub, xpriv, xpub, ypub, auth_s, kk, kj) != 0 { c4=1 }
116 g_row("C4 tampered relay ID -> client REJECTS" as *u8, c4, pass, tot)
117
118 g_w("NOTE honest scope: two-sided agreement proves the ntor CONSTRUCTION; byte-exact interop vs the live\n" as *u8)
119 g_w(" Tor network still needs Tor's own published ntor vector + the x25519 base-point fix (see header).\n" as *u8)
120 g_w("TOR-NTOR-GATE rows=" as *u8); g_n(tot[0]); g_w(" pass=" as *u8); g_n(pass[0])
121 if pass[0]==tot[0] {
122 g_w(" verdict=GREEN\n" as *u8)
123 let lg: i64 = sys_openat_append("knowledge/status/tor_ntor_gate.log" as *u8, 0x1a4)
124 if lg>=0 { g_fw(lg, "TOR-NTOR-GATE pass=" as *u8); g_fn(lg, pass[0]); g_fw(lg, "/" as *u8); g_fn(lg, tot[0]); g_fw(lg, " verdict=GREEN scope=spec-faithful+rfc-primitive-KAT+two-sided-consistent(NOT-yet-byte-exact-vs-tor) epoch=" as *u8); g_fn(lg, sys_now_realtime_sec()); g_fw(lg, "\n" as *u8); sys_close(lg) }
125 sys_exit(0); return 0
126 }
127 g_w(" verdict=RED\n" as *u8); sys_exit(1); return 1
128}