code wiki / (root) / nx_iot_local_tuya_v33_test.nx

nx_iot_local_tuya_v33_test.nx source

↩ module page · 208 lines · 9112 B

1// nx_iot_local_tuya_v33_test.nx -- end-to-end smoke for the Tuya 2// v3.3 frame envelope primitive. 3// 4// Coverage: 5// - CRC32 KAT against the canonical "123456789" -> 0xCBF43926 6// - CRC32 zero-length corner case 7// - sealed-enum decode verdict validity gate 8// - frame encode + decode roundtrip with a varied payload 9// - cmd / seq survival across roundtrip 10// - encode: out_cap too small -> -1 11// - decode: truncated buffer -> BUF_TOO_SMALL 12// - decode: corrupted header sentinel -> BAD_HEADER 13// - decode: corrupted tail sentinel -> BAD_TAIL 14// - decode: tampered CRC -> BAD_CRC 15// - decode: tampered payload (CRC mismatches) -> BAD_CRC 16// - decode: length field below minimum -> BAD_LEN 17// 18// expect_exit: 0 19// 20// license_tier: ORIGINAL 21 22// The frame primitive itself is syscall-free; the smoke uses sys_mmap 23// for scratch buffers and so needs an ISA-specific syscall layer. 24// This file targets x86_64 native exec via bench_x86_64_native_smoke.sh; 25// a parallel _aarch64_test.nx will land when the hub box is chosen. 26import "nx_syscalls_x86_64.nx" 27import "nx_iot_local_tuya_v33.nx" 28 29func main() -> i64 { 30 // ---- CRC32 KAT -------------------------------------------------- 31 // "123456789" = bytes 0x31..0x39, CRC32 = 0xCBF43926 (zlib KAT). 32 let kat: *u8 = sys_mmap(16) 33 kat[0] = 0x31; kat[1] = 0x32; kat[2] = 0x33; kat[3] = 0x34 34 kat[4] = 0x35; kat[5] = 0x36; kat[6] = 0x37; kat[7] = 0x38 35 kat[8] = 0x39 36 let c: i64 = nx_tuya_crc32(kat, 9) 37 if c != 0xCBF43926 { return 1 } 38 39 // Zero-length input: CRC32 of empty == 0x00000000 (init XOR xorout). 40 let zero_c: i64 = nx_tuya_crc32(kat, 0) 41 if zero_c != 0 { return 2 } 42 43 // ---- Decode-verdict validity gate ------------------------------- 44 if nx_tuya_decode_verdict_is_valid(NX_TUYA_DECODE_UNKNOWN) != 1 { return 10 } 45 if nx_tuya_decode_verdict_is_valid(NX_TUYA_DECODE_OK) != 1 { return 11 } 46 if nx_tuya_decode_verdict_is_valid(NX_TUYA_DECODE_BAD_HEADER) != 1 { return 12 } 47 if nx_tuya_decode_verdict_is_valid(NX_TUYA_DECODE_BAD_TAIL) != 1 { return 13 } 48 if nx_tuya_decode_verdict_is_valid(NX_TUYA_DECODE_BAD_CRC) != 1 { return 14 } 49 if nx_tuya_decode_verdict_is_valid(NX_TUYA_DECODE_BAD_LEN) != 1 { return 15 } 50 if nx_tuya_decode_verdict_is_valid(NX_TUYA_DECODE_BUF_TOO_SMALL) != 1 { return 16 } 51 if nx_tuya_decode_verdict_is_valid(NX_TUYA_DECODE_N) != 0 { return 17 } 52 if nx_tuya_decode_verdict_is_valid(-3) != 0 { return 18 } 53 if nx_tuya_decode_verdict_is_valid(99) != 0 { return 19 } 54 55 // ---- Encode + decode roundtrip ---------------------------------- 56 // Build a 16-byte representative payload (simulates a ciphertext 57 // block; this primitive is payload-agnostic). 58 let payload: *u8 = sys_mmap(32) 59 var i: i64 = 0 60 while i < 16 { payload[i] = (i * 17) & 0xff; i = i + 1 } 61 62 let frame: *u8 = sys_mmap(64) 63 let total: i64 = nx_tuya_frame_encode(NX_TUYA_CMD_CONTROL, 0x12345678, 64 payload, 16, frame, 64) 65 if total != 16 + 24 { return 20 } // 24 byte overhead + 16 byte payload 66 67 // Header bytes 68 if frame[0] != 0x00 { return 21 } 69 if frame[1] != 0x00 { return 22 } 70 if frame[2] != 0x55 { return 23 } 71 if frame[3] != 0xAA { return 24 } 72 // Sequence BE 73 if frame[4] != 0x12 { return 25 } 74 if frame[5] != 0x34 { return 26 } 75 if frame[6] != 0x56 { return 27 } 76 if frame[7] != 0x78 { return 28 } 77 // Command BE 78 if nx_tuya_read_be32(frame, 8) != NX_TUYA_CMD_CONTROL { return 29 } 79 // Length field BE = payload + suffix(8) = 24 80 if nx_tuya_read_be32(frame, 12) != 24 { return 30 } 81 // Tail bytes 82 if frame[total - 4] != 0x00 { return 31 } 83 if frame[total - 3] != 0x00 { return 32 } 84 if frame[total - 2] != 0xAA { return 33 } 85 if frame[total - 1] != 0x55 { return 34 } 86 87 // Decode the frame we just built. 88 let dec_cmd: *i64 = sys_mmap(8) as *i64 89 let dec_seq: *i64 = sys_mmap(8) as *i64 90 let dec_pl: *u8 = sys_mmap(32) 91 let dec_v: *i64 = sys_mmap(8) as *i64 92 let pl_len: i64 = nx_tuya_frame_decode(frame, total, 93 dec_cmd, dec_seq, 94 dec_pl, 32, dec_v) 95 if pl_len != 16 { return 40 } 96 if dec_v[0] != NX_TUYA_DECODE_OK { return 41 } 97 if dec_cmd[0] != NX_TUYA_CMD_CONTROL { return 42 } 98 if dec_seq[0] != 0x12345678 { return 43 } 99 // Payload bytes match what we encoded 100 var k: i64 = 0 101 while k < 16 { 102 if dec_pl[k] != ((k * 17) & 0xff) { return 50 + k } 103 k = k + 1 104 } 105 106 // ---- Encode: out_cap too small ---------------------------------- 107 let small: *u8 = sys_mmap(8) 108 let bad_enc: i64 = nx_tuya_frame_encode(NX_TUYA_CMD_CONTROL, 1, 109 payload, 16, small, 8) 110 if bad_enc != -1 { return 70 } 111 112 // ---- Decode: truncated buffer (< OVERHEAD) --------------------- 113 let trunc_v: *i64 = sys_mmap(8) as *i64 114 let trunc_pl: *u8 = sys_mmap(32) 115 let trunc_cmd: *i64 = sys_mmap(8) as *i64 116 let trunc_seq: *i64 = sys_mmap(8) as *i64 117 let trunc_r: i64 = nx_tuya_frame_decode(frame, 8, 118 trunc_cmd, trunc_seq, 119 trunc_pl, 32, trunc_v) 120 if trunc_r != -1 { return 71 } 121 if trunc_v[0] != NX_TUYA_DECODE_BUF_TOO_SMALL { return 72 } 122 123 // ---- Decode: corrupted header sentinel -------------------------- 124 let bh: *u8 = sys_mmap(64) 125 var j: i64 = 0 126 while j < total { bh[j] = frame[j]; j = j + 1 } 127 bh[0] = 0xFF // smash header 128 let bh_v: *i64 = sys_mmap(8) as *i64 129 let bh_r: i64 = nx_tuya_frame_decode(bh, total, 130 trunc_cmd, trunc_seq, 131 trunc_pl, 32, bh_v) 132 if bh_r != -1 { return 73 } 133 if bh_v[0] != NX_TUYA_DECODE_BAD_HEADER { return 74 } 134 135 // ---- Decode: corrupted tail sentinel ---------------------------- 136 let bt: *u8 = sys_mmap(64) 137 j = 0 138 while j < total { bt[j] = frame[j]; j = j + 1 } 139 bt[total - 1] = 0xFF // smash tail 140 let bt_v: *i64 = sys_mmap(8) as *i64 141 let bt_r: i64 = nx_tuya_frame_decode(bt, total, 142 trunc_cmd, trunc_seq, 143 trunc_pl, 32, bt_v) 144 if bt_r != -1 { return 75 } 145 if bt_v[0] != NX_TUYA_DECODE_BAD_TAIL { return 76 } 146 147 // ---- Decode: tampered CRC -------------------------------------- 148 let bc: *u8 = sys_mmap(64) 149 j = 0 150 while j < total { bc[j] = frame[j]; j = j + 1 } 151 // CRC bytes are at offsets total-8 .. total-5 152 bc[total - 8] = bc[total - 8] ^ 0xFF 153 let bc_v: *i64 = sys_mmap(8) as *i64 154 let bc_r: i64 = nx_tuya_frame_decode(bc, total, 155 trunc_cmd, trunc_seq, 156 trunc_pl, 32, bc_v) 157 if bc_r != -1 { return 77 } 158 if bc_v[0] != NX_TUYA_DECODE_BAD_CRC { return 78 } 159 160 // ---- Decode: tampered payload (CRC mismatches) ----------------- 161 let bp: *u8 = sys_mmap(64) 162 j = 0 163 while j < total { bp[j] = frame[j]; j = j + 1 } 164 bp[16] = bp[16] ^ 0xFF // flip first payload byte 165 let bp_v: *i64 = sys_mmap(8) as *i64 166 let bp_r: i64 = nx_tuya_frame_decode(bp, total, 167 trunc_cmd, trunc_seq, 168 trunc_pl, 32, bp_v) 169 if bp_r != -1 { return 79 } 170 if bp_v[0] != NX_TUYA_DECODE_BAD_CRC { return 80 } 171 172 // ---- Decode: length field below minimum (< 8) ------------------ 173 let bl: *u8 = sys_mmap(64) 174 j = 0 175 while j < total { bl[j] = frame[j]; j = j + 1 } 176 // Write length-field = 4 (less than SUFFIX_LEN = 8) 177 nx_tuya_write_be32(bl, 12, 4) 178 let bl_v: *i64 = sys_mmap(8) as *i64 179 let bl_r: i64 = nx_tuya_frame_decode(bl, total, 180 trunc_cmd, trunc_seq, 181 trunc_pl, 32, bl_v) 182 if bl_r != -1 { return 81 } 183 if bl_v[0] != NX_TUYA_DECODE_BAD_LEN { return 82 } 184 185 // ---- Decode: length field declares more bytes than buffer has -- 186 let bg: *u8 = sys_mmap(64) 187 j = 0 188 while j < total { bg[j] = frame[j]; j = j + 1 } 189 // Length field = payload(16) + suffix(8) + 100 extra -> truncated 190 nx_tuya_write_be32(bg, 12, 24 + 100) 191 let bg_v: *i64 = sys_mmap(8) as *i64 192 let bg_r: i64 = nx_tuya_frame_decode(bg, total, 193 trunc_cmd, trunc_seq, 194 trunc_pl, 32, bg_v) 195 if bg_r != -1 { return 83 } 196 if bg_v[0] != NX_TUYA_DECODE_BAD_LEN { return 84 } 197 198 // ---- BE read/write helpers -------------------------------------- 199 let be: *u8 = sys_mmap(8) 200 nx_tuya_write_be32(be, 0, 0xDEADBEEF) 201 if be[0] != 0xDE { return 90 } 202 if be[1] != 0xAD { return 91 } 203 if be[2] != 0xBE { return 92 } 204 if be[3] != 0xEF { return 93 } 205 if nx_tuya_read_be32(be, 0) != 0xDEADBEEF { return 94 } 206 207 return 0 208}