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