code wiki / _hdl_build / nx_connect_keyx_vm_gate.nx
nx_connect_keyx_vm_gate.nx source
↩ module page · 107 lines · 6762 B
1// nx_connect_keyx_vm_gate.nx -- THE FULL-E2E KEY-AGREEMENT CROWN TOOTH: prove the Diffie-Hellman
2// property on the EXACT wasm bytes the browsers run (web_assets/_video_build/nx_x25519.wasm), inside the
3// sovereign nx_wasm_vm, against RFC 7748 section 6.1's complete Alice/Bob exchange:
4// T2 X25519(alice_priv, 9) == alice_pub (keygen half, Alice)
5// T3 X25519(bob_priv, 9) == bob_pub (keygen half, Bob)
6// T4 X25519(alice_priv, bob_pub) == K (Alice derives the shared key)
7// T5 X25519(bob_priv, alice_pub) == K and == T4 (Bob derives the SAME key = agreement)
8// If GREEN, the two browsers in the CONNECT E2E client MUST agree on a conversation key without the
9// server ever seeing a private key -- proven on the shipped artifact, not on a reimplementation.
10// license_tier: ORIGINAL expect_exit: 0
11import "nx_syscalls.nx"
12import "nx_wasm_vm.nx"
13
14func g_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
15func g_pn(v: i64) -> i64 {
16 let b: *u8 = sys_mmap(28); var x: i64 = v
17 if x == 0 { b[0]=48; sys_write(1,b,1); return 0 }
18 var d: i64=0; var y: i64=x
19 while y>0 { d=d+1; y=y/10 }
20 var i: i64=d-1; y=x
21 while i>=0 { b[i]=(48+(y%10)) as u8; y=y/10; i=i-1 }
22 sys_write(1,b,d); return 0
23}
24func g_check(name: *u8, cond: i64) -> i64 {
25 if cond==1 { g_puts(" PASS " as *u8) } else { g_puts(" FAIL " as *u8) }
26 g_puts(name); g_puts("\n" as *u8); return cond
27}
28
29// run one scalarmult in the VM: scalar/point copied to fixed offsets, result copied OUT to res.
30func kx_mult(mod: *WasmMod, scalar: *i64, point: *i64, res: *i64) -> i64 {
31 var i: i64 = 0
32 while i < 32 { mod.mem[i] = scalar[i] as u8; mod.mem[64 + i] = point[i] as u8; i = i + 1 }
33 wm_run(mod, "nx_x25519_scalarmult" as *u8, 0, 64, 256, 2048, 0, 4)
34 i = 0
35 while i < 32 { res[i] = mod.mem[2048 + i] as i64; i = i + 1 }
36 return 0
37}
38func kx_eq(a: *i64, b: *i64) -> i64 {
39 var i: i64 = 0
40 while i < 32 { if a[i] != b[i] { return 0 } i = i + 1 }
41 return 1
42}
43
44func main() -> i64 {
45 g_puts("nx_connect_keyx_vm_gate (RFC 7748 6.1 full DH exchange, executed on the SHIPPED nx_x25519.wasm in nx_wasm_vm)\n" as *u8)
46 var pass: i64 = 0; var total: i64 = 0
47 let box: *i64 = sys_mmap(16) as *i64
48 let wasm: *u8 = sys_read_file("/mnt/c/Users/elder/nishi-core/nxc2/web_assets/_video_build/nx_x25519.wasm" as *u8, box)
49 if (wasm as i64) == 0 { g_puts(" FAIL read wasm\n" as *u8); g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1 }
50 let mod: *WasmMod = wm_new(wasm, box[0])
51 if wm_parse(mod) != 0 { g_puts(" FAIL parse\n" as *u8); g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1 }
52 mod.mem = sys_mmap(131072) as *u8
53 let fidx: i64 = wm_find_export(mod, "nx_x25519_scalarmult" as *u8)
54 pass = pass + g_check("T1 nx_x25519_scalarmult exported by the shipped wasm" as *u8, fidx >= 0); total=total+1
55
56 // ---- RFC 7748 6.1 vectors ----
57 let ap: *i64 = sys_mmap(32*8) as *i64 // Alice private
58 let apub: *i64 = sys_mmap(32*8) as *i64 // Alice public (expected)
59 let bp: *i64 = sys_mmap(32*8) as *i64 // Bob private
60 let bpub: *i64 = sys_mmap(32*8) as *i64 // Bob public (expected)
61 let shk: *i64 = sys_mmap(32*8) as *i64 // shared K (expected)
62 let base: *i64 = sys_mmap(32*8) as *i64 // the curve base point u=9
63 var z: i64=0
64 while z<32 { base[z]=0; z=z+1 }
65 base[0]=9
66 ap[0]=119; ap[1]=7; ap[2]=109; ap[3]=10; ap[4]=115; ap[5]=24; ap[6]=165; ap[7]=125
67 ap[8]=60; ap[9]=22; ap[10]=193; ap[11]=114; ap[12]=81; ap[13]=178; ap[14]=102; ap[15]=69
68 ap[16]=223; ap[17]=76; ap[18]=47; ap[19]=135; ap[20]=235; ap[21]=192; ap[22]=153; ap[23]=42
69 ap[24]=177; ap[25]=119; ap[26]=251; ap[27]=165; ap[28]=29; ap[29]=185; ap[30]=44; ap[31]=42
70 apub[0]=133; apub[1]=32; apub[2]=240; apub[3]=9; apub[4]=137; apub[5]=48; apub[6]=167; apub[7]=84
71 apub[8]=116; apub[9]=139; apub[10]=125; apub[11]=220; apub[12]=180; apub[13]=62; apub[14]=247; apub[15]=90
72 apub[16]=13; apub[17]=191; apub[18]=58; apub[19]=13; apub[20]=38; apub[21]=56; apub[22]=26; apub[23]=244
73 apub[24]=235; apub[25]=164; apub[26]=169; apub[27]=142; apub[28]=170; apub[29]=155; apub[30]=78; apub[31]=106
74 bp[0]=93; bp[1]=171; bp[2]=8; bp[3]=126; bp[4]=98; bp[5]=74; bp[6]=138; bp[7]=75
75 bp[8]=121; bp[9]=225; bp[10]=127; bp[11]=139; bp[12]=131; bp[13]=128; bp[14]=14; bp[15]=230
76 bp[16]=111; bp[17]=59; bp[18]=177; bp[19]=41; bp[20]=38; bp[21]=24; bp[22]=182; bp[23]=253
77 bp[24]=28; bp[25]=47; bp[26]=139; bp[27]=39; bp[28]=255; bp[29]=136; bp[30]=224; bp[31]=235
78 bpub[0]=222; bpub[1]=158; bpub[2]=219; bpub[3]=125; bpub[4]=123; bpub[5]=125; bpub[6]=193; bpub[7]=180
79 bpub[8]=211; bpub[9]=91; bpub[10]=97; bpub[11]=194; bpub[12]=236; bpub[13]=228; bpub[14]=53; bpub[15]=55
80 bpub[16]=63; bpub[17]=131; bpub[18]=67; bpub[19]=200; bpub[20]=91; bpub[21]=120; bpub[22]=103; bpub[23]=77
81 bpub[24]=173; bpub[25]=252; bpub[26]=126; bpub[27]=20; bpub[28]=111; bpub[29]=136; bpub[30]=43; bpub[31]=79
82 shk[0]=74; shk[1]=93; shk[2]=157; shk[3]=91; shk[4]=164; shk[5]=206; shk[6]=45; shk[7]=225
83 shk[8]=114; shk[9]=142; shk[10]=59; shk[11]=244; shk[12]=128; shk[13]=53; shk[14]=15; shk[15]=37
84 shk[16]=224; shk[17]=126; shk[18]=33; shk[19]=201; shk[20]=71; shk[21]=209; shk[22]=158; shk[23]=51
85 shk[24]=118; shk[25]=240; shk[26]=155; shk[27]=60; shk[28]=30; shk[29]=22; shk[30]=23; shk[31]=66
86
87 let r1: *i64 = sys_mmap(32*8) as *i64
88 let r2: *i64 = sys_mmap(32*8) as *i64
89 let r3: *i64 = sys_mmap(32*8) as *i64
90 let r4: *i64 = sys_mmap(32*8) as *i64
91
92 g_puts(" running 4 scalarmults in the interpreted VM (Montgomery ladder x4 -- slow is expected)...\n" as *u8)
93 kx_mult(mod, ap, base, r1)
94 pass = pass + g_check("T2 Alice keygen: X25519(alice_priv, 9) == RFC alice_pub" as *u8, kx_eq(r1, apub)); total=total+1
95 kx_mult(mod, bp, base, r2)
96 pass = pass + g_check("T3 Bob keygen: X25519(bob_priv, 9) == RFC bob_pub" as *u8, kx_eq(r2, bpub)); total=total+1
97 kx_mult(mod, ap, bpub, r3)
98 pass = pass + g_check("T4 Alice derives: X25519(alice_priv, bob_pub) == RFC shared K" as *u8, kx_eq(r3, shk)); total=total+1
99 kx_mult(mod, bp, apub, r4)
100 var t5: i64 = 0
101 if kx_eq(r4, shk)==1 { if kx_eq(r4, r3)==1 { t5=1 } }
102 pass = pass + g_check("T5 Bob derives the SAME key: X25519(bob_priv, alice_pub) == K == Alice's derivation (DH AGREEMENT)" as *u8, t5); total=total+1
103
104 g_puts("---- connect keyx VM gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8)
105 if pass == total { g_puts("verdict=GREEN\n" as *u8); sys_exit(0); return 0 }
106 g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1
107}