nx_chacha20_test.nx source
↩ module page · 96 lines · 3429 B
1// nx_chacha20_test.nx -- RFC 8439 §2.3.2 KAT + round-trip for ChaCha20.
2//
3// Vector (RFC 8439 §2.3.2 worked example):
4// Key: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
5// 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
6// Nonce: 00 00 00 09 00 00 00 4a 00 00 00 00
7// Counter: 1
8// Output (64-byte keystream block):
9// 10 f1 e7 e4 d1 3b 59 15 50 0f dd 1f a3 20 71 c4
10// c7 d1 f4 c7 33 c0 68 03 04 22 aa 9a c3 d4 6c 4e
11// d2 82 64 46 07 9f aa 09 14 c2 d7 05 d9 8b 02 a2
12// b5 12 9c d1 de 16 4e b9 cb d0 83 e8 a2 50 3c 4e
13//
14// Plus a round-trip: encrypt(decrypt(P)) == P since ChaCha20 is XOR
15// with the keystream (self-inverse with same key/counter/nonce).
16//
17// expect_exit: 0
18//
19// license_tier: ORIGINAL
20
21import "nx_syscalls.nx"
22import "nx_chacha20.nx"
23
24func main() -> i64 {
25 // ---- Build the 32-byte key 00..1f ----
26 let key: *u8 = sys_mmap(64)
27 var i: i64 = 0
28 while i < 32 {
29 key[i] = i
30 i = i + 1
31 }
32
33 // ---- 12-byte nonce ----
34 let nonce: *u8 = sys_mmap(16)
35 nonce[0]=0; nonce[1]=0; nonce[2]=0; nonce[3]=9
36 nonce[4]=0; nonce[5]=0; nonce[6]=0; nonce[7]=0x4a
37 nonce[8]=0; nonce[9]=0; nonce[10]=0; nonce[11]=0
38
39 // ---- Generate one keystream block with counter=1 ----
40 let out: *u8 = sys_mmap(128)
41 chacha20_block(key, 1, nonce, out)
42
43 // ---- Expected 64-byte block from RFC 8439 §2.3.2 ----
44 let exp: *u8 = sys_mmap(128)
45 exp[0]=0x10; exp[1]=0xf1; exp[2]=0xe7; exp[3]=0xe4
46 exp[4]=0xd1; exp[5]=0x3b; exp[6]=0x59; exp[7]=0x15
47 exp[8]=0x50; exp[9]=0x0f; exp[10]=0xdd; exp[11]=0x1f
48 exp[12]=0xa3; exp[13]=0x20; exp[14]=0x71; exp[15]=0xc4
49 exp[16]=0xc7; exp[17]=0xd1; exp[18]=0xf4; exp[19]=0xc7
50 exp[20]=0x33; exp[21]=0xc0; exp[22]=0x68; exp[23]=0x03
51 exp[24]=0x04; exp[25]=0x22; exp[26]=0xaa; exp[27]=0x9a
52 exp[28]=0xc3; exp[29]=0xd4; exp[30]=0x6c; exp[31]=0x4e
53 exp[32]=0xd2; exp[33]=0x82; exp[34]=0x64; exp[35]=0x46
54 exp[36]=0x07; exp[37]=0x9f; exp[38]=0xaa; exp[39]=0x09
55 exp[40]=0x14; exp[41]=0xc2; exp[42]=0xd7; exp[43]=0x05
56 exp[44]=0xd9; exp[45]=0x8b; exp[46]=0x02; exp[47]=0xa2
57 exp[48]=0xb5; exp[49]=0x12; exp[50]=0x9c; exp[51]=0xd1
58 exp[52]=0xde; exp[53]=0x16; exp[54]=0x4e; exp[55]=0xb9
59 exp[56]=0xcb; exp[57]=0xd0; exp[58]=0x83; exp[59]=0xe8
60 exp[60]=0xa2; exp[61]=0x50; exp[62]=0x3c; exp[63]=0x4e
61
62 // ---- Compare keystream byte-for-byte; exit code 100+i on mismatch ----
63 var k: i64 = 0
64 while k < 64 {
65 if (out[k] & 0xff) != (exp[k] & 0xff) { return 100 + k }
66 k = k + 1
67 }
68
69 // ---- Round-trip: encrypt(encrypt(P)) == P (XOR self-inverse) ----
70 let pt: *u8 = sys_mmap(128)
71 let ct: *u8 = sys_mmap(128)
72 let pt2: *u8 = sys_mmap(128)
73 var p: i64 = 0
74 while p < 100 {
75 pt[p] = (p * 17 + 3) & 0xff
76 p = p + 1
77 }
78 chacha20_encrypt(key, 1, nonce, pt, 100, ct)
79 chacha20_encrypt(key, 1, nonce, ct, 100, pt2)
80 var r: i64 = 0
81 while r < 100 {
82 if (pt[r] & 0xff) != (pt2[r] & 0xff) { return 200 + r }
83 r = r + 1
84 }
85
86 // ---- Sanity: ciphertext differs from plaintext (XOR was non-trivial) ----
87 var diff_count: i64 = 0
88 var s: i64 = 0
89 while s < 100 {
90 if (pt[s] & 0xff) != (ct[s] & 0xff) { diff_count = diff_count + 1 }
91 s = s + 1
92 }
93 if diff_count < 90 { return 1 } // expect ~all bytes to differ
94
95 return 0
96}