weftcodec 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
weftcodec/frame.py ADDED
@@ -0,0 +1,455 @@
1
+ """WFT1 frame header/table parsing and strict structural validation.
2
+
3
+ Layout (WEFTCODEC-FORMAT §2)::
4
+
5
+ header (96 bytes) || dependency table || chunk table || body || trailer (4)
6
+
7
+ This module parses and validates structure only; payload modes live in
8
+ :mod:`weftcodec.modes`.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from dataclasses import dataclass
14
+
15
+ from .crc32c import crc32c
16
+ from .errors import (
17
+ Corrupt,
18
+ Malformed,
19
+ UnsupportedFeature,
20
+ UnsupportedMode,
21
+ UnsupportedVersion,
22
+ LimitExceeded,
23
+ )
24
+ from .limits import Limits
25
+
26
+ MAGIC = b"WFT1"
27
+ HEADER_LEN = 96
28
+ TRAILER_LEN = 4
29
+ DEP_ENTRY_LEN = 48
30
+ CHUNK_ENTRY_LEN = 48
31
+ HASH_LEN = 32
32
+
33
+ FORMAT_MAJOR = 1
34
+ FORMAT_MINOR = 0
35
+
36
+ DOMAIN_PAYLOAD = 0
37
+ DOMAIN_STRUCTURED = 1
38
+
39
+ DEP_DOMAIN_PAYLOAD = 0
40
+ DEP_DOMAIN_STRUCTURED = 1
41
+ DEP_DOMAIN_DICTIONARY = 2
42
+
43
+ DEP_FLAG_REQUIRED = 0x01
44
+
45
+ FLAG_CHUNKED = 0x0001
46
+ FLAG_SELF_CONTAINED = 0x0002
47
+ FLAG_DICT_RAW = 0x0004
48
+ FLAG_ORIGINAL_HASH = 0x0008
49
+
50
+ FEATURE_DEPENDENCIES = 0x0001
51
+ FEATURE_CHUNK_HASHES = 0x0002
52
+
53
+ MODE_NAMES = {
54
+ 0: "raw",
55
+ 1: "zstd",
56
+ 2: "reference",
57
+ 3: "delta",
58
+ 4: "dictionary",
59
+ 5: "structured",
60
+ 6: "tensor",
61
+ 7: "tokens",
62
+ 8: "quantized_tensor",
63
+ 9: "float_tensor",
64
+ 10: "tensor_sharded",
65
+ 11: "weight_delta",
66
+ 12: "kv_cache",
67
+ 13: "activation_stream",
68
+ 14: "semantic_delta",
69
+ 15: "tensor_tiled",
70
+ 16: "sparse_delta",
71
+ 17: "float_tiled",
72
+ 18: "float_tiled_streams",
73
+ }
74
+
75
+ #: Modes this Python reader can actually materialize plaintext for.
76
+ IMPLEMENTED_MODES = frozenset(MODE_NAMES)
77
+
78
+ #: Modes whose wire value is allocated but not implemented here.
79
+ UNIMPLEMENTED_MODES = frozenset()
80
+
81
+
82
+ @dataclass(frozen=True)
83
+ class Dependency:
84
+ hash: bytes
85
+ decoded_len: int
86
+ dep_domain: int
87
+ dep_flags: int
88
+ codec_hint: int
89
+
90
+
91
+ @dataclass(frozen=True)
92
+ class ChunkEntry:
93
+ encoded_off: int
94
+ encoded_len: int
95
+ decoded_len: int
96
+ hash: bytes
97
+
98
+
99
+ @dataclass(frozen=True)
100
+ class FrameHeader:
101
+ format_major: int
102
+ format_minor: int
103
+ domain: int
104
+ mode: int
105
+ flags: int
106
+ level: int
107
+ decoded_len: int
108
+ body_len: int
109
+ dep_count: int
110
+ chunk_count: int
111
+ features: int
112
+ content_hash: bytes
113
+ table_len: int
114
+
115
+ @property
116
+ def mode_name(self) -> str:
117
+ return MODE_NAMES.get(self.mode, "unknown")
118
+
119
+ @property
120
+ def is_chunked(self) -> bool:
121
+ return bool(self.flags & FLAG_CHUNKED)
122
+
123
+ def flag_names(self) -> "list[str]":
124
+ names = []
125
+ if self.flags & FLAG_CHUNKED:
126
+ names.append("CHUNKED")
127
+ if self.flags & FLAG_SELF_CONTAINED:
128
+ names.append("SELF_CONTAINED")
129
+ if self.flags & FLAG_DICT_RAW:
130
+ names.append("DICT_RAW")
131
+ if self.flags & FLAG_ORIGINAL_HASH:
132
+ names.append("ORIGINAL_HASH")
133
+ return names
134
+
135
+ def feature_names(self) -> "list[str]":
136
+ names = []
137
+ if self.features & FEATURE_DEPENDENCIES:
138
+ names.append("DEPENDENCIES")
139
+ if self.features & FEATURE_CHUNK_HASHES:
140
+ names.append("CHUNK_HASHES")
141
+ return names
142
+
143
+
144
+ @dataclass(frozen=True)
145
+ class Frame:
146
+ header: FrameHeader
147
+ dependencies: "tuple[Dependency, ...]"
148
+ chunks: "tuple[ChunkEntry, ...]"
149
+ body: bytes
150
+ raw: bytes
151
+
152
+
153
+ def _le_u16(data: bytes, offset: int) -> int:
154
+ return int.from_bytes(data[offset : offset + 2], "little")
155
+
156
+
157
+ def _le_u32(data: bytes, offset: int) -> int:
158
+ return int.from_bytes(data[offset : offset + 4], "little")
159
+
160
+
161
+ def _le_u64(data: bytes, offset: int) -> int:
162
+ return int.from_bytes(data[offset : offset + 8], "little")
163
+
164
+
165
+ def _check_len(length: int, maximum: int, what: str) -> None:
166
+ if length > maximum:
167
+ raise LimitExceeded("%s length %d exceeds limit %d" % (what, length, maximum))
168
+
169
+
170
+ def mode_from_u8(value: int) -> int:
171
+ if value in MODE_NAMES:
172
+ return value
173
+ if 17 <= value <= 127:
174
+ raise UnsupportedMode("reserved mode %d is not defined in v1" % value)
175
+ raise UnsupportedMode("experimental mode %d must not be persisted" % value)
176
+
177
+
178
+ def parse(data: bytes, limits: "Limits | None" = None) -> Frame:
179
+ """Parse and fully validate a frame's structure."""
180
+ limits = limits or Limits()
181
+ if len(data) < HEADER_LEN + TRAILER_LEN:
182
+ raise Malformed(
183
+ "frame length %d is below the minimum %d"
184
+ % (len(data), HEADER_LEN + TRAILER_LEN)
185
+ )
186
+ _check_len(len(data), limits.max_frame_bytes, "frame")
187
+
188
+ if data[0:4] != MAGIC:
189
+ raise Malformed("bad frame magic (expected WFT1)")
190
+ format_major = data[4]
191
+ format_minor = data[5]
192
+ if format_major != FORMAT_MAJOR:
193
+ raise UnsupportedVersion("unsupported format major %d" % format_major)
194
+ if format_minor != FORMAT_MINOR:
195
+ raise UnsupportedVersion("unsupported format minor %d" % format_minor)
196
+
197
+ # The header checksum is verified before any length field is trusted.
198
+ stored_header_crc = _le_u32(data, 72)
199
+ if crc32c(data[0:72] + data[76:96]) != stored_header_crc:
200
+ raise Corrupt("header CRC32C mismatch")
201
+
202
+ domain = data[6]
203
+ mode = mode_from_u8(data[7])
204
+ flags = _le_u16(data, 8)
205
+ level = _le_u16(data, 10)
206
+ decoded_len = _le_u64(data, 12)
207
+ body_len = _le_u64(data, 20)
208
+ dep_count = _le_u32(data, 28)
209
+ chunk_count = _le_u32(data, 32)
210
+ feature_bits = _le_u16(data, 36)
211
+ reserved0 = _le_u16(data, 38)
212
+ content_hash = bytes(data[40:72])
213
+ table_len = _le_u64(data, 76)
214
+ reserved1 = _le_u32(data, 84)
215
+ reserved2 = _le_u64(data, 88)
216
+
217
+ if reserved0 != 0 or reserved1 != 0 or reserved2 != 0:
218
+ raise Malformed("reserved header fields must be zero")
219
+ if domain > DOMAIN_STRUCTURED:
220
+ raise Malformed("invalid domain value %d" % domain)
221
+ if flags & ~(FLAG_CHUNKED | FLAG_SELF_CONTAINED | FLAG_DICT_RAW | FLAG_ORIGINAL_HASH):
222
+ raise UnsupportedFeature("unknown critical flag bits 0x%04x" % (flags & ~0x000F))
223
+ if flags & FLAG_ORIGINAL_HASH:
224
+ raise UnsupportedFeature("ORIGINAL_HASH flag is reserved in v1")
225
+ if flags & FLAG_SELF_CONTAINED:
226
+ raise UnsupportedFeature("SELF_CONTAINED is reserved and not produced in v1")
227
+ if feature_bits & ~(FEATURE_DEPENDENCIES | FEATURE_CHUNK_HASHES):
228
+ raise UnsupportedFeature(
229
+ "unknown critical feature bits 0x%04x" % (feature_bits & ~0x0003)
230
+ )
231
+
232
+ _check_len(decoded_len, limits.max_decoded_bytes, "decoded data")
233
+ _check_len(dep_count, limits.max_dependency_count, "dependency count")
234
+ _check_len(chunk_count, limits.max_chunks, "chunk count")
235
+
236
+ expected_table_len = dep_count * DEP_ENTRY_LEN + chunk_count * CHUNK_ENTRY_LEN
237
+ if table_len != expected_table_len:
238
+ raise Malformed(
239
+ "table_len %d does not match %d dependencies and %d chunks"
240
+ % (table_len, dep_count, chunk_count)
241
+ )
242
+
243
+ expected_total = HEADER_LEN + table_len + body_len + TRAILER_LEN
244
+ if expected_total != len(data):
245
+ raise Malformed(
246
+ "frame length %d does not match header-derived length %d"
247
+ % (len(data), expected_total)
248
+ )
249
+
250
+ chunked = bool(flags & FLAG_CHUNKED)
251
+ if chunked:
252
+ if chunk_count == 0:
253
+ raise Malformed("CHUNKED set with an empty chunk table")
254
+ if not feature_bits & FEATURE_CHUNK_HASHES:
255
+ raise Malformed("CHUNKED set without the CHUNK_HASHES feature")
256
+ else:
257
+ if chunk_count != 0:
258
+ raise Malformed("chunk table present without the CHUNKED flag")
259
+ if feature_bits & FEATURE_CHUNK_HASHES:
260
+ raise Malformed("CHUNK_HASHES set without the CHUNKED flag")
261
+ if dep_count > 0 and not feature_bits & FEATURE_DEPENDENCIES:
262
+ raise Malformed("dependency table present without the DEPENDENCIES feature")
263
+
264
+ body_start = HEADER_LEN + table_len
265
+ body_end = body_start + body_len
266
+ body = bytes(data[body_start:body_end])
267
+
268
+ trailer_at = len(data) - TRAILER_LEN
269
+ stored_trailer_crc = _le_u32(data, trailer_at)
270
+ if crc32c(data[:trailer_at]) != stored_trailer_crc:
271
+ raise Corrupt("frame trailer CRC32C mismatch")
272
+
273
+ dependencies = []
274
+ for index in range(dep_count):
275
+ offset = HEADER_LEN + index * DEP_ENTRY_LEN
276
+ dep_hash = bytes(data[offset : offset + HASH_LEN])
277
+ dep_len = _le_u64(data, offset + 32)
278
+ dep_domain = data[offset + 40]
279
+ dep_flags = data[offset + 41]
280
+ reserved = _le_u16(data, offset + 42)
281
+ codec_hint = _le_u32(data, offset + 44)
282
+ if dep_flags & ~DEP_FLAG_REQUIRED:
283
+ raise Malformed("dependency %d has unknown flag bits" % index)
284
+ if not dep_flags & DEP_FLAG_REQUIRED:
285
+ raise Malformed("dependency %d does not set REQUIRED" % index)
286
+ if reserved != 0:
287
+ raise Malformed("dependency %d reserved field must be zero" % index)
288
+ if dep_domain > DEP_DOMAIN_DICTIONARY:
289
+ raise Malformed("dependency %d has invalid domain %d" % (index, dep_domain))
290
+ _check_len(dep_len, limits.max_decoded_bytes, "dependency decoded data")
291
+ dependencies.append(
292
+ Dependency(dep_hash, dep_len, dep_domain, dep_flags, codec_hint)
293
+ )
294
+
295
+ chunk_table_start = HEADER_LEN + dep_count * DEP_ENTRY_LEN
296
+ chunks = []
297
+ for index in range(chunk_count):
298
+ offset = chunk_table_start + index * CHUNK_ENTRY_LEN
299
+ chunks.append(
300
+ ChunkEntry(
301
+ encoded_off=_le_u64(data, offset),
302
+ encoded_len=_le_u32(data, offset + 8),
303
+ decoded_len=_le_u32(data, offset + 12),
304
+ hash=bytes(data[offset + 16 : offset + 48]),
305
+ )
306
+ )
307
+
308
+ if chunked:
309
+ next_offset = 0
310
+ decoded_sum = 0
311
+ for index, chunk in enumerate(chunks):
312
+ if chunk.encoded_off != next_offset:
313
+ raise Malformed(
314
+ "chunk %d starts at %d but expected %d (gap or overlap)"
315
+ % (index, chunk.encoded_off, next_offset)
316
+ )
317
+ if chunk.encoded_len == 0:
318
+ raise Malformed("chunk %d has zero encoded length" % index)
319
+ next_offset += chunk.encoded_len
320
+ decoded_sum += chunk.decoded_len
321
+ if next_offset != body_len:
322
+ raise Malformed(
323
+ "chunk extents end at %d but body_len is %d" % (next_offset, body_len)
324
+ )
325
+ if decoded_sum != decoded_len:
326
+ raise Malformed(
327
+ "chunk decoded lengths sum to %d but decoded_len is %d"
328
+ % (decoded_sum, decoded_len)
329
+ )
330
+
331
+ header = FrameHeader(
332
+ format_major=format_major,
333
+ format_minor=format_minor,
334
+ domain=domain,
335
+ mode=mode,
336
+ flags=flags,
337
+ level=level,
338
+ decoded_len=decoded_len,
339
+ body_len=body_len,
340
+ dep_count=dep_count,
341
+ chunk_count=chunk_count,
342
+ features=feature_bits,
343
+ content_hash=content_hash,
344
+ table_len=table_len,
345
+ )
346
+ _validate_mode_rules(header, dependencies, limits)
347
+ return Frame(header, tuple(dependencies), tuple(chunks), body, bytes(data))
348
+
349
+
350
+ def _validate_mode_rules(
351
+ header: FrameHeader, dependencies: "list[Dependency]", limits: Limits
352
+ ) -> None:
353
+ mode = header.mode
354
+ dict_flag = bool(header.flags & FLAG_DICT_RAW)
355
+
356
+ def payload_domain(what: str) -> None:
357
+ if header.domain != DOMAIN_PAYLOAD:
358
+ raise Malformed("%s frame must use the payload domain" % what)
359
+
360
+ def no_dict(what: str) -> None:
361
+ if dict_flag:
362
+ raise Malformed("DICT_RAW is only valid for DICTIONARY (%s)" % what)
363
+
364
+ if mode == 0: # RAW
365
+ payload_domain("RAW")
366
+ no_dict("RAW")
367
+ if header.dep_count != 0:
368
+ raise Malformed("RAW frame must not have dependencies")
369
+ if header.body_len != header.decoded_len:
370
+ raise Malformed("RAW body_len must equal decoded_len")
371
+ elif mode == 1: # ZSTD
372
+ payload_domain("ZSTD")
373
+ no_dict("ZSTD")
374
+ if header.dep_count != 0:
375
+ raise Malformed("ZSTD frame must not have dependencies in v1")
376
+ elif mode == 2: # REFERENCE
377
+ payload_domain("REFERENCE")
378
+ no_dict("REFERENCE")
379
+ if header.body_len != 0:
380
+ raise Malformed("REFERENCE body must be empty")
381
+ if header.dep_count != 1:
382
+ raise Malformed("REFERENCE requires exactly one dependency")
383
+ if header.chunk_count != 0:
384
+ raise Malformed("REFERENCE must not be chunked")
385
+ if header.decoded_len != dependencies[0].decoded_len:
386
+ raise Malformed(
387
+ "REFERENCE decoded_len must equal dependency decoded_len"
388
+ )
389
+ elif mode == 3: # DELTA
390
+ payload_domain("DELTA")
391
+ no_dict("DELTA")
392
+ if header.dep_count != 1:
393
+ raise Malformed("DELTA requires exactly one dependency")
394
+ if header.chunk_count != 0:
395
+ raise Malformed("DELTA must not be chunked")
396
+ elif mode == 4: # DICTIONARY
397
+ payload_domain("DICTIONARY")
398
+ if not dict_flag:
399
+ raise Malformed("DICTIONARY requires the DICT_RAW flag")
400
+ if header.dep_count != 1:
401
+ raise Malformed("DICTIONARY requires exactly one dependency")
402
+ if dependencies[0].dep_domain != DEP_DOMAIN_DICTIONARY:
403
+ raise Malformed(
404
+ "DICTIONARY dependency must use dep_domain 2 (dictionary bytes)"
405
+ )
406
+ if header.chunk_count != 0:
407
+ raise Malformed("DICTIONARY must not be chunked")
408
+ _check_len(
409
+ dependencies[0].decoded_len,
410
+ limits.max_dictionary_bytes,
411
+ "dictionary",
412
+ )
413
+ elif mode == 5: # STRUCTURED
414
+ if header.domain != DOMAIN_STRUCTURED:
415
+ raise Malformed("STRUCTURED frame must use the structured domain")
416
+ no_dict("STRUCTURED")
417
+ if header.dep_count != 0:
418
+ raise Malformed("STRUCTURED must not have dependencies in v1")
419
+ if header.chunk_count != 0:
420
+ raise Malformed("STRUCTURED must not be chunked")
421
+ if header.body_len != header.decoded_len:
422
+ raise Malformed("STRUCTURED body_len must equal decoded_len")
423
+ elif mode in (6, 7, 8, 9, 10, 12, 13, 15): # AI modes without dependencies
424
+ payload_domain("AI-mode")
425
+ no_dict("AI-mode")
426
+ if header.dep_count != 0:
427
+ raise Malformed("AI-mode frames must not have dependencies in v1")
428
+ if header.chunk_count != 0:
429
+ raise Malformed("AI-mode frames must not be chunked")
430
+ if header.body_len < 4:
431
+ raise Malformed("AI-mode body is shorter than its 4-byte metadata length")
432
+ elif mode in (11, 14, 16): # WEIGHT_DELTA / SEMANTIC_DELTA / SPARSE_DELTA
433
+ name = {
434
+ 11: "WEIGHT_DELTA",
435
+ 14: "SEMANTIC_DELTA",
436
+ 16: "SPARSE_DELTA",
437
+ }[mode]
438
+ payload_domain(name)
439
+ no_dict(name)
440
+ if header.dep_count != 1:
441
+ raise Malformed("%s requires exactly one dependency" % name)
442
+ if header.chunk_count != 0:
443
+ raise Malformed("%s must not be chunked" % name)
444
+ if header.body_len < 4:
445
+ raise Malformed(
446
+ "%s body is shorter than its 4-byte metadata length" % name
447
+ )
448
+ if dependencies[0].dep_domain != DEP_DOMAIN_PAYLOAD:
449
+ raise Malformed(
450
+ "%s dependency must use dep_domain 0 (payload)" % name
451
+ )
452
+ if header.decoded_len != dependencies[0].decoded_len:
453
+ raise Malformed(
454
+ "%s decoded_len must equal the base decoded_len" % name
455
+ )
weftcodec/hashing.py ADDED
@@ -0,0 +1,56 @@
1
+ """Domain-separated BLAKE3-256 hashing (WEFTCODEC-FORMAT §1.1).
2
+
3
+ Exactly one construction is used in v1::
4
+
5
+ H(domain, data) = BLAKE3-256(u32le(|domain|) || domain || data)
6
+
7
+ Domain strings are ASCII, contain no NUL, and are versioned.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from blake3 import blake3
13
+
14
+ HASH_LEN = 32
15
+
16
+ DOMAIN_CHUNK = "weft/chunk/v1"
17
+ DOMAIN_MANIFEST = "weft/manifest/v1"
18
+ DOMAIN_STRUCTURED = "weft/structured/v1"
19
+ DOMAIN_TENSOR_PAYLOAD = "weft/tensor/payload/v1"
20
+ DOMAIN_TOKENS_PAYLOAD = "weft/tokens/payload/v1"
21
+ DOMAIN_QUANTIZED_TENSOR_PAYLOAD = "weft/quantized-tensor/payload/v1"
22
+ DOMAIN_FLOAT_TENSOR_PAYLOAD = "weft/float-tensor/payload/v1"
23
+ DOMAIN_TENSOR_SHARDED_PAYLOAD = "weft/tensor-sharded/payload/v1"
24
+ DOMAIN_TENSOR_VALUES = "weft/tensor/values/v1"
25
+ DOMAIN_TENSOR_LOGICAL = "weft/tensor/logical/v1"
26
+ DOMAIN_TENSOR_TILE = "weft/tensor/tile/v1"
27
+ DOMAIN_TENSOR_FLOAT_TILE = "weft/tensor/float_tile/v1"
28
+ #: Independently decodable multi-stream float-tile identity
29
+ #: (WEFT-AI-CODEC §19).
30
+ DOMAIN_TENSOR_FLOAT_TILE_STREAMS = "weft/tensor/float_tile_streams/v1"
31
+ DOMAIN_TENSOR_SEMANTIC = "weft/tensor/semantic/v1"
32
+ DOMAIN_TENSOR_SEMANTIC_VALUES = "weft/tensor/semantic-values/v1"
33
+ DOMAIN_AI_STREAM = "weft/ai/stream/v1"
34
+
35
+
36
+ def hash_domain(domain: str, data: bytes) -> bytes:
37
+ """Return the 32-byte domain-separated digest."""
38
+ raw = domain.encode("ascii")
39
+ hasher = blake3()
40
+ hasher.update(len(raw).to_bytes(4, "little"))
41
+ hasher.update(raw)
42
+ hasher.update(data)
43
+ return hasher.digest()
44
+
45
+
46
+ def hash_domain_hex(domain: str, data: bytes) -> str:
47
+ return hash_domain(domain, data).hex()
48
+
49
+
50
+ def content_root(data: bytes) -> bytes:
51
+ """``H("weft/chunk/v1", data)`` — the content root of plaintext bytes."""
52
+ return hash_domain(DOMAIN_CHUNK, data)
53
+
54
+
55
+ def content_root_hex(data: bytes) -> str:
56
+ return content_root(data).hex()