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}