nx_zlib_wrap.nx source
↩ module page · 284 lines · 9945 B
1// nx_zlib_wrap.nx -- RFC 1950 zlib container (DEFLATE + headers + Adler-32).
2//
3// CAPABILITY_COMPLETENESS: FULL
4//
5// zlib stream layout per RFC 1950:
6//
7// +---+---+ 2-byte header
8// |CMF|FLG|
9// +---+---+
10// | ... | DEFLATE-compressed data (RFC 1951)
11// +-------+
12// |Adler32| 4-byte big-endian Adler-32 of uncompressed data
13// +-------+
14//
15// CMF (compression method + flags):
16// bits 0-3 CM (4 = deflate is reserved; 8 = deflate stream)
17// bits 4-7 CINFO (log2(window-size) - 8); for 32 KB window = 7
18//
19// FLG:
20// bits 0-4 FCHECK -- chosen so (CMF*256 + FLG) mod 31 == 0
21// bit 5 FDICT -- 1 if preset dictionary in use (rare; refused
22// in v1; queued as `feedback-preset-dict` work)
23// bits 6-7 FLEVEL -- compression-level hint (advisory; ignored)
24//
25// genealogy_id: rfc1950_zlib_1996
26// lineage_id: nx_zlib_wrap_v1
27//
28// Composes: nx_deflate (INFLATE) + nx_adler32 (already shipped).
29
30// nx_safety_envelope:
31// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
32// sil_target: SIL1
33// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
34// verdict: NOT_YET_EVALUATED
35
36import "nx_syscalls.nx"
37import "nx_runtime.nx"
38import "nx_tier.nx"
39import "nx_deflate.nx"
40import "nx_adler32.nx"
41const NX_MAGIC_16449714: i64 = 16449714
42const NX_MAGIC_30720: i64 = 30720
43
44// ===== error codes ================================================
45
46const NX_ZLIB_OK: nx_int = 0
47const NX_ZLIB_ERR_TOO_SHORT: nx_int = 1
48const NX_ZLIB_ERR_BAD_METHOD: nx_int = 2
49const NX_ZLIB_ERR_BAD_CHECK: nx_int = 3
50const NX_ZLIB_ERR_PRESET_DICT: nx_int = 4
51const NX_ZLIB_ERR_DEFLATE: nx_int = 5
52const NX_ZLIB_ERR_ADLER_MISMATCH: nx_int = 6
53
54// ===== result struct ==============================================
55
56struct NxZlibResult {
57 output_data: *u8,
58 output_size: nx_int,
59 bytes_consumed: nx_int,
60 error_code: nx_int,
61 cm: nx_int,
62 cinfo: nx_int,
63 fdict: nx_int,
64 flevel: nx_int,
65 adler_expected: nx_int,
66 adler_computed: nx_int,
67}
68
69const NX_ZLIB_RESULT_BYTES: nx_size = 80
70
71// ===== inflate full zlib stream ===================================
72
73func nx_zlib_inflate(input: *u8, input_size: nx_int,
74 max_output: nx_int) -> *NxZlibResult {
75 let r_ptr: *u8 = sys_mmap(NX_ZLIB_RESULT_BYTES)
76 let r: *NxZlibResult = r_ptr as *NxZlibResult
77 r.output_data = 0 as *u8
78 r.output_size = 0
79 r.bytes_consumed = 0
80 r.error_code = NX_ZLIB_OK
81
82 if input_size < 6 { // 2-byte header + min 0-byte DEFLATE + 4-byte trailer
83 r.error_code = NX_ZLIB_ERR_TOO_SHORT
84 return r
85 }
86
87 let cmf: nx_int = (input[0] as nx_int) & 255
88 let flg: nx_int = (input[1] as nx_int) & 255
89 let cm: nx_int = cmf & 15
90 let cinfo: nx_int = (cmf >> 4) & 15
91 let fdict: nx_int = (flg >> 5) & 1
92 let flevel: nx_int = (flg >> 6) & 3
93 r.cm = cm
94 r.cinfo = cinfo
95 r.fdict = fdict
96 r.flevel = flevel
97
98 if cm != 8 {
99 r.error_code = NX_ZLIB_ERR_BAD_METHOD
100 return r
101 }
102 // FCHECK: (cmf*256 + flg) mod 31 must equal 0.
103 let check_val: nx_int = (cmf * 256 + flg) % 31
104 if check_val != 0 {
105 r.error_code = NX_ZLIB_ERR_BAD_CHECK
106 return r
107 }
108 if fdict == 1 {
109 // Preset dictionary requires the caller to supply the
110 // dictionary out-of-band -- queued capability.
111 r.error_code = NX_ZLIB_ERR_PRESET_DICT
112 return r
113 }
114
115 // DEFLATE-compressed payload starts at offset 2 and ends 4
116 // bytes before EOF (Adler-32 trailer).
117 let payload_size: nx_int = input_size - 2 - 4
118 let payload: *u8 = (input as nx_int + 2) as *u8
119
120 let def_r: *NxDeflateResult = nx_deflate_inflate(
121 payload, payload_size, max_output)
122 if def_r == (0 as *NxDeflateResult) {
123 r.error_code = NX_ZLIB_ERR_DEFLATE
124 return r
125 }
126 if def_r.error_code != NX_DEF_OK {
127 r.error_code = NX_ZLIB_ERR_DEFLATE
128 r.output_data = def_r.output_data
129 r.output_size = def_r.output_size
130 r.bytes_consumed = 2 + def_r.bytes_consumed
131 return r
132 }
133
134 // Read 4-byte big-endian Adler-32 trailer.
135 let trailer_off: nx_int = 2 + def_r.bytes_consumed
136 if (trailer_off + 4) > input_size {
137 r.error_code = NX_ZLIB_ERR_TOO_SHORT
138 return r
139 }
140 let a0: nx_int = (input[trailer_off] as nx_int) & 255
141 let a1: nx_int = (input[trailer_off + 1] as nx_int) & 255
142 let a2: nx_int = (input[trailer_off + 2] as nx_int) & 255
143 let a3: nx_int = (input[trailer_off + 3] as nx_int) & 255
144 let adler_expected: nx_int = (a0 << 24) | (a1 << 16) | (a2 << 8) | a3
145
146 // Verify Adler-32 over the inflated output.
147 let adler_computed: nx_int = adler32(def_r.output_data, def_r.output_size)
148 r.adler_expected = adler_expected
149 r.adler_computed = adler_computed
150
151 if adler_expected != adler_computed {
152 r.error_code = NX_ZLIB_ERR_ADLER_MISMATCH
153 }
154
155 r.output_data = def_r.output_data
156 r.output_size = def_r.output_size
157 r.bytes_consumed = trailer_off + 4
158 return r
159}
160
161// ===== self-test ==================================================
162//
163// Construct a minimal zlib stream by hand:
164// CMF = 0x78 (CM=8 deflate, CINFO=7 32KB window)
165// FLG chosen so (0x78*256 + FLG) % 31 == 0
166// 0x78 * 256 = 30720; 30720 % 31 = 30720 - 31*991 = 30720 - 30721 = -1 = 30
167// FLG must satisfy (30 + FLG) % 31 == 0 -> FLG = 1.
168// With FDICT=0 FLEVEL=0 FCHECK=1 -> FLG = 1.
169// Payload: BFINAL=1 BTYPE=00 stored + LEN=2 + NLEN=0xFFFD + "Hi"
170// byte 0: 0x01 (BFINAL=1, BTYPE=00 + padding)
171// byte 1: 0x02 (LEN lo)
172// byte 2: 0x00 (LEN hi)
173// byte 3: 0xFD (NLEN lo)
174// byte 4: 0xFF (NLEN hi)
175// byte 5: 'H' = 0x48
176// byte 6: 'i' = 0x69
177// Adler-32 of "Hi":
178// a = 1 + 'H' = 73; a = 73 + 'i' = 73 + 105 = 178
179// b = 0 + 1 + 73 + 178 = ... compute via library
180// s1 = 178, s2 = 0 + 73 + 178 = 251
181// adler = (251 << 16) | 178 = 0x00FB00B2
182
183func main() -> nx_int {
184 // First verify Adler-32 helper produces 0x00FB00B2 for "Hi".
185 let hi: *u8 = (sys_mmap(2)) as *u8
186 hi[0] = 0x48 as u8
187 hi[1] = 0x69 as u8
188 let a_hi: nx_int = adler32(hi, 2)
189 if a_hi != NX_MAGIC_16449714 { return 1 } // 0x00FB00B2
190
191 // Build the zlib stream.
192 let stream: *u8 = (sys_mmap(11)) as *u8
193 stream[0] = 0x78 as u8 // CMF
194 stream[1] = 0x01 as u8 // FLG
195 stream[2] = 0x01 as u8 // BFINAL=1 BTYPE=00
196 stream[3] = 0x02 as u8 // LEN lo
197 stream[4] = 0x00 as u8 // LEN hi
198 stream[5] = 0xFD as u8 // NLEN lo
199 stream[6] = 0xFF as u8 // NLEN hi
200 stream[7] = 0x48 as u8 // 'H'
201 stream[8] = 0x69 as u8 // 'i'
202 // big-endian Adler-32 = 0x00 0xFB 0x00 0xB2
203 stream[9] = 0x00 as u8 // unused high byte
204 stream[10] = 0xFB as u8 // unused high byte 2
205 // need full 4 bytes -- expand:
206 let stream2: *u8 = (sys_mmap(13)) as *u8
207 var i: nx_int = 0
208 while i < 9 {
209 stream2[i] = stream[i]
210 i = i + 1
211 }
212 stream2[9] = 0x00 as u8
213 stream2[10] = 0xFB as u8
214 stream2[11] = 0x00 as u8
215 stream2[12] = 0xB2 as u8
216
217 let r: *NxZlibResult = nx_zlib_inflate(stream2, 13, 64)
218 if r == (0 as *NxZlibResult) { return 2 }
219 if r.error_code != NX_ZLIB_OK { return 3 }
220 if r.cm != 8 { return 4 }
221 if r.cinfo != 7 { return 5 }
222 if r.output_size != 2 { return 6 }
223 if r.output_data[0] != (0x48 as u8) { return 7 }
224 if r.output_data[1] != (0x69 as u8) { return 8 }
225 if r.adler_expected != r.adler_computed { return 9 }
226
227 // ---- Bad method (CM != 8) ----
228 let bad_method: *u8 = (sys_mmap(13)) as *u8
229 var j: nx_int = 0
230 while j < 13 {
231 bad_method[j] = stream2[j]
232 j = j + 1
233 }
234 bad_method[0] = 0x79 as u8 // CM=9, bad
235 // recompute FCHECK so header passes 31-mod check? Doesn't
236 // matter -- bad-method check fires first.
237 let rbm: *NxZlibResult = nx_zlib_inflate(bad_method, 13, 64)
238 if rbm.error_code != NX_ZLIB_ERR_BAD_METHOD { return 20 }
239
240 // ---- Bad FCHECK (FLG that breaks % 31 check) ----
241 let bad_fcheck: *u8 = (sys_mmap(13)) as *u8
242 var k: nx_int = 0
243 while k < 13 {
244 bad_fcheck[k] = stream2[k]
245 k = k + 1
246 }
247 bad_fcheck[1] = 0x02 as u8 // FLG=2 -> (NX_MAGIC_30720+2) % 31 = 1 != 0
248 let rbc: *NxZlibResult = nx_zlib_inflate(bad_fcheck, 13, 64)
249 if rbc.error_code != NX_ZLIB_ERR_BAD_CHECK { return 30 }
250
251 // ---- Preset dictionary (FDICT bit set) refused ----
252 let preset: *u8 = (sys_mmap(13)) as *u8
253 var p: nx_int = 0
254 while p < 13 {
255 preset[p] = stream2[p]
256 p = p + 1
257 }
258 // FDICT = 1, FLEVEL = 0; need to recompute FCHECK so 31-mod passes.
259 // CMF*256 + FLG; with FDICT bit set, FLG = 32 + FCHECK.
260 // (30720 + 32 + FCHECK) % 31 == 0 -> (30752 + FCHECK) % 31 == 0
261 // 30752 % 31 = ? 30752 / 31 = 991.9.. -> 991*31 = 30721; remainder 31; mod 31 = 0.
262 // So FCHECK = 0 gives (30752) % 31 = 0. FLG = 32.
263 preset[1] = 0x20 as u8
264 let rpd: *NxZlibResult = nx_zlib_inflate(preset, 13, 64)
265 if rpd.error_code != NX_ZLIB_ERR_PRESET_DICT { return 40 }
266
267 // ---- Adler mismatch ----
268 let bad_adler: *u8 = (sys_mmap(13)) as *u8
269 var m: nx_int = 0
270 while m < 13 {
271 bad_adler[m] = stream2[m]
272 m = m + 1
273 }
274 bad_adler[12] = 0x00 as u8 // corrupt trailer
275 let rba: *NxZlibResult = nx_zlib_inflate(bad_adler, 13, 64)
276 if rba.error_code != NX_ZLIB_ERR_ADLER_MISMATCH { return 50 }
277
278 // ---- Too-short input ----
279 let too_short: *u8 = (sys_mmap(4)) as *u8
280 let rts: *NxZlibResult = nx_zlib_inflate(too_short, 4, 64)
281 if rts.error_code != NX_ZLIB_ERR_TOO_SHORT { return 60 }
282
283 return 0
284}