code wiki / (root) / nx_blake2b.nx

nx_blake2b.nx source

↩ module page · 696 lines · 24167 B

1// nx_blake2b.nx -- RFC 7693 BLAKE2b-512 hash (variable output length). 2// 3// BLAKE2b is the 64-bit-optimized member of the BLAKE2 family 4// (Aumasson, Neves, Wilcox-O'Hearn, Winnerlein 2013). The 5// substrate brick under nx_argon2id (RFC 9106) and any future 6// nx_blake3 / nx_kangaroo12 work. 7// 8// Per cardinal feedback-bits-up-exceed-never-match: 9// This is the substrate's own BLAKE2b -- not a libsodium binding, 10// not an OpenSSL EVP wrap. The math runs on substrate i64 ops. 11// 12// Per cardinal feedback-no-third-party-trust-native-or-nothing: 13// Validated against RFC 7693 Appendix A KAT byte-exactly. Any 14// change here MUST re-run the KAT smoke. 15// 16// ===== Algorithm summary (RFC 7693 sec 3) ========================= 17// 18// State: 8 x u64 chained hash words h[0..7], initialized to the 19// BLAKE2b IV (= SHA-512 IV: square roots of first 8 primes). 20// 21// Parameter block (8-byte XOR into h[0]): 22// byte 0 : output digest length (1..64) 23// byte 1 : key length (0..64) 24// byte 2 : fanout (1 for sequential) 25// byte 3 : depth (1 for sequential) 26// byte 4-7 : leaf length (0 for sequential) 27// 28// Compression F(h, block, t, last): 29// v[0..7] = h[0..7] 30// v[8..15] = IV[0..7] 31// v[12] ^= t low 64 bits (bytes-so-far including this block) 32// v[13] ^= t high 64 bits (0 in normal usage) 33// v[14] ^= 0xFFFFFFFFFFFFFFFF if last block 34// 35// for r in 0..12: 36// Mix 8 column + 4 diagonal moves per RFC 7693 sec 3.2. 37// 38// h[i] ^= v[i] ^ v[i+8] for i in 0..7 39// 40// G(v, a, b, c, d, x, y): 41// v[a] = v[a] + v[b] + x 42// v[d] = rotr64(v[d] ^ v[a], 32) 43// v[c] = v[c] + v[d] 44// v[b] = rotr64(v[b] ^ v[c], 24) 45// v[a] = v[a] + v[b] + y 46// v[d] = rotr64(v[d] ^ v[a], 16) 47// v[c] = v[c] + v[d] 48// v[b] = rotr64(v[b] ^ v[c], 63) 49// 50// ===== AI / GPU / ASIC stance ===================================== 51// 52// BLAKE2b by itself is NOT memory-hard -- a GPU/ASIC attacker can 53// compute it as fast as a CPU. nx_argon2id (RFC 9106) USES 54// BLAKE2b inside its memory-mixing function to gain the memory 55// hardness; the AI/GPU/ASIC resistance lives there. This file 56// ships the cryptographic core; the memory-hard wrapping lives 57// in nx_argon2id.nx. 58// 59// ===== Caller-owns-memory pattern ================================= 60// 61// Per cardinal feedback-user-owns-every-bit: this library does not 62// call sys_mmap. Caller supplies: 63// - NxBlake2b ctx (13 i64 fields = 104 bytes) 64// - block buffer (128 bytes) 65// - key buffer + key_len (0..64; key bytes for keyed mode) 66// - output buffer + out_len (1..64) 67// 68// license_tier: ORIGINAL 69 70// nx_safety_envelope: 71// intended_use: crypto hash; foundation for password KDF 72// sil_target: SIL2 (algorithm is mature + KAT-verified) 73// evidence: [rfc_7693_kat_abc_byte_exact, 74// rfc_7693_kat_empty_byte_exact] 75// verdict: NOT_YET_EVALUATED (gating: 2 KATs PASS) 76 77// ===== Verdict ==================================================== 78 79const NX_BLAKE2B_OK: i64 = 0 80const NX_BLAKE2B_BAD_OUT_LEN: i64 = 1 81const NX_BLAKE2B_BAD_KEY_LEN: i64 = 2 82const NX_BLAKE2B_BAD_ARG: i64 = 3 83const NX_BLAKE2B_VERDICT_N: i64 = 4 84 85func nx_blake2b_verdict_is_valid(v: i64) -> i64 { 86 if v < 0 { return 0 } 87 if v >= NX_BLAKE2B_VERDICT_N { return 0 } 88 return 1 89} 90 91func nx_blake2b_verdict_name(v: i64) -> *u8 { 92 if v == NX_BLAKE2B_OK { return "OK" } 93 if v == NX_BLAKE2B_BAD_OUT_LEN { return "BAD_OUT_LEN" } 94 if v == NX_BLAKE2B_BAD_KEY_LEN { return "BAD_KEY_LEN" } 95 if v == NX_BLAKE2B_BAD_ARG { return "BAD_ARG" } 96 return "UNKNOWN" 97} 98 99// ===== Constants ================================================== 100 101const NX_BLAKE2B_BLOCK_BYTES: i64 = 128 102const NX_BLAKE2B_OUT_MAX: i64 = 64 103const NX_BLAKE2B_KEY_MAX: i64 = 64 104 105// ===== Context ==================================================== 106 107struct NxBlake2b { 108 h0: i64, h1: i64, h2: i64, h3: i64, 109 h4: i64, h5: i64, h6: i64, h7: i64, 110 t_low: i64, // bytes processed (low 64 bits) 111 t_high: i64, // bytes processed (high 64 bits) 112 buf_filled: i64, // bytes currently buffered (0..128) 113 out_len: i64, // requested output length (1..64) 114 finalized: i64, // 1 once nx_blake2b_final has run 115} 116 117const NX_BLAKE2B_CTX_BYTES: i64 = 104 // 13 i64 fields * 8 118 119// ===== 64-bit primitive ops ======================================= 120 121// Unsigned right shift (no sign extension). 122func _b2b_shr64(x: i64, n: i64) -> i64 { 123 let nn: i64 = n & 63 124 if nn == 0 { return x } 125 let mask_lo: i64 = (1 << (64 - nn)) - 1 126 return (x >> nn) & mask_lo 127} 128 129// Right rotate by n bits (0 < n < 64). 130func _b2b_rotr64(x: i64, n: i64) -> i64 { 131 let nn: i64 = n & 63 132 if nn == 0 { return x } 133 let lo: i64 = _b2b_shr64(x, nn) 134 let hi: i64 = x << (64 - nn) 135 return lo | hi 136} 137 138// Load 8 bytes little-endian from buf+off. 139func _b2b_load_u64_le(buf: *u8, off: i64) -> i64 { 140 let b0: i64 = (buf[off + 0] as i64) & 255 141 let b1: i64 = (buf[off + 1] as i64) & 255 142 let b2: i64 = (buf[off + 2] as i64) & 255 143 let b3: i64 = (buf[off + 3] as i64) & 255 144 let b4: i64 = (buf[off + 4] as i64) & 255 145 let b5: i64 = (buf[off + 5] as i64) & 255 146 let b6: i64 = (buf[off + 6] as i64) & 255 147 let b7: i64 = (buf[off + 7] as i64) & 255 148 return b0 149 | (b1 << 8) 150 | (b2 << 16) 151 | (b3 << 24) 152 | (b4 << 32) 153 | (b5 << 40) 154 | (b6 << 48) 155 | (b7 << 56) 156} 157 158// Store 8 bytes little-endian to buf+off. 159func _b2b_store_u64_le(buf: *u8, off: i64, v: i64) -> i64 { 160 buf[off + 0] = (v & 255) as u8 161 buf[off + 1] = (_b2b_shr64(v, 8) & 255) as u8 162 buf[off + 2] = (_b2b_shr64(v, 16) & 255) as u8 163 buf[off + 3] = (_b2b_shr64(v, 24) & 255) as u8 164 buf[off + 4] = (_b2b_shr64(v, 32) & 255) as u8 165 buf[off + 5] = (_b2b_shr64(v, 40) & 255) as u8 166 buf[off + 6] = (_b2b_shr64(v, 48) & 255) as u8 167 buf[off + 7] = (_b2b_shr64(v, 56) & 255) as u8 168 return 0 169} 170 171// ===== IV ========================================================= 172// 173// SHA-512 IV = fractional parts of square roots of first 8 primes 174// (2, 3, 5, 7, 11, 13, 17, 19), times 2^64. 175 176func _b2b_iv(i: i64) -> i64 { 177 if i == 0 { return 7640891576956012808 } // 0x6a09e667f3bcc908 178 if i == 1 { return -4942790177534073029 } // 0xbb67ae8584caa73b 179 if i == 2 { return 4354685564936845355 } // 0x3c6ef372fe94f82b 180 if i == 3 { return -6534734903238641935 } // 0xa54ff53a5f1d36f1 181 if i == 4 { return 5840696475078001361 } // 0x510e527fade682d1 182 if i == 5 { return -7276294671716946913 } // 0x9b05688c2b3e6c1f 183 if i == 6 { return 2270897969802886507 } // 0x1f83d9abfb41bd6b 184 if i == 7 { return 6620516959819538809 } // 0x5be0cd19137e2179 185 return 0 186} 187 188// ===== SIGMA permutation (RFC 7693 sec 2.7) ======================= 189// 190// 10 rows of 16 indices, indexed by (round mod 10). 191 192func _b2b_sigma(row: i64, col: i64) -> i64 { 193 let rr: i64 = row % 10 194 if rr == 0 { 195 if col == 0 { return 0 } 196 if col == 1 { return 1 } 197 if col == 2 { return 2 } 198 if col == 3 { return 3 } 199 if col == 4 { return 4 } 200 if col == 5 { return 5 } 201 if col == 6 { return 6 } 202 if col == 7 { return 7 } 203 if col == 8 { return 8 } 204 if col == 9 { return 9 } 205 if col == 10 { return 10 } 206 if col == 11 { return 11 } 207 if col == 12 { return 12 } 208 if col == 13 { return 13 } 209 if col == 14 { return 14 } 210 if col == 15 { return 15 } 211 } 212 if rr == 1 { 213 if col == 0 { return 14 } 214 if col == 1 { return 10 } 215 if col == 2 { return 4 } 216 if col == 3 { return 8 } 217 if col == 4 { return 9 } 218 if col == 5 { return 15 } 219 if col == 6 { return 13 } 220 if col == 7 { return 6 } 221 if col == 8 { return 1 } 222 if col == 9 { return 12 } 223 if col == 10 { return 0 } 224 if col == 11 { return 2 } 225 if col == 12 { return 11 } 226 if col == 13 { return 7 } 227 if col == 14 { return 5 } 228 if col == 15 { return 3 } 229 } 230 if rr == 2 { 231 if col == 0 { return 11 } 232 if col == 1 { return 8 } 233 if col == 2 { return 12 } 234 if col == 3 { return 0 } 235 if col == 4 { return 5 } 236 if col == 5 { return 2 } 237 if col == 6 { return 15 } 238 if col == 7 { return 13 } 239 if col == 8 { return 10 } 240 if col == 9 { return 14 } 241 if col == 10 { return 3 } 242 if col == 11 { return 6 } 243 if col == 12 { return 7 } 244 if col == 13 { return 1 } 245 if col == 14 { return 9 } 246 if col == 15 { return 4 } 247 } 248 if rr == 3 { 249 if col == 0 { return 7 } 250 if col == 1 { return 9 } 251 if col == 2 { return 3 } 252 if col == 3 { return 1 } 253 if col == 4 { return 13 } 254 if col == 5 { return 12 } 255 if col == 6 { return 11 } 256 if col == 7 { return 14 } 257 if col == 8 { return 2 } 258 if col == 9 { return 6 } 259 if col == 10 { return 5 } 260 if col == 11 { return 10 } 261 if col == 12 { return 4 } 262 if col == 13 { return 0 } 263 if col == 14 { return 15 } 264 if col == 15 { return 8 } 265 } 266 if rr == 4 { 267 if col == 0 { return 9 } 268 if col == 1 { return 0 } 269 if col == 2 { return 5 } 270 if col == 3 { return 7 } 271 if col == 4 { return 2 } 272 if col == 5 { return 4 } 273 if col == 6 { return 10 } 274 if col == 7 { return 15 } 275 if col == 8 { return 14 } 276 if col == 9 { return 1 } 277 if col == 10 { return 11 } 278 if col == 11 { return 12 } 279 if col == 12 { return 6 } 280 if col == 13 { return 8 } 281 if col == 14 { return 3 } 282 if col == 15 { return 13 } 283 } 284 if rr == 5 { 285 if col == 0 { return 2 } 286 if col == 1 { return 12 } 287 if col == 2 { return 6 } 288 if col == 3 { return 10 } 289 if col == 4 { return 0 } 290 if col == 5 { return 11 } 291 if col == 6 { return 8 } 292 if col == 7 { return 3 } 293 if col == 8 { return 4 } 294 if col == 9 { return 13 } 295 if col == 10 { return 7 } 296 if col == 11 { return 5 } 297 if col == 12 { return 15 } 298 if col == 13 { return 14 } 299 if col == 14 { return 1 } 300 if col == 15 { return 9 } 301 } 302 if rr == 6 { 303 if col == 0 { return 12 } 304 if col == 1 { return 5 } 305 if col == 2 { return 1 } 306 if col == 3 { return 15 } 307 if col == 4 { return 14 } 308 if col == 5 { return 13 } 309 if col == 6 { return 4 } 310 if col == 7 { return 10 } 311 if col == 8 { return 0 } 312 if col == 9 { return 7 } 313 if col == 10 { return 6 } 314 if col == 11 { return 3 } 315 if col == 12 { return 9 } 316 if col == 13 { return 2 } 317 if col == 14 { return 8 } 318 if col == 15 { return 11 } 319 } 320 if rr == 7 { 321 if col == 0 { return 13 } 322 if col == 1 { return 11 } 323 if col == 2 { return 7 } 324 if col == 3 { return 14 } 325 if col == 4 { return 12 } 326 if col == 5 { return 1 } 327 if col == 6 { return 3 } 328 if col == 7 { return 9 } 329 if col == 8 { return 5 } 330 if col == 9 { return 0 } 331 if col == 10 { return 15 } 332 if col == 11 { return 4 } 333 if col == 12 { return 8 } 334 if col == 13 { return 6 } 335 if col == 14 { return 2 } 336 if col == 15 { return 10 } 337 } 338 if rr == 8 { 339 if col == 0 { return 6 } 340 if col == 1 { return 15 } 341 if col == 2 { return 14 } 342 if col == 3 { return 9 } 343 if col == 4 { return 11 } 344 if col == 5 { return 3 } 345 if col == 6 { return 0 } 346 if col == 7 { return 8 } 347 if col == 8 { return 12 } 348 if col == 9 { return 2 } 349 if col == 10 { return 13 } 350 if col == 11 { return 7 } 351 if col == 12 { return 1 } 352 if col == 13 { return 4 } 353 if col == 14 { return 10 } 354 if col == 15 { return 5 } 355 } 356 // rr == 9 357 if col == 0 { return 10 } 358 if col == 1 { return 2 } 359 if col == 2 { return 8 } 360 if col == 3 { return 4 } 361 if col == 4 { return 7 } 362 if col == 5 { return 6 } 363 if col == 6 { return 1 } 364 if col == 7 { return 5 } 365 if col == 8 { return 15 } 366 if col == 9 { return 11 } 367 if col == 10 { return 9 } 368 if col == 11 { return 14 } 369 if col == 12 { return 3 } 370 if col == 13 { return 12 } 371 if col == 14 { return 13 } 372 return 0 373} 374 375// ===== G mix function ============================================= 376// 377// v is a 16-i64 flat array passed as *i64 pointer. 378 379func _b2b_mix(v: *i64, a: i64, b: i64, c: i64, d: i64, 380 x: i64, y: i64) -> i64 { 381 v[a] = v[a] + v[b] + x 382 v[d] = _b2b_rotr64(v[d] ^ v[a], 32) 383 v[c] = v[c] + v[d] 384 v[b] = _b2b_rotr64(v[b] ^ v[c], 24) 385 v[a] = v[a] + v[b] + y 386 v[d] = _b2b_rotr64(v[d] ^ v[a], 16) 387 v[c] = v[c] + v[d] 388 v[b] = _b2b_rotr64(v[b] ^ v[c], 63) 389 return 0 390} 391 392// ===== Compression F ============================================== 393// 394// Compresses one 128-byte block into the chained hash state. 395// Caller must update t_low/t_high BEFORE calling F. 396// 397// Storage for v[16] + m[16] passed via two caller-supplied *i64 398// scratch areas (32 * 8 = 256 bytes total). The substrate avoids 399// stack-array idioms and per-call sys_mmap. 400 401func _b2b_compress(ctx: *NxBlake2b, block: *u8, 402 v: *i64, m: *i64, last: i64) -> i64 { 403 // Load 16 little-endian u64 from block. 404 var i: i64 = 0 405 while i < 16 { 406 m[i] = _b2b_load_u64_le(block, i * 8) 407 i = i + 1 408 } 409 410 // Initialize working state. 411 v[0] = ctx.h0 412 v[1] = ctx.h1 413 v[2] = ctx.h2 414 v[3] = ctx.h3 415 v[4] = ctx.h4 416 v[5] = ctx.h5 417 v[6] = ctx.h6 418 v[7] = ctx.h7 419 v[8] = _b2b_iv(0) 420 v[9] = _b2b_iv(1) 421 v[10] = _b2b_iv(2) 422 v[11] = _b2b_iv(3) 423 v[12] = _b2b_iv(4) ^ ctx.t_low 424 v[13] = _b2b_iv(5) ^ ctx.t_high 425 v[14] = _b2b_iv(6) 426 v[15] = _b2b_iv(7) 427 if last == 1 { 428 v[14] = v[14] ^ -1 // 0xFFFFFFFFFFFFFFFF 429 } 430 431 // 12 rounds. 432 var r: i64 = 0 433 while r < 12 { 434 // Column step 435 _b2b_mix(v, 0, 4, 8, 12, m[_b2b_sigma(r, 0)], m[_b2b_sigma(r, 1)]) 436 _b2b_mix(v, 1, 5, 9, 13, m[_b2b_sigma(r, 2)], m[_b2b_sigma(r, 3)]) 437 _b2b_mix(v, 2, 6, 10, 14, m[_b2b_sigma(r, 4)], m[_b2b_sigma(r, 5)]) 438 _b2b_mix(v, 3, 7, 11, 15, m[_b2b_sigma(r, 6)], m[_b2b_sigma(r, 7)]) 439 // Diagonal step 440 _b2b_mix(v, 0, 5, 10, 15, m[_b2b_sigma(r, 8)], m[_b2b_sigma(r, 9)]) 441 _b2b_mix(v, 1, 6, 11, 12, m[_b2b_sigma(r, 10)], m[_b2b_sigma(r, 11)]) 442 _b2b_mix(v, 2, 7, 8, 13, m[_b2b_sigma(r, 12)], m[_b2b_sigma(r, 13)]) 443 _b2b_mix(v, 3, 4, 9, 14, m[_b2b_sigma(r, 14)], m[_b2b_sigma(r, 15)]) 444 r = r + 1 445 } 446 447 // Finalize -- mix v halves into h. 448 ctx.h0 = ctx.h0 ^ v[0] ^ v[8] 449 ctx.h1 = ctx.h1 ^ v[1] ^ v[9] 450 ctx.h2 = ctx.h2 ^ v[2] ^ v[10] 451 ctx.h3 = ctx.h3 ^ v[3] ^ v[11] 452 ctx.h4 = ctx.h4 ^ v[4] ^ v[12] 453 ctx.h5 = ctx.h5 ^ v[5] ^ v[13] 454 ctx.h6 = ctx.h6 ^ v[6] ^ v[14] 455 ctx.h7 = ctx.h7 ^ v[7] ^ v[15] 456 return 0 457} 458 459// ===== Entry points =============================================== 460 461// nx_blake2b_init(ctx, out_len, key, key_len) -> verdict 462// 463// out_len: 1..64 (RFC 7693 sec 3.1) 464// key_len: 0..64 (0 = unkeyed) 465// key: pointer; ignored when key_len == 0 466// 467// Caller need NOT zero the ctx beforehand. 468 469func nx_blake2b_init(ctx: *NxBlake2b, 470 out_len: i64, 471 key: *u8, key_len: i64, 472 buf128: *u8) -> i64 { 473 if ctx == (0 as *NxBlake2b) { return NX_BLAKE2B_BAD_ARG } 474 if out_len < 1 { return NX_BLAKE2B_BAD_OUT_LEN } 475 if out_len > NX_BLAKE2B_OUT_MAX { return NX_BLAKE2B_BAD_OUT_LEN } 476 if key_len < 0 { return NX_BLAKE2B_BAD_KEY_LEN } 477 if key_len > NX_BLAKE2B_KEY_MAX { return NX_BLAKE2B_BAD_KEY_LEN } 478 if buf128 == (0 as *u8) { return NX_BLAKE2B_BAD_ARG } 479 480 // Initialize h[i] = IV[i]. 481 ctx.h0 = _b2b_iv(0) 482 ctx.h1 = _b2b_iv(1) 483 ctx.h2 = _b2b_iv(2) 484 ctx.h3 = _b2b_iv(3) 485 ctx.h4 = _b2b_iv(4) 486 ctx.h5 = _b2b_iv(5) 487 ctx.h6 = _b2b_iv(6) 488 ctx.h7 = _b2b_iv(7) 489 490 // XOR parameter block bottom 8 bytes into h[0]: 491 // byte 0 = out_len 492 // byte 1 = key_len 493 // byte 2 = fanout = 1 494 // byte 3 = depth = 1 495 // byte 4-7 = leaf length = 0 496 let param: i64 = out_len 497 | (key_len << 8) 498 | (1 << 16) 499 | (1 << 24) 500 ctx.h0 = ctx.h0 ^ param 501 502 ctx.t_low = 0 503 ctx.t_high = 0 504 ctx.buf_filled = 0 505 ctx.out_len = out_len 506 ctx.finalized = 0 507 508 // Keyed mode: pad key to 128 bytes + treat as first message block. 509 if key_len > 0 { 510 var i: i64 = 0 511 while i < 128 { 512 buf128[i] = 0 as u8 513 i = i + 1 514 } 515 var k: i64 = 0 516 while k < key_len { 517 buf128[k] = key[k] 518 k = k + 1 519 } 520 ctx.buf_filled = 128 521 } 522 return NX_BLAKE2B_OK 523} 524 525// nx_blake2b_update(ctx, msg, msg_len, buf128, scratch_v, scratch_m) 526// 527// scratch_v + scratch_m: caller-supplied *i64 with 16 entries each 528// (passed through to _b2b_compress). 529 530func nx_blake2b_update(ctx: *NxBlake2b, 531 msg: *u8, msg_len: i64, 532 buf128: *u8, 533 scratch_v: *i64, scratch_m: *i64) -> i64 { 534 if ctx == (0 as *NxBlake2b) { return NX_BLAKE2B_BAD_ARG } 535 if ctx.finalized == 1 { return NX_BLAKE2B_BAD_ARG } 536 if buf128 == (0 as *u8) { return NX_BLAKE2B_BAD_ARG } 537 if msg_len < 0 { return NX_BLAKE2B_BAD_ARG } 538 if msg_len > 0 { 539 if msg == (0 as *u8) { return NX_BLAKE2B_BAD_ARG } 540 } 541 542 var consumed: i64 = 0 543 while consumed < msg_len { 544 let room: i64 = 128 - ctx.buf_filled 545 let avail: i64 = msg_len - consumed 546 // If we'd fill the buffer AND there are more bytes to come, 547 // flush it via compression FIRST, then keep going. 548 if ctx.buf_filled == 128 { 549 // Increment counter by the 128 bytes about to be hashed 550 // BEFORE compression (RFC 7693 sec 3.2 reads counter inside 551 // F as bytes-so-far including this block). 552 ctx.t_low = ctx.t_low + 128 553 if ctx.t_low == 0 { ctx.t_high = ctx.t_high + 1 } 554 // For our usage t_low < 2^63 always; sign-bit overflow 555 // would require > 8 EiB input. Skip wrap handling. 556 _b2b_compress(ctx, buf128, scratch_v, scratch_m, 0) 557 ctx.buf_filled = 0 558 } 559 // Copy as many bytes as fit (but never the LAST byte unless 560 // we know more is coming, because final() handles last block). 561 let take_max: i64 = 128 - ctx.buf_filled 562 var take: i64 = avail 563 if take > take_max { take = take_max } 564 // We MUST leave at least one byte for the final-block 565 // compression to handle as `last`. So if take fills the 566 // buffer and ALSO consumes all remaining input, hold off 567 // the last byte for final(). But since update doesn't 568 // know if more bytes will arrive in a subsequent update() 569 // call, we leave the trailing block buffered for final(). 570 // Solution: only compress when buffer is FULL AND there 571 // is strictly more input coming in this update(). 572 if take == take_max { 573 if avail > take_max { 574 // More bytes will come this update -- safe to fill + 575 // flush at top of next iteration. 576 var j: i64 = 0 577 while j < take { 578 buf128[ctx.buf_filled + j] = msg[consumed + j] 579 j = j + 1 580 } 581 ctx.buf_filled = ctx.buf_filled + take 582 consumed = consumed + take 583 continue 584 } else { 585 // take fills the buffer AND avail == take_max, so 586 // this is the last byte. Don't compress -- buffer 587 // it for final() which will set last=1. 588 var k: i64 = 0 589 while k < take { 590 buf128[ctx.buf_filled + k] = msg[consumed + k] 591 k = k + 1 592 } 593 ctx.buf_filled = ctx.buf_filled + take 594 consumed = consumed + take 595 continue 596 } 597 } 598 // take < take_max -- partial fill, no compression. 599 var n: i64 = 0 600 while n < take { 601 buf128[ctx.buf_filled + n] = msg[consumed + n] 602 n = n + 1 603 } 604 ctx.buf_filled = ctx.buf_filled + take 605 consumed = consumed + take 606 } 607 return NX_BLAKE2B_OK 608} 609 610// nx_blake2b_final(ctx, out, buf128, scratch_v, scratch_m) 611// 612// Pads the last block with zeros + compresses with last=1, then 613// writes h[0..ceil(out_len/8)] little-endian to out[0..out_len]. 614 615func nx_blake2b_final(ctx: *NxBlake2b, 616 out: *u8, 617 buf128: *u8, 618 scratch_v: *i64, scratch_m: *i64) -> i64 { 619 if ctx == (0 as *NxBlake2b) { return NX_BLAKE2B_BAD_ARG } 620 if out == (0 as *u8) { return NX_BLAKE2B_BAD_ARG } 621 if buf128 == (0 as *u8) { return NX_BLAKE2B_BAD_ARG } 622 if ctx.finalized == 1 { return NX_BLAKE2B_BAD_ARG } 623 624 // Counter += bytes in this final block. 625 ctx.t_low = ctx.t_low + ctx.buf_filled 626 if ctx.t_low < 0 { ctx.t_high = ctx.t_high + 1 } 627 628 // Zero-pad the remainder of buf128. 629 var i: i64 = ctx.buf_filled 630 while i < 128 { 631 buf128[i] = 0 as u8 632 i = i + 1 633 } 634 635 _b2b_compress(ctx, buf128, scratch_v, scratch_m, 1) 636 637 // Write h[0..7] LE into out[]. 638 let words_full: i64 = ctx.out_len / 8 639 let bytes_partial: i64 = ctx.out_len - (words_full * 8) 640 var w: i64 = 0 641 while w < words_full { 642 var hv: i64 = 0 643 if w == 0 { hv = ctx.h0 } 644 if w == 1 { hv = ctx.h1 } 645 if w == 2 { hv = ctx.h2 } 646 if w == 3 { hv = ctx.h3 } 647 if w == 4 { hv = ctx.h4 } 648 if w == 5 { hv = ctx.h5 } 649 if w == 6 { hv = ctx.h6 } 650 if w == 7 { hv = ctx.h7 } 651 _b2b_store_u64_le(out, w * 8, hv) 652 w = w + 1 653 } 654 // Partial trailing word, if out_len % 8 != 0. 655 if bytes_partial > 0 { 656 var tail_word: i64 = 0 657 if words_full == 0 { tail_word = ctx.h0 } 658 if words_full == 1 { tail_word = ctx.h1 } 659 if words_full == 2 { tail_word = ctx.h2 } 660 if words_full == 3 { tail_word = ctx.h3 } 661 if words_full == 4 { tail_word = ctx.h4 } 662 if words_full == 5 { tail_word = ctx.h5 } 663 if words_full == 6 { tail_word = ctx.h6 } 664 if words_full == 7 { tail_word = ctx.h7 } 665 let base: i64 = words_full * 8 666 var b: i64 = 0 667 while b < bytes_partial { 668 out[base + b] = (_b2b_shr64(tail_word, b * 8) & 255) as u8 669 b = b + 1 670 } 671 } 672 673 ctx.finalized = 1 674 return NX_BLAKE2B_OK 675} 676 677// ===== One-shot convenience ======================================= 678// 679// nx_blake2b_hash(msg, msg_len, key, key_len, out, out_len, 680// ctx, buf128, scratch_v, scratch_m) 681// 682// Composes init + update + final using caller-supplied buffers. 683 684func nx_blake2b_hash(msg: *u8, msg_len: i64, 685 key: *u8, key_len: i64, 686 out: *u8, out_len: i64, 687 ctx: *NxBlake2b, 688 buf128: *u8, 689 scratch_v: *i64, scratch_m: *i64) -> i64 { 690 let v1: i64 = nx_blake2b_init(ctx, out_len, key, key_len, buf128) 691 if v1 != NX_BLAKE2B_OK { return v1 } 692 let v2: i64 = nx_blake2b_update(ctx, msg, msg_len, buf128, 693 scratch_v, scratch_m) 694 if v2 != NX_BLAKE2B_OK { return v2 } 695 return nx_blake2b_final(ctx, out, buf128, scratch_v, scratch_m) 696}