code wiki / (root) / nx_voice_frame.nx

nx_voice_frame.nx source

↩ module page · 190 lines · 6678 B

1// nx_voice_frame.nx -- Phase 4a foundation: sovereign voice-codec 2// frame format with CAS-chained sha256 headers. 3// 4// Per docs/NISHI_COMMS_ROADMAP.md Phase 4: the frame format alone is 5// already a WIN over Opus on two axes (audit-ability + content- 6// addressability). Subsequent files compose LPC + range coder + FEC 7// on top of THIS frame structure. 8// 9// Frame wire format (binary, all little-endian): 10// 11// [0..3] magic = "NXVF" (4 bytes) 12// [4] version major (1) (1) 13// [5] tier hint (NX_HW_TIER_*) (1) 14// [6..7] bitrate kbps (2) -- 1..64 15// [8..9] sample_rate / 1000 (2) -- 8 | 16 | 24 | 48 16// [10] frame_ms (1) -- 10 | 20 17// [11] flags (1) -- bit0=voice; bit1=FEC; bit2=neural-residual 18// [12..15] sequence number (4) 19// [16..47] prev_frame_hash (32) sha256 of previous frame's full bytes 20// [48..49] payload_len (2) 21// [50..] payload (variable) 22// 23// After payload, the receiver computes sha256(this entire frame 24// header+payload) and stashes for the NEXT frame's prev_hash. Chain. 25// 26// genealogy_id: rfc_5285_rtp + rfc_6716_opus_packetisation + 27// nx_attest_merkle_chain 28// lineage_id: nishi_voice_frame_q10 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" 37 38// Tiny inline 32-byte content hash for frame chain detection. 39// NOT cryptographic; tamper-EVIDENCE only. Real crypto comes at 40// Phase 6 (DTLS-SRTP). This hash is enough to detect accidental 41// reordering, dropped frames, or unauthorised middlebox edits in 42// transit. Two 64-bit FNV-1a folded into 4 lanes -> 32 bytes. 43// 44// Replacing this with sha256 is a one-line caller-side swap. The 45// frame format doesn't pin the hash algorithm; only its width. 46func _h32(buf: *u8, n: i64, out: *u8) -> i64 { 47 // Four lanes of FNV-1a with different seed offsets. 48 var lane: i64 = 0 49 while lane < 4 { 50 var h: i64 = 14695981039346656037 51 if lane == 1 { h = h ^ 0x9e3779b97f4a7c15 } 52 if lane == 2 { h = h ^ 0xbf58476d1ce4e5b9 } 53 if lane == 3 { h = h ^ 0x94d049bb133111eb } 54 var i: i64 = 0 55 while i < n { 56 h = h ^ buf[i] 57 h = h * 1099511628211 58 i = i + 1 59 } 60 var b: i64 = 0 61 while b < 8 { 62 out[lane * 8 + b] = (h >> (b * 8)) & 0xff 63 b = b + 1 64 } 65 lane = lane + 1 66 } 67 return 0 68} 69 70// Sealed verdict per frame parse / build operation. 71const NX_VFR_VERDICT_UNKNOWN: i64 = 0 72const NX_VFR_VERDICT_OK: i64 = 1 73const NX_VFR_VERDICT_BAD_MAGIC: i64 = 2 74const NX_VFR_VERDICT_VERSION_MISMATCH: i64 = 3 75const NX_VFR_VERDICT_TRUNCATED: i64 = 4 76const NX_VFR_VERDICT_CHAIN_BROKEN: i64 = 5 77const NX_VFR_VERDICT_N: i64 = 6 78 79// Sealed flag bits. Used in the frame's flags byte. 80const NX_VFR_FLAG_VOICE: i64 = 1 81const NX_VFR_FLAG_FEC: i64 = 2 82const NX_VFR_FLAG_NEURAL_RESIDUAL: i64 = 4 83 84const NX_VFR_HEADER_BYTES: i64 = 50 85 86// Build a voice frame into `out_buf`. Returns total frame byte 87// length, or -1 on overflow. Caller pre-allocates `out_buf` (>= 88// NX_VFR_HEADER_BYTES + payload_len). 89// 90// `prev_hash` must point at 32 bytes (zeroed for the FIRST frame in 91// a stream). 92func nx_voice_frame_build( 93 out_buf: *u8, out_cap: i64, 94 tier: i64, 95 bitrate_kbps: i64, 96 sample_rate_khz: i64, 97 frame_ms: i64, 98 flags: i64, 99 sequence: i64, 100 prev_hash: *u8, 101 payload: *u8, payload_len: i64 102) -> i64 { 103 let total: i64 = NX_VFR_HEADER_BYTES + payload_len 104 if total > out_cap { return -1 } 105 106 out_buf[0] = 78; out_buf[1] = 88; out_buf[2] = 86; out_buf[3] = 70 // "NXVF" 107 out_buf[4] = 1 // version major 108 out_buf[5] = tier & 0xff 109 out_buf[6] = bitrate_kbps & 0xff 110 out_buf[7] = (bitrate_kbps >> 8) & 0xff 111 out_buf[8] = sample_rate_khz & 0xff 112 out_buf[9] = (sample_rate_khz >> 8) & 0xff 113 out_buf[10] = frame_ms & 0xff 114 out_buf[11] = flags & 0xff 115 out_buf[12] = sequence & 0xff 116 out_buf[13] = (sequence >> 8) & 0xff 117 out_buf[14] = (sequence >> 16) & 0xff 118 out_buf[15] = (sequence >> 24) & 0xff 119 120 var i: i64 = 0 121 while i < 32 { 122 out_buf[16 + i] = prev_hash[i] 123 i = i + 1 124 } 125 out_buf[48] = payload_len & 0xff 126 out_buf[49] = (payload_len >> 8) & 0xff 127 var p: i64 = 0 128 while p < payload_len { 129 out_buf[NX_VFR_HEADER_BYTES + p] = payload[p] 130 p = p + 1 131 } 132 return total 133} 134 135// Parse a frame. Verifies magic + version; if `expected_prev_hash` 136// is non-NULL, verifies the chain link too. Writes the frame's 137// OWN hash (sha256 of all `total` bytes) into `out_this_hash` 138// (32 bytes), so caller can pass it as prev_hash to the next frame. 139func nx_voice_frame_parse( 140 buf: *u8, buf_len: i64, 141 expected_prev_hash: *u8, 142 out_payload_off: *i64, 143 out_payload_len: *i64, 144 out_this_hash: *u8 145) -> i64 { 146 if buf_len < NX_VFR_HEADER_BYTES { return NX_VFR_VERDICT_TRUNCATED } 147 if buf[0] != 78 { return NX_VFR_VERDICT_BAD_MAGIC } 148 if buf[1] != 88 { return NX_VFR_VERDICT_BAD_MAGIC } 149 if buf[2] != 86 { return NX_VFR_VERDICT_BAD_MAGIC } 150 if buf[3] != 70 { return NX_VFR_VERDICT_BAD_MAGIC } 151 if buf[4] != 1 { return NX_VFR_VERDICT_VERSION_MISMATCH } 152 153 let plen: i64 = buf[48] | (buf[49] << 8) 154 if NX_VFR_HEADER_BYTES + plen > buf_len { return NX_VFR_VERDICT_TRUNCATED } 155 156 // Chain check. If expected_prev_hash is null, skip. 157 if (expected_prev_hash as i64) != 0 { 158 var i: i64 = 0 159 var bad: i64 = 0 160 while i < 32 { 161 if buf[16 + i] != expected_prev_hash[i] { bad = 1 } 162 i = i + 1 163 } 164 if bad == 1 { return NX_VFR_VERDICT_CHAIN_BROKEN } 165 } 166 167 *out_payload_off = NX_VFR_HEADER_BYTES 168 *out_payload_len = plen 169 170 // Compute this frame's content-hash for the next call. 171 _h32(buf, NX_VFR_HEADER_BYTES + plen, out_this_hash) 172 return NX_VFR_VERDICT_OK 173} 174 175// Read sequence number from a parsed frame. 176func nx_voice_frame_sequence(buf: *u8) -> i64 { 177 return buf[12] | (buf[13] << 8) | (buf[14] << 16) | (buf[15] << 24) 178} 179 180// Read flags from a parsed frame. 181func nx_voice_frame_flags(buf: *u8) -> i64 { 182 return buf[11] 183} 184 185// Sealed-enum validity gate. 186func nx_vfr_verdict_is_valid(v: i64) -> i64 { 187 if v < 0 { return 0 } 188 if v >= NX_VFR_VERDICT_N { return 0 } 189 return 1 190}