code wiki / _hdl_build / nx_chacha_block_dump.nx
nx_chacha_block_dump.nx source
↩ module page · 53 lines · 2543 B
1// nx_chacha_block_dump.nx -- ground-truth oracle for the SIMD ChaCha rung. Inlines the scalar ChaCha20
2// block (RFC 8439 ยง2.3.2 input: key=0..31, nonce=00 00 00 09 00 00 00 4a 00 00 00 00, counter=1) and
3// prints the 64 keystream bytes as decimals. The SIMD ChaCha must reproduce THIS exactly (SIMD==scalar
4// == the KAT'd-correct oracle). No hallucinated vectors. license_tier: ORIGINAL
5import "nx_syscalls.nx"
6
7func u32(x: i64) -> i64 { return x & 0xFFFFFFFF }
8func rotl32(x: i64, r: i64) -> i64 { let a: i64 = (x << r) & 0xFFFFFFFF; let b: i64 = (x & 0xFFFFFFFF) >> (32 - r); return a | b }
9
10func qr(s: *i64, a: i64, b: i64, c: i64, d: i64) -> i64 {
11 s[a] = u32(s[a] + s[b]); s[d] = rotl32(s[d] ^ s[a], 16)
12 s[c] = u32(s[c] + s[d]); s[b] = rotl32(s[b] ^ s[c], 12)
13 s[a] = u32(s[a] + s[b]); s[d] = rotl32(s[d] ^ s[a], 8)
14 s[c] = u32(s[c] + s[d]); s[b] = rotl32(s[b] ^ s[c], 7)
15 return 0
16}
17
18func pn(v: i64) -> i64 {
19 let bb: *u8 = sys_mmap(16); var m: i64 = v; let t: *u8 = sys_mmap(16); var k: i64 = 0
20 if m == 0 { t[0] = 48; k = 1 }
21 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
22 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
23 sys_write(1, bb, k); sys_write(1, "," as *u8, 1); return 0
24}
25
26func main() -> i64 {
27 let s: *i64 = sys_mmap(8 * 16) as *i64
28 let init: *i64 = sys_mmap(8 * 16) as *i64
29 s[0] = 0x61707865; s[1] = 0x3320646e; s[2] = 0x79622d32; s[3] = 0x6b206574
30 s[4] = 0x03020100; s[5] = 0x07060504; s[6] = 0x0b0a0908; s[7] = 0x0f0e0d0c
31 s[8] = 0x13121110; s[9] = 0x17161514; s[10] = 0x1b1a1918; s[11] = 0x1f1e1d1c
32 s[12] = 1; s[13] = 0x09000000; s[14] = 0x4a000000; s[15] = 0x00000000
33 var i: i64 = 0; while i < 16 { init[i] = s[i]; i = i + 1 }
34 var r: i64 = 0
35 while r < 10 {
36 qr(s, 0, 4, 8, 12); qr(s, 1, 5, 9, 13); qr(s, 2, 6, 10, 14); qr(s, 3, 7, 11, 15)
37 qr(s, 0, 5, 10, 15); qr(s, 1, 6, 11, 12); qr(s, 2, 7, 8, 13); qr(s, 3, 4, 9, 14)
38 r = r + 1
39 }
40 var j: i64 = 0; while j < 16 { s[j] = u32(s[j] + init[j]); j = j + 1 }
41 // serialize little-endian, print 64 decimal bytes
42 var k: i64 = 0
43 while k < 16 {
44 pn(s[k] & 0xff); pn((s[k] >> 8) & 0xff); pn((s[k] >> 16) & 0xff); pn((s[k] >> 24) & 0xff)
45 k = k + 1
46 }
47 sys_write(1, "\n" as *u8, 1)
48 // also print the first 4 words (the SIMD gate checks word0..3 = lane values) for a compact KAT
49 sys_write(1, "W0_3=" as *u8, 5)
50 pn(s[0]); pn(s[1]); pn(s[2]); pn(s[3])
51 sys_write(1, "\n" as *u8, 1)
52 return 0
53}