nx_hmac_drbg_wasm.nx source
↩ module page · 455 lines · 17683 B
1// nx_hmac_drbg_wasm.nx -- HMAC-DRBG with SHA-256 per NIST SP 800-90A §10.1.2.
2//
3// State: K (32 B), V (32 B).
4//
5// Update(provided_data):
6// K = HMAC(K, V || 0x00 || provided_data)
7// V = HMAC(K, V)
8// if provided_data is empty: return
9// K = HMAC(K, V || 0x01 || provided_data)
10// V = HMAC(K, V)
11//
12// Instantiate(entropy, nonce, personalisation):
13// K = 32 zero bytes
14// V = 32 0x01 bytes
15// Update(entropy || nonce || personalisation)
16//
17// Reseed(entropy, additional_input):
18// Update(entropy || additional_input)
19//
20// Generate(N, additional_input):
21// if additional_input non-empty: Update(additional_input)
22// tmp = ""
23// while len(tmp) < N:
24// V = HMAC(K, V)
25// tmp = tmp || V
26// Update(additional_input) -- this is required even when
27// additional_input was empty
28// return tmp[:N]
29//
30// API for the embedder (each takes a 64-byte state buffer = K || V):
31//
32// nx_drbg_instantiate(state_ptr,
33// entropy_ptr, entropy_len,
34// nonce_ptr, nonce_len,
35// person_ptr, person_len,
36// scratch_ptr) -> i64
37// nx_drbg_reseed(state_ptr, entropy_ptr, entropy_len,
38// addl_ptr, addl_len, scratch_ptr) -> i64
39// nx_drbg_generate(state_ptr, out_ptr, out_len,
40// addl_ptr, addl_len, scratch_ptr) -> i64
41//
42// scratch_ptr must be >= 2048 bytes (HMAC inner scratch + concat
43// staging space).
44//
45// Per NIST SP 800-90A §10.1.2, max bits per Generate call = 2^19 bits
46// = 65536 bytes; max calls before reseed = 2^48. We enforce neither
47// at the WASM layer (caller's responsibility).
48//
49// license_tier: INDEPENDENT_REDERIVE
50// genealogy_id: international-research-sources/nist/sp_800_90a +
51// ietf/rfc_2104
52// lineage_id: nishi_hmac_drbg_wasm_q11
53
54const M32: i64 = 0xFFFFFFFF
55const HMAC_B: i64 = 64
56
57// ---- SHA-256 + HMAC helpers (same self-contained pattern) ----
58
59func _rotr32(x: i64, n: i64) -> i64 {
60 let nn: i64 = n & 31
61 let low: i64 = (x >> nn) & M32
62 let high: i64 = (x << (32 - nn)) & M32
63 return (low | high) & M32
64}
65
66func _sha256_k(i: i64) -> i64 {
67 if i == 0 { return 0x428a2f98 } if i == 1 { return 0x71374491 }
68 if i == 2 { return 0xb5c0fbcf } if i == 3 { return 0xe9b5dba5 }
69 if i == 4 { return 0x3956c25b } if i == 5 { return 0x59f111f1 }
70 if i == 6 { return 0x923f82a4 } if i == 7 { return 0xab1c5ed5 }
71 if i == 8 { return 0xd807aa98 } if i == 9 { return 0x12835b01 }
72 if i == 10 { return 0x243185be } if i == 11 { return 0x550c7dc3 }
73 if i == 12 { return 0x72be5d74 } if i == 13 { return 0x80deb1fe }
74 if i == 14 { return 0x9bdc06a7 } if i == 15 { return 0xc19bf174 }
75 if i == 16 { return 0xe49b69c1 } if i == 17 { return 0xefbe4786 }
76 if i == 18 { return 0x0fc19dc6 } if i == 19 { return 0x240ca1cc }
77 if i == 20 { return 0x2de92c6f } if i == 21 { return 0x4a7484aa }
78 if i == 22 { return 0x5cb0a9dc } if i == 23 { return 0x76f988da }
79 if i == 24 { return 0x983e5152 } if i == 25 { return 0xa831c66d }
80 if i == 26 { return 0xb00327c8 } if i == 27 { return 0xbf597fc7 }
81 if i == 28 { return 0xc6e00bf3 } if i == 29 { return 0xd5a79147 }
82 if i == 30 { return 0x06ca6351 } if i == 31 { return 0x14292967 }
83 if i == 32 { return 0x27b70a85 } if i == 33 { return 0x2e1b2138 }
84 if i == 34 { return 0x4d2c6dfc } if i == 35 { return 0x53380d13 }
85 if i == 36 { return 0x650a7354 } if i == 37 { return 0x766a0abb }
86 if i == 38 { return 0x81c2c92e } if i == 39 { return 0x92722c85 }
87 if i == 40 { return 0xa2bfe8a1 } if i == 41 { return 0xa81a664b }
88 if i == 42 { return 0xc24b8b70 } if i == 43 { return 0xc76c51a3 }
89 if i == 44 { return 0xd192e819 } if i == 45 { return 0xd6990624 }
90 if i == 46 { return 0xf40e3585 } if i == 47 { return 0x106aa070 }
91 if i == 48 { return 0x19a4c116 } if i == 49 { return 0x1e376c08 }
92 if i == 50 { return 0x2748774c } if i == 51 { return 0x34b0bcb5 }
93 if i == 52 { return 0x391c0cb3 } if i == 53 { return 0x4ed8aa4a }
94 if i == 54 { return 0x5b9cca4f } if i == 55 { return 0x682e6ff3 }
95 if i == 56 { return 0x748f82ee } if i == 57 { return 0x78a5636f }
96 if i == 58 { return 0x84c87814 } if i == 59 { return 0x8cc70208 }
97 if i == 60 { return 0x90befffa } if i == 61 { return 0xa4506ceb }
98 if i == 62 { return 0xbef9a3f7 }
99 return 0xc67178f2
100}
101
102func _blk_word_be(ctx_ptr: *u8, off: i64) -> i64 {
103 let b0: i64 = ctx_ptr[off]
104 let b1: i64 = ctx_ptr[off + 1]
105 let b2: i64 = ctx_ptr[off + 2]
106 let b3: i64 = ctx_ptr[off + 3]
107 return ((b0 << 24) | (b1 << 16) | (b2 << 8) | b3) & M32
108}
109
110func _h_get(ctx_ptr: *u8, i: i64) -> i64 {
111 let off: i64 = 64 + i * 4
112 let b0: i64 = ctx_ptr[off]
113 let b1: i64 = ctx_ptr[off + 1]
114 let b2: i64 = ctx_ptr[off + 2]
115 let b3: i64 = ctx_ptr[off + 3]
116 return (b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)) & M32
117}
118func _h_set(ctx_ptr: *u8, i: i64, v: i64) -> i64 {
119 let off: i64 = 64 + i * 4
120 ctx_ptr[off] = v & 0xFF
121 ctx_ptr[off + 1] = (v >> 8) & 0xFF
122 ctx_ptr[off + 2] = (v >> 16) & 0xFF
123 ctx_ptr[off + 3] = (v >> 24) & 0xFF
124 return 0
125}
126
127func _sha256_compress(ctx_ptr: *u8) -> i64 {
128 var i: i64 = 0
129 while i < 16 {
130 let w: i64 = _blk_word_be(ctx_ptr, i * 4)
131 let woff: i64 = 105 + i * 4
132 ctx_ptr[woff] = w & 0xFF
133 ctx_ptr[woff + 1] = (w >> 8) & 0xFF
134 ctx_ptr[woff + 2] = (w >> 16) & 0xFF
135 ctx_ptr[woff + 3] = (w >> 24) & 0xFF
136 i = i + 1
137 }
138 i = 16
139 while i < 64 {
140 let w_2_o: i64 = 105 + (i - 2) * 4
141 let w_15_o: i64 = 105 + (i - 15) * 4
142 let w_7_o: i64 = 105 + (i - 7) * 4
143 let w_16_o: i64 = 105 + (i - 16) * 4
144 let w_2: i64 = (ctx_ptr[w_2_o] as i64) | ((ctx_ptr[w_2_o+1] as i64) << 8) |
145 ((ctx_ptr[w_2_o+2] as i64) << 16) | ((ctx_ptr[w_2_o+3] as i64) << 24)
146 let w_15: i64 = (ctx_ptr[w_15_o] as i64) | ((ctx_ptr[w_15_o+1] as i64) << 8) |
147 ((ctx_ptr[w_15_o+2] as i64) << 16) | ((ctx_ptr[w_15_o+3] as i64) << 24)
148 let w_7: i64 = (ctx_ptr[w_7_o] as i64) | ((ctx_ptr[w_7_o+1] as i64) << 8) |
149 ((ctx_ptr[w_7_o+2] as i64) << 16) | ((ctx_ptr[w_7_o+3] as i64) << 24)
150 let w_16: i64 = (ctx_ptr[w_16_o] as i64) | ((ctx_ptr[w_16_o+1] as i64) << 8) |
151 ((ctx_ptr[w_16_o+2] as i64) << 16) | ((ctx_ptr[w_16_o+3] as i64) << 24)
152 let s0: i64 = _rotr32(w_15, 7) ^ _rotr32(w_15, 18) ^ ((w_15 >> 3) & M32)
153 let s1: i64 = _rotr32(w_2, 17) ^ _rotr32(w_2, 19) ^ ((w_2 >> 10) & M32)
154 let wi: i64 = ((w_16 + s0 + w_7 + s1) as i64) & M32
155 let woff: i64 = 105 + i * 4
156 ctx_ptr[woff] = wi & 0xFF
157 ctx_ptr[woff + 1] = (wi >> 8) & 0xFF
158 ctx_ptr[woff + 2] = (wi >> 16) & 0xFF
159 ctx_ptr[woff + 3] = (wi >> 24) & 0xFF
160 i = i + 1
161 }
162 var a: i64 = _h_get(ctx_ptr, 0)
163 var b: i64 = _h_get(ctx_ptr, 1)
164 var c: i64 = _h_get(ctx_ptr, 2)
165 var d: i64 = _h_get(ctx_ptr, 3)
166 var e: i64 = _h_get(ctx_ptr, 4)
167 var f: i64 = _h_get(ctx_ptr, 5)
168 var g: i64 = _h_get(ctx_ptr, 6)
169 var h: i64 = _h_get(ctx_ptr, 7)
170 i = 0
171 while i < 64 {
172 let woff: i64 = 105 + i * 4
173 let w: i64 = (ctx_ptr[woff] as i64) | ((ctx_ptr[woff+1] as i64) << 8) |
174 ((ctx_ptr[woff+2] as i64) << 16) | ((ctx_ptr[woff+3] as i64) << 24)
175 let s1: i64 = _rotr32(e, 6) ^ _rotr32(e, 11) ^ _rotr32(e, 25)
176 let ch: i64 = ((e & f) ^ ((~e) & g & M32)) & M32
177 let temp1: i64 = (h + s1 + ch + _sha256_k(i) + w) & M32
178 let s0: i64 = _rotr32(a, 2) ^ _rotr32(a, 13) ^ _rotr32(a, 22)
179 let maj: i64 = ((a & b) ^ (a & c) ^ (b & c)) & M32
180 let temp2: i64 = (s0 + maj) & M32
181 h = g; g = f; f = e
182 e = (d + temp1) & M32
183 d = c; c = b; b = a
184 a = (temp1 + temp2) & M32
185 i = i + 1
186 }
187 _h_set(ctx_ptr, 0, (_h_get(ctx_ptr, 0) + a) & M32)
188 _h_set(ctx_ptr, 1, (_h_get(ctx_ptr, 1) + b) & M32)
189 _h_set(ctx_ptr, 2, (_h_get(ctx_ptr, 2) + c) & M32)
190 _h_set(ctx_ptr, 3, (_h_get(ctx_ptr, 3) + d) & M32)
191 _h_set(ctx_ptr, 4, (_h_get(ctx_ptr, 4) + e) & M32)
192 _h_set(ctx_ptr, 5, (_h_get(ctx_ptr, 5) + f) & M32)
193 _h_set(ctx_ptr, 6, (_h_get(ctx_ptr, 6) + g) & M32)
194 _h_set(ctx_ptr, 7, (_h_get(ctx_ptr, 7) + h) & M32)
195 return 0
196}
197
198func _sha256_one_shot(in_ptr: *u8, in_len: i64, ctx_ptr: *u8, out_ptr: *u8) -> i64 {
199 _h_set(ctx_ptr, 0, 0x6a09e667)
200 _h_set(ctx_ptr, 1, 0xbb67ae85)
201 _h_set(ctx_ptr, 2, 0x3c6ef372)
202 _h_set(ctx_ptr, 3, 0xa54ff53a)
203 _h_set(ctx_ptr, 4, 0x510e527f)
204 _h_set(ctx_ptr, 5, 0x9b05688c)
205 _h_set(ctx_ptr, 6, 0x1f83d9ab)
206 _h_set(ctx_ptr, 7, 0x5be0cd19)
207 var idx: i64 = 0
208 var bit_len: i64 = 0
209 var i: i64 = 0
210 while i < in_len {
211 ctx_ptr[idx] = in_ptr[i]
212 idx = idx + 1
213 bit_len = bit_len + 8
214 if idx == 64 {
215 _sha256_compress(ctx_ptr)
216 idx = 0
217 }
218 i = i + 1
219 }
220 ctx_ptr[idx] = 0x80
221 idx = idx + 1
222 if idx > 56 {
223 while idx < 64 { ctx_ptr[idx] = 0; idx = idx + 1 }
224 _sha256_compress(ctx_ptr)
225 idx = 0
226 }
227 while idx < 56 { ctx_ptr[idx] = 0; idx = idx + 1 }
228 ctx_ptr[56] = (bit_len >> 56) & 0xFF
229 ctx_ptr[57] = (bit_len >> 48) & 0xFF
230 ctx_ptr[58] = (bit_len >> 40) & 0xFF
231 ctx_ptr[59] = (bit_len >> 32) & 0xFF
232 ctx_ptr[60] = (bit_len >> 24) & 0xFF
233 ctx_ptr[61] = (bit_len >> 16) & 0xFF
234 ctx_ptr[62] = (bit_len >> 8) & 0xFF
235 ctx_ptr[63] = bit_len & 0xFF
236 _sha256_compress(ctx_ptr)
237 var k: i64 = 0
238 while k < 8 {
239 let hv: i64 = _h_get(ctx_ptr, k)
240 out_ptr[k * 4] = (hv >> 24) & 0xFF
241 out_ptr[k * 4 + 1] = (hv >> 16) & 0xFF
242 out_ptr[k * 4 + 2] = (hv >> 8) & 0xFF
243 out_ptr[k * 4 + 3] = hv & 0xFF
244 k = k + 1
245 }
246 return 0
247}
248
249// HMAC-SHA-256 used internally.
250// scratch layout: same as nx_hmac_sha256_wasm; needs >= 1024 bytes.
251func _hmac_sha256(key_ptr: *u8, key_len: i64, msg_ptr: *u8, msg_len: i64,
252 scratch_ptr: *u8, out_ptr: *u8) -> i64 {
253 let kprime: *u8 = scratch_ptr
254 var j: i64 = 0
255 while j < HMAC_B { kprime[j] = 0; j = j + 1 }
256 if key_len > HMAC_B {
257 let h_ctx: *u8 = (scratch_ptr as i64 + 256) as *u8
258 _sha256_one_shot(key_ptr, key_len, h_ctx, kprime)
259 } else {
260 var ki: i64 = 0
261 while ki < key_len { kprime[ki] = key_ptr[ki]; ki = ki + 1 }
262 }
263 let ipad_blk: *u8 = (scratch_ptr as i64 + 64) as *u8
264 var ii: i64 = 0
265 while ii < HMAC_B { ipad_blk[ii] = kprime[ii] ^ 0x36; ii = ii + 1 }
266 let opad_blk: *u8 = (scratch_ptr as i64 + 128) as *u8
267 var oi: i64 = 0
268 while oi < HMAC_B { opad_blk[oi] = kprime[oi] ^ 0x5c; oi = oi + 1 }
269 let inner_ctx: *u8 = (scratch_ptr as i64 + 256) as *u8
270 _h_set(inner_ctx, 0, 0x6a09e667)
271 _h_set(inner_ctx, 1, 0xbb67ae85)
272 _h_set(inner_ctx, 2, 0x3c6ef372)
273 _h_set(inner_ctx, 3, 0xa54ff53a)
274 _h_set(inner_ctx, 4, 0x510e527f)
275 _h_set(inner_ctx, 5, 0x9b05688c)
276 _h_set(inner_ctx, 6, 0x1f83d9ab)
277 _h_set(inner_ctx, 7, 0x5be0cd19)
278 var inner_idx: i64 = 0
279 var inner_bits: i64 = 0
280 var ip: i64 = 0
281 while ip < HMAC_B {
282 inner_ctx[inner_idx] = ipad_blk[ip]
283 inner_idx = inner_idx + 1
284 inner_bits = inner_bits + 8
285 if inner_idx == 64 { _sha256_compress(inner_ctx); inner_idx = 0 }
286 ip = ip + 1
287 }
288 var mp: i64 = 0
289 while mp < msg_len {
290 inner_ctx[inner_idx] = msg_ptr[mp]
291 inner_idx = inner_idx + 1
292 inner_bits = inner_bits + 8
293 if inner_idx == 64 { _sha256_compress(inner_ctx); inner_idx = 0 }
294 mp = mp + 1
295 }
296 inner_ctx[inner_idx] = 0x80
297 inner_idx = inner_idx + 1
298 if inner_idx > 56 {
299 while inner_idx < 64 { inner_ctx[inner_idx] = 0; inner_idx = inner_idx + 1 }
300 _sha256_compress(inner_ctx)
301 inner_idx = 0
302 }
303 while inner_idx < 56 { inner_ctx[inner_idx] = 0; inner_idx = inner_idx + 1 }
304 inner_ctx[56] = (inner_bits >> 56) & 0xFF
305 inner_ctx[57] = (inner_bits >> 48) & 0xFF
306 inner_ctx[58] = (inner_bits >> 40) & 0xFF
307 inner_ctx[59] = (inner_bits >> 32) & 0xFF
308 inner_ctx[60] = (inner_bits >> 24) & 0xFF
309 inner_ctx[61] = (inner_bits >> 16) & 0xFF
310 inner_ctx[62] = (inner_bits >> 8) & 0xFF
311 inner_ctx[63] = inner_bits & 0xFF
312 _sha256_compress(inner_ctx)
313 let inner_out: *u8 = (scratch_ptr as i64 + 192) as *u8
314 var dk: i64 = 0
315 while dk < 8 {
316 let hv: i64 = _h_get(inner_ctx, dk)
317 inner_out[dk * 4] = (hv >> 24) & 0xFF
318 inner_out[dk * 4 + 1] = (hv >> 16) & 0xFF
319 inner_out[dk * 4 + 2] = (hv >> 8) & 0xFF
320 inner_out[dk * 4 + 3] = hv & 0xFF
321 dk = dk + 1
322 }
323 let outer_in: *u8 = (scratch_ptr as i64 + 768) as *u8
324 var op: i64 = 0
325 while op < HMAC_B { outer_in[op] = opad_blk[op]; op = op + 1 }
326 var ohi: i64 = 0
327 while ohi < 32 { outer_in[HMAC_B + ohi] = inner_out[ohi]; ohi = ohi + 1 }
328 _sha256_one_shot(outer_in, HMAC_B + 32, inner_ctx, out_ptr)
329 return 0
330}
331
332// ---- DRBG state helpers ----
333// state[0..31] = K
334// state[32..63] = V
335
336// Internal: Update(provided_data) per SP 800-90A.
337// K = HMAC(K, V || 0x00 || provided_data)
338// V = HMAC(K, V)
339// if pdata empty: return
340// K = HMAC(K, V || 0x01 || provided_data)
341// V = HMAC(K, V)
342//
343// scratch[1024..] is used as the V || tag || pdata concat buffer
344// (must fit V (32) + 1 byte + provided_data; we cap at 8 KiB total
345// which means pdata can be up to ~8 KiB - 33 = 8155 bytes).
346func _drbg_update(state: *u8, pdata: *u8, pdata_len: i64, scratch: *u8) -> i64 {
347 let K: *u8 = state
348 let V: *u8 = (state as i64 + 32) as *u8
349
350 let concat: *u8 = (scratch as i64 + 1024) as *u8
351 // First round: K = HMAC(K, V || 0x00 || pdata)
352 var i: i64 = 0
353 while i < 32 { concat[i] = V[i]; i = i + 1 }
354 concat[32] = 0
355 var p: i64 = 0
356 while p < pdata_len { concat[33 + p] = pdata[p]; p = p + 1 }
357 _hmac_sha256(K, 32, concat, 33 + pdata_len, scratch, K)
358 // V = HMAC(K, V)
359 _hmac_sha256(K, 32, V, 32, scratch, V)
360
361 if pdata_len == 0 { return 0 }
362
363 // Second round: K = HMAC(K, V || 0x01 || pdata)
364 var i2: i64 = 0
365 while i2 < 32 { concat[i2] = V[i2]; i2 = i2 + 1 }
366 concat[32] = 1
367 var p2: i64 = 0
368 while p2 < pdata_len { concat[33 + p2] = pdata[p2]; p2 = p2 + 1 }
369 _hmac_sha256(K, 32, concat, 33 + pdata_len, scratch, K)
370 // V = HMAC(K, V)
371 _hmac_sha256(K, 32, V, 32, scratch, V)
372 return 0
373}
374
375// Public: Instantiate(state, entropy, nonce, personalisation).
376// State must point to >=64 bytes; scratch must point to >=2048 bytes.
377// Per SP 800-90A §10.1.2.3:
378// K = 0x00 * outlen
379// V = 0x01 * outlen
380// seed_material = entropy || nonce || personalisation
381// Update(seed_material)
382func nx_drbg_instantiate(state: *u8,
383 entropy: *u8, entropy_len: i64,
384 nonce: *u8, nonce_len: i64,
385 person: *u8, person_len: i64,
386 scratch: *u8) -> i64 {
387 let K: *u8 = state
388 let V: *u8 = (state as i64 + 32) as *u8
389 var i: i64 = 0
390 while i < 32 { K[i] = 0; V[i] = 1; i = i + 1 }
391
392 // Build seed_material in scratch[1500..] -- separate from the
393 // _drbg_update concat buffer (which starts at scratch[1024]).
394 let seed: *u8 = (scratch as i64 + 1500) as *u8
395 var sp: i64 = 0
396 var ei: i64 = 0
397 while ei < entropy_len { seed[sp] = entropy[ei]; sp = sp + 1; ei = ei + 1 }
398 var ni: i64 = 0
399 while ni < nonce_len { seed[sp] = nonce[ni]; sp = sp + 1; ni = ni + 1 }
400 var pi: i64 = 0
401 while pi < person_len { seed[sp] = person[pi]; sp = sp + 1; pi = pi + 1 }
402 _drbg_update(state, seed, sp, scratch)
403 return 0
404}
405
406// Public: Reseed(state, entropy, additional_input).
407// Per SP 800-90A §10.1.2.4:
408// seed_material = entropy || additional_input
409// Update(seed_material)
410func nx_drbg_reseed(state: *u8,
411 entropy: *u8, entropy_len: i64,
412 addl: *u8, addl_len: i64,
413 scratch: *u8) -> i64 {
414 let seed: *u8 = (scratch as i64 + 1500) as *u8
415 var sp: i64 = 0
416 var ei: i64 = 0
417 while ei < entropy_len { seed[sp] = entropy[ei]; sp = sp + 1; ei = ei + 1 }
418 var ai: i64 = 0
419 while ai < addl_len { seed[sp] = addl[ai]; sp = sp + 1; ai = ai + 1 }
420 _drbg_update(state, seed, sp, scratch)
421 return 0
422}
423
424// Public: Generate(state, out, out_len, additional_input).
425// Per SP 800-90A §10.1.2.5:
426// if additional_input present: Update(additional_input)
427// tmp = ""
428// while len(tmp) < out_len: V = HMAC(K, V); tmp = tmp || V
429// Update(additional_input)
430// return tmp[:out_len]
431func nx_drbg_generate(state: *u8, out_ptr: *u8, out_len: i64,
432 addl: *u8, addl_len: i64, scratch: *u8) -> i64 {
433 let K: *u8 = state
434 let V: *u8 = (state as i64 + 32) as *u8
435
436 if addl_len > 0 {
437 _drbg_update(state, addl, addl_len, scratch)
438 }
439 var written: i64 = 0
440 while written < out_len {
441 _hmac_sha256(K, 32, V, 32, scratch, V)
442 var take: i64 = 32
443 let remaining: i64 = out_len - written
444 if remaining < 32 { take = remaining }
445 var ti: i64 = 0
446 while ti < take {
447 out_ptr[written + ti] = V[ti]
448 ti = ti + 1
449 }
450 written = written + take
451 }
452 // Always Update with addl_input (even if empty) per §10.1.2.5.
453 _drbg_update(state, addl, addl_len, scratch)
454 return 0
455}