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}