code wiki / (root) / nx_hmac_drbg_wasm.nx

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}