code wiki / (root) / nx_ws_crypto.nx

nx_ws_crypto.nx source

↩ module page · 226 lines · 6877 B

1// nx_ws_crypto.nx -- minimal SHA-1 + Base64 used by nx_websocket. 2// Standalone copy that imports nx_syscalls_x86_64.nx directly so the 3// x86_64 codec/comms toolchain doesn't pull in the RV64 syscall 4// numbers via runtime/nx_sha1.nx + runtime/nx_base64.nx (which 5// import "nx_syscalls.nx" -- the RV64 file). Same math, same 6// constants; functions renamed `_wsx_*` to avoid symbol collision 7// when both ecosystems coexist in one binary. 8// 9// genealogy_id: rfc_3174_sha1 + rfc_4648_base64 + nx_sha1_q10 + nx_base64_q10 10// lineage_id: nishi_ws_crypto_q10 11 12// nx_safety_envelope: 13// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 14// sil_target: SIL1 15// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 16// verdict: NOT_YET_EVALUATED 17 18import "nx_syscalls_x86_64.nx" 19 20const _WSX_SHA1_H0: i64 = 0x67452301 21const _WSX_SHA1_H1: i64 = 0xEFCDAB89 22const _WSX_SHA1_H2: i64 = 0x98BADCFE 23const _WSX_SHA1_H3: i64 = 0x10325476 24const _WSX_SHA1_H4: i64 = 0xC3D2E1F0 25 26const _WSX_SHA1_K0: i64 = 0x5A827999 27const _WSX_SHA1_K1: i64 = 0x6ED9EBA1 28const _WSX_SHA1_K2: i64 = 0x8F1BBCDC 29const _WSX_SHA1_K3: i64 = 0xCA62C1D6 30 31const _WSX_M32: i64 = 0xFFFFFFFF 32 33func _wsx_rotl(x: i64, k: i64) -> i64 { 34 let x32: i64 = x & _WSX_M32 35 let lo: i64 = (x32 << k) & _WSX_M32 36 // BUG FIX (2026-05-15): original mask `(1 << (32 - k)) - 1` was 37 // inverted -- it kept only the LOW (32 - k) bits of the shifted-down 38 // top, dropping the actual rotated-in bits. Just mask to MASK32 39 // (the shifted-down value is at most 32 bits anyway). 40 let hi: i64 = (x32 >> (32 - k)) & _WSX_M32 41 return lo | hi 42} 43 44func _wsx_sha1_block(buf: *u8, off: i64, state: *i64) -> i64 { 45 let w_raw: *u8 = sys_mmap(80 * 8) 46 let w: *i64 = w_raw as *i64 47 48 var t: i64 = 0 49 while t < 16 { 50 let b0: i64 = buf[off + t * 4] 51 let b1: i64 = buf[off + t * 4 + 1] 52 let b2: i64 = buf[off + t * 4 + 2] 53 let b3: i64 = buf[off + t * 4 + 3] 54 w[t] = ((b0 << 24) | (b1 << 16) | (b2 << 8) | b3) & _WSX_M32 55 t = t + 1 56 } 57 t = 16 58 while t < 80 { 59 let v: i64 = w[t-3] ^ w[t-8] ^ w[t-14] ^ w[t-16] 60 w[t] = _wsx_rotl(v, 1) 61 t = t + 1 62 } 63 64 var a: i64 = state[0] 65 var b: i64 = state[1] 66 var c: i64 = state[2] 67 var d: i64 = state[3] 68 var e: i64 = state[4] 69 70 t = 0 71 while t < 80 { 72 var f: i64 = 0 73 var k: i64 = 0 74 if t < 20 { 75 f = (b & c) | ((b ^ _WSX_M32) & d) 76 k = _WSX_SHA1_K0 77 } 78 if t >= 20 { 79 if t < 40 { 80 f = b ^ c ^ d 81 k = _WSX_SHA1_K1 82 } 83 } 84 if t >= 40 { 85 if t < 60 { 86 f = (b & c) | (b & d) | (c & d) 87 k = _WSX_SHA1_K2 88 } 89 } 90 if t >= 60 { 91 f = b ^ c ^ d 92 k = _WSX_SHA1_K3 93 } 94 95 let temp: i64 = (_wsx_rotl(a, 5) + f + e + k + w[t]) & _WSX_M32 96 e = d 97 d = c 98 c = _wsx_rotl(b, 30) 99 b = a 100 a = temp 101 t = t + 1 102 } 103 104 state[0] = (state[0] + a) & _WSX_M32 105 state[1] = (state[1] + b) & _WSX_M32 106 state[2] = (state[2] + c) & _WSX_M32 107 state[3] = (state[3] + d) & _WSX_M32 108 state[4] = (state[4] + e) & _WSX_M32 109 return 0 110} 111 112func _wsx_if_ge(a: i64, b: i64, v1: i64, v2: i64) -> i64 { 113 if a >= b { return v1 } 114 return v2 115} 116 117// Compute SHA-1 of data[0..n] into out[0..20]. 118func nx_wsx_sha1(data: *u8, n: i64, out: *u8) -> i64 { 119 let state_raw: *u8 = sys_mmap(40) 120 let state: *i64 = state_raw as *i64 121 state[0] = _WSX_SHA1_H0 122 state[1] = _WSX_SHA1_H1 123 state[2] = _WSX_SHA1_H2 124 state[3] = _WSX_SHA1_H3 125 state[4] = _WSX_SHA1_H4 126 127 let full_blocks: i64 = n / 64 128 var i: i64 = 0 129 while i < full_blocks { 130 _wsx_sha1_block(data, i * 64, state) 131 i = i + 1 132 } 133 134 let tail_off: i64 = full_blocks * 64 135 let tail_len: i64 = n - tail_off 136 137 let pad_size: i64 = 128 138 let pad_raw: *u8 = sys_mmap(pad_size) 139 var j: i64 = 0 140 while j < tail_len { 141 pad_raw[j] = data[tail_off + j] 142 j = j + 1 143 } 144 pad_raw[tail_len] = 0x80 145 j = tail_len + 1 146 147 let blocks_needed: i64 = _wsx_if_ge(tail_len + 1, 57, 2, 1) 148 let total_padded: i64 = blocks_needed * 64 149 while j < total_padded - 8 { 150 pad_raw[j] = 0 151 j = j + 1 152 } 153 let bits: i64 = n * 8 154 pad_raw[total_padded - 8] = (bits >> 56) & 0xFF 155 pad_raw[total_padded - 7] = (bits >> 48) & 0xFF 156 pad_raw[total_padded - 6] = (bits >> 40) & 0xFF 157 pad_raw[total_padded - 5] = (bits >> 32) & 0xFF 158 pad_raw[total_padded - 4] = (bits >> 24) & 0xFF 159 pad_raw[total_padded - 3] = (bits >> 16) & 0xFF 160 pad_raw[total_padded - 2] = (bits >> 8) & 0xFF 161 pad_raw[total_padded - 1] = bits & 0xFF 162 163 var bb: i64 = 0 164 while bb < blocks_needed { 165 _wsx_sha1_block(pad_raw, bb * 64, state) 166 bb = bb + 1 167 } 168 169 var w2: i64 = 0 170 while w2 < 5 { 171 out[w2 * 4] = (state[w2] >> 24) & 0xFF 172 out[w2 * 4 + 1] = (state[w2] >> 16) & 0xFF 173 out[w2 * 4 + 2] = (state[w2] >> 8) & 0xFF 174 out[w2 * 4 + 3] = state[w2] & 0xFF 175 w2 = w2 + 1 176 } 177 return 0 178} 179 180// Base64 standard alphabet. 181const _WSX_B64_PAD: i64 = 0x3D 182 183func _wsx_b64_char(n: i64) -> i64 { 184 let v: i64 = n & 0x3F 185 if v < 26 { return 0x41 + v } 186 if v < 52 { return 0x61 + (v - 26) } 187 if v < 62 { return 0x30 + (v - 52) } 188 if v == 62 { return 0x2B } 189 return 0x2F 190} 191 192// Encode `n` bytes from `in_bytes` to `out`; returns written length. 193func nx_wsx_b64_encode(in_bytes: *u8, n: i64, out: *u8) -> i64 { 194 var pos: i64 = 0 195 var out_pos: i64 = 0 196 while pos + 3 <= n { 197 let b0: i64 = in_bytes[pos] 198 let b1: i64 = in_bytes[pos + 1] 199 let b2: i64 = in_bytes[pos + 2] 200 out[out_pos + 0] = _wsx_b64_char((b0 >> 2) & 0x3F) 201 out[out_pos + 1] = _wsx_b64_char(((b0 << 4) | (b1 >> 4)) & 0x3F) 202 out[out_pos + 2] = _wsx_b64_char(((b1 << 2) | (b2 >> 6)) & 0x3F) 203 out[out_pos + 3] = _wsx_b64_char(b2 & 0x3F) 204 pos = pos + 3 205 out_pos = out_pos + 4 206 } 207 let remain: i64 = n - pos 208 if remain == 1 { 209 let b0: i64 = in_bytes[pos] 210 out[out_pos + 0] = _wsx_b64_char((b0 >> 2) & 0x3F) 211 out[out_pos + 1] = _wsx_b64_char((b0 << 4) & 0x3F) 212 out[out_pos + 2] = _WSX_B64_PAD 213 out[out_pos + 3] = _WSX_B64_PAD 214 out_pos = out_pos + 4 215 } 216 if remain == 2 { 217 let b0: i64 = in_bytes[pos] 218 let b1: i64 = in_bytes[pos + 1] 219 out[out_pos + 0] = _wsx_b64_char((b0 >> 2) & 0x3F) 220 out[out_pos + 1] = _wsx_b64_char(((b0 << 4) | (b1 >> 4)) & 0x3F) 221 out[out_pos + 2] = _wsx_b64_char((b1 << 2) & 0x3F) 222 out[out_pos + 3] = _WSX_B64_PAD 223 out_pos = out_pos + 4 224 } 225 return out_pos 226}