code wiki / _hdl_build / nx_media_crypt_gate.nx

nx_media_crypt_gate.nx source

↩ module page · 126 lines · 6890 B

1import "nx_gate_base.nx" 2// nx_media_crypt_gate.nx -- ChaCha20 (RFC 8439) KAT + E2EE property gate. license_tier: ORIGINAL 3import "nx_syscalls.nx" 4import "nx_media_crypt.nx" 5 6func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw(" 7" as *u8); return ok } 8func gn(v: i64) -> i64 { 9 let b: *u8=sys_mmap(28); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m} 10 let t: *u8=sys_mmap(28); 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} 11 var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 12func ck(name: *u8, ok: i64, p: *i64, t: *i64) -> i64 { 13 t[0]=t[0]+1; gw(" " as *u8); gw(name) 14 if ok==1 { gw(" PASS\n" as *u8); p[0]=p[0]+1 } else { gw(" FAIL\n" as *u8) } 15 return 0 } 16func fill(b: *u8, n: i64, seed: i64) -> i64 { var i: i64=0; while i<n { b[i]=((i*seed+7)&255) as u8; i=i+1 } return 0 } 17func same(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 } 18func popdiff(a: *u8, b: *u8, n: i64) -> i64 { var d: i64=0; var i: i64=0 19 while i<n { var x: i64=(a[i]^b[i])&255; while x>0 { d=d+(x&1); x=x/2 } i=i+1 } return d } 20func hexdec(hex: *u8, nbytes: i64, out: *u8) -> i64 { // decode nbytes from a 2*nbytes hex string 21 var i: i64=0 22 while i<nbytes { out[i]=((mc_hexval(hex[i*2]&0xff)<<4)|mc_hexval(hex[i*2+1]&0xff)) as u8; i=i+1 } 23 return 0 } 24 25func main() -> i64 { 26 gw("=== nx_media_crypt_gate: ChaCha20 (RFC 8439) + E2EE properties ===\n" as *u8) 27 let p: *i64 = sys_mmap(16) as *i64; let t: *i64 = sys_mmap(16) as *i64 28 let scr: *u8 = sys_mmap(512) // ChaCha scratch (>= MC_SCRATCH), passed to every mc_xform 29 30 // ---- T0 KAT: RFC 8439 section 2.3.2 block function (key 00..1f, nonce 00000009..4a, counter 1) ---- 31 let key: *u8 = sys_mmap(64) 32 var ki: i64=0; while ki<32 { key[ki]=ki as u8; ki=ki+1 } // key bytes 00..1f 33 let non: *u8 = sys_mmap(16) 34 non[0]=0 as u8; non[1]=0 as u8; non[2]=0 as u8; non[3]=9 as u8 35 non[4]=0 as u8; non[5]=0 as u8; non[6]=0 as u8; non[7]=0x4a as u8 36 non[8]=0 as u8; non[9]=0 as u8; non[10]=0 as u8; non[11]=0 as u8 37 let s: *i64 = sys_mmap(16*8) as *i64; let w: *i64 = sys_mmap(16*8) as *i64 38 let blk: *u8 = sys_mmap(64) 39 mc_block(key, non, 1, blk, s, w) 40 let exp: *u8 = sys_mmap(64) 41 hexdec("10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4ed2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e" as *u8, 64, exp) 42 ck("T0 KAT RFC8439 2.3.2 block function (64 bytes) \x00" as *u8, same(blk, exp, 64), p, t) 43 44 // ---- T0b KAT: RFC 8439 section 2.4.2 full encryption (counter starts at 1, sunscreen plaintext) ---- 45 let non2: *u8 = sys_mmap(16) 46 var ni: i64=0; while ni<12 { non2[ni]=0 as u8; ni=ni+1 } 47 non2[7]=0x4a as u8 // nonce 00 00 00 00 00 00 00 4a 00 00 00 00 48 let pt: *u8 = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it." as *u8 49 var pl: i64=0; while pt[pl]!=(0 as u8){pl=pl+1} // 114 bytes 50 let ct: *u8 = sys_mmap(256) 51 var ci: i64=0; while ci<pl { ct[ci]=pt[ci]; ci=ci+1 } 52 mc_xform(key, non2, 1, ct, pl, scr) // ctr0=1 per the vector 53 let cexp: *u8 = sys_mmap(256) 54 hexdec("6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0bf91b65c5524733ab8f593dabcd62b3571639d624e65152ab8f530c359f0861d807ca0dbf500d6a6156a38e088a22b65e52bc514d16ccf806818ce91ab77937365af90bbf74a35be6b40b8eedf2785e42874d" as *u8, 114, cexp) 55 ck("T0b KAT RFC8439 2.4.2 full encryption (114 bytes)\x00" as *u8, same(ct, cexp, pl), p, t) 56 57 // ---- E2EE properties (via the mc_ media API) ---- 58 let p2: *i64 = sys_mmap(16) as *i64 59 let ek: *u8 = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" as *u8 60 let ek2: *u8 = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1e" as *u8 // last byte 1f->1e 61 let key1: *u8 = sys_mmap(64); let keyB: *u8 = sys_mmap(64) 62 mc_key(ek, 64, key1); mc_key(ek2, 64, keyB) 63 let n1: *u8 = sys_mmap(16); mc_nonce("SENDER01" as *u8, 42, n1) 64 65 let L: i64 = 200 66 let dpt: *u8 = sys_mmap(256); fill(dpt, L, 3) 67 let c1: *u8 = sys_mmap(256); let d1: *u8 = sys_mmap(256) 68 69 // T1 round-trip + length-preserving 70 var i: i64=0; while i<L { c1[i]=dpt[i]; i=i+1 } 71 mc_xform(key1, n1, 0, c1, L, scr) 72 var ok: i64=1 73 if same(c1, dpt, L)==1 { ok=0 } 74 i=0; while i<L { d1[i]=c1[i]; i=i+1 } 75 mc_xform(key1, n1, 0, d1, L, scr) 76 if same(d1, dpt, L)!=1 { ok=0 } 77 ck("T1 round-trip identity + length-preserving \x00" as *u8, ok, p, t) 78 79 // T2 per-frame nonce -> different ciphertext (no keystream reuse across the SFU seq-rewrite) 80 ok=1 81 let n2: *u8 = sys_mmap(16); mc_nonce("SENDER01" as *u8, 43, n2) 82 let c2: *u8 = sys_mmap(256); i=0; while i<L { c2[i]=dpt[i]; i=i+1 } 83 mc_xform(key1, n2, 0, c2, L, scr) 84 if same(c1, c2, L)==1 { ok=0 } 85 ck("T2 per-frame nonce -> unique keystream \x00" as *u8, ok, p, t) 86 87 // T3 per-sender nonce -> different keystream 88 ok=1 89 let n3: *u8 = sys_mmap(16); mc_nonce("SENDER02" as *u8, 42, n3) 90 let c3: *u8 = sys_mmap(256); i=0; while i<L { c3[i]=dpt[i]; i=i+1 } 91 mc_xform(key1, n3, 0, c3, L, scr) 92 if same(c1, c3, L)==1 { ok=0 } 93 ck("T3 per-sender nonce -> unique keystream \x00" as *u8, ok, p, t) 94 95 // T4 wrong key -> garbage (relay-blind: token holder without ekey cannot recover) 96 ok=1 97 let bad: *u8 = sys_mmap(256); i=0; while i<L { bad[i]=c1[i]; i=i+1 } 98 mc_xform(keyB, n1, 0, bad, L, scr) 99 if same(bad, dpt, L)==1 { ok=0 } 100 ck("T4 wrong key -> garbage (relay-blind) \x00" as *u8, ok, p, t) 101 102 // T5 keystream avalanche ~50% on a 1-bit key flip 103 ok=1 104 let z1: *u8 = sys_mmap(256); let z2: *u8 = sys_mmap(256) 105 i=0; while i<L { z1[i]=0 as u8; z2[i]=0 as u8; i=i+1 } 106 mc_xform(key1, n1, 0, z1, L, scr) 107 mc_xform(keyB, n1, 0, z2, L, scr) 108 let bits: i64 = popdiff(z1, z2, L) 109 if bits < (L*8*35)/100 { ok=0 } 110 if bits > (L*8*65)/100 { ok=0 } 111 ck("T5 keystream avalanche ~50% on key flip \x00" as *u8, ok, p, t) 112 113 // T6 non-block-aligned tail (200 % 64 = 8) round-trips 114 ok=1 115 let tl: *u8 = sys_mmap(64); fill(tl, 8, 9) 116 let tc: *u8 = sys_mmap(64); i=0; while i<8 { tc[i]=tl[i]; i=i+1 } 117 mc_xform(key1, n1, 0, tc, 8, scr) 118 if same(tc, tl, 8)==1 { ok=0 } 119 mc_xform(key1, n1, 0, tc, 8, scr) 120 if same(tc, tl, 8)!=1 { ok=0 } 121 ck("T6 non-aligned tail round-trip \x00" as *u8, ok, p, t) 122 123 gw("MEDIA-CRYPT: " as *u8); gn(p[0]); gw("/" as *u8); gn(t[0]) 124 if p[0]==t[0] { gw(" ALL GREEN (ChaCha20 KAT-verified)\n" as *u8); return 0 } 125 gw(" RED\n" as *u8) 126 return 1 }