code wiki / (root) / nx_chacha20_test.nx

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}