code wiki / hub / nx_save_file_format.nx

nx_save_file_format.nx

buildroot/runtime/hub/nx_save_file_format.nx

14415 B374 linesdepth 6pulls 7 transitivereach 0 importersview sourcekind orphan library
docsdependenciesstructsconstsfunctions

about

nx_save_file_format.nx -- NSAV save file format encoder + decoder. V-CLIENT-STORE-1 per NISHI_CLIENT_STORE_CHARTER §2.2 + §8 M1. CARDINAL CONTEXT: per CS-2 client-owned storage cardinal, game saves live on the user's OWN FILESYSTEM, NEVER on substrate servers. This module provides the canonical wire format so saves are: - portable across browsers / devices / save paths (Path A / B / C) - integrity-checked (HMAC-SHA-256 footer detects tampering) - versioned (forward-compat via header version field) - cross-game distinguishable (game_id field; SHA-256 of identifier) - sovereign substrate-canonical (no proprietary blob format) FILE LAYOUT (per charter §2.2): offset 0..4 magic ascii "NSAV" offset 4..6 version u16 BE (V1 = 0x0001) offset 6..8 flags u16 BE (bit 0: encrypted [V+1]; bits 1-15 reserved) offset 8..40 game_id SHA-256("site_id|||game_name") 32 bytes offset 40..48 created_at i64 BE unix seconds since epoch offset 48..56 payload_len i64 BE byte length of payload offset 56..56+payload_len payload (opaque to substrate; game-defined) offset (..)..(..)+32 hmac_sha256 over bytes[0..(end-32)] with file_key = SHA-256("nishi-save|||" || game_id || passphrase) FILE_KEY derivation: HMAC key = SHA-256("nishi-save|||" || game_id || user_passphrase). For unencrypted V1 saves, passphrase = "" (empty); the key still provides integrity binding to game_id so a save for game A cannot be passed off as a save for game B. COMPOSES (per "avoid duplicate primitives" cardinal): nx_hmac hmac_sha256 (RFC 2104) sha256 digest helper for game_id derivation nx_syscalls sys_mmap COMPOSED BY: hub/nx_client_storage_emit V-CLIENT-STORE-3/4 emits JS that serializes/deserializes NSAV via this bench/nx_client_store_smoke V-CLIENT-STORE-6 vector tests

dependencies 3 imports · 0 importers

nx_syscalls.nx nx_hmac.nx sha256.nx nx_save_file_format.nx

imports: nx_syscalls.nxnx_hmac.nxsha256.nx

imported by: nobody (leaf or entry point)

structs

none

consts

60const NX_NSAV_OK: i64 = 0
61const NX_NSAV_BAD_INPUT: i64 = 1360
62const NX_NSAV_BUF_OVERFLOW: i64 = 1361
63const NX_NSAV_MAGIC_MISMATCH: i64 = 1362
64const NX_NSAV_VERSION_UNSUPPORTED: i64 = 1363
65const NX_NSAV_GAME_ID_MISMATCH: i64 = 1364
66const NX_NSAV_HMAC_MISMATCH: i64 = 1365
67const NX_NSAV_TRUNCATED: i64 = 1366
68const NX_NSAV_PAYLOAD_TOO_LARGE: i64 = 1367
69const NX_NSAV_FLAG_UNSUPPORTED: i64 = 1368
72const NX_NSAV_MAGIC_BYTES: i64 = 4
73const NX_NSAV_VERSION_BYTES: i64 = 2
74const NX_NSAV_FLAGS_BYTES: i64 = 2
75const NX_NSAV_GAME_ID_BYTES: i64 = 32
76const NX_NSAV_CREATED_AT_BYTES: i64 = 8
77const NX_NSAV_PAYLOAD_LEN_BYTES: i64 = 8
78const NX_NSAV_HMAC_BYTES: i64 = 32
79const NX_NSAV_HEADER_BYTES: i64 = 56 // sum of fields before payload
80const NX_NSAV_MIN_FILE_BYTES: i64 = 88 // header (56) + min payload (0) + hmac (32)
82const NX_NSAV_OFF_MAGIC: i64 = 0
83const NX_NSAV_OFF_VERSION: i64 = 4
84const NX_NSAV_OFF_FLAGS: i64 = 6
85const NX_NSAV_OFF_GAME_ID: i64 = 8
86const NX_NSAV_OFF_CREATED_AT: i64 = 40
87const NX_NSAV_OFF_PAYLOAD_LEN: i64 = 48
88const NX_NSAV_OFF_PAYLOAD: i64 = 56
90const NX_NSAV_VERSION_V1: i64 = 0x0001
91const NX_NSAV_FLAG_ENCRYPTED: i64 = 0x0001 // V+1
92const NX_NSAV_FLAGS_VALID_MASK: i64 = 0x0000 // V1 supports no flags yet
94const NX_NSAV_MAX_PAYLOAD_BYTES: i64 = 16777216 // 16 MiB; sanity cap
96const NX_NSAV_FILE_KEY_BYTES: i64 = 32

functions

100func _nsav_put_u16_be(out: *u8, v: i64) -> i64
called by 1: nx_nsav_encode
108func _nsav_get_u16_be(b: *u8) -> i64
112func _nsav_put_i64_be(out: *u8, v: i64) -> i64
called by 1: nx_nsav_encode
124func _nsav_get_i64_be(b: *u8) -> i64
144func nx_nsav_derive_game_id(
calls 1: sys_mmap
181func nx_nsav_derive_file_key(
calls 1: sys_mmap
224func nx_nsav_encode(
299func nx_nsav_decode_and_verify(