xref: /freebsd/sys/dev/random/fenestrasX/fx_brng.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1a3c41f8bSConrad Meyer /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3a3c41f8bSConrad Meyer  *
4a3c41f8bSConrad Meyer  * Copyright (c) 2019 Conrad Meyer <cem@FreeBSD.org>
5a3c41f8bSConrad Meyer  *
6a3c41f8bSConrad Meyer  * Redistribution and use in source and binary forms, with or without
7a3c41f8bSConrad Meyer  * modification, are permitted provided that the following conditions
8a3c41f8bSConrad Meyer  * are met:
9a3c41f8bSConrad Meyer  * 1. Redistributions of source code must retain the above copyright
10a3c41f8bSConrad Meyer  *    notice, this list of conditions and the following disclaimer.
11a3c41f8bSConrad Meyer  * 2. Redistributions in binary form must reproduce the above copyright
12a3c41f8bSConrad Meyer  *    notice, this list of conditions and the following disclaimer in the
13a3c41f8bSConrad Meyer  *    documentation and/or other materials provided with the distribution.
14a3c41f8bSConrad Meyer  *
15a3c41f8bSConrad Meyer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16a3c41f8bSConrad Meyer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17a3c41f8bSConrad Meyer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18a3c41f8bSConrad Meyer  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19a3c41f8bSConrad Meyer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20a3c41f8bSConrad Meyer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21a3c41f8bSConrad Meyer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22a3c41f8bSConrad Meyer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23a3c41f8bSConrad Meyer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24a3c41f8bSConrad Meyer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25a3c41f8bSConrad Meyer  * SUCH DAMAGE.
26a3c41f8bSConrad Meyer  */
27a3c41f8bSConrad Meyer 
28a3c41f8bSConrad Meyer #include <sys/param.h>
29a3c41f8bSConrad Meyer #include <sys/fail.h>
30a3c41f8bSConrad Meyer #include <sys/limits.h>
31a3c41f8bSConrad Meyer #include <sys/lock.h>
32a3c41f8bSConrad Meyer #include <sys/kernel.h>
33a3c41f8bSConrad Meyer #include <sys/malloc.h>
34a3c41f8bSConrad Meyer #include <sys/mutex.h>
35a3c41f8bSConrad Meyer #include <sys/random.h>
36a3c41f8bSConrad Meyer #include <sys/sdt.h>
37a3c41f8bSConrad Meyer #include <sys/sysctl.h>
38a3c41f8bSConrad Meyer #include <sys/systm.h>
39f8e8a06dSConrad Meyer #include <sys/vdso.h>
40a3c41f8bSConrad Meyer 
41a3c41f8bSConrad Meyer #include <machine/cpu.h>
42a3c41f8bSConrad Meyer 
43a3c41f8bSConrad Meyer #include <dev/random/randomdev.h>
44a3c41f8bSConrad Meyer #include <dev/random/random_harvestq.h>
45a3c41f8bSConrad Meyer #include <dev/random/uint128.h>
46a3c41f8bSConrad Meyer 
47a3c41f8bSConrad Meyer #include <dev/random/fenestrasX/fx_brng.h>
48a3c41f8bSConrad Meyer #include <dev/random/fenestrasX/fx_priv.h>
4910b1a175SConrad Meyer #include <dev/random/fenestrasX/fx_pub.h>
50a3c41f8bSConrad Meyer #include <dev/random/fenestrasX/fx_rng.h>
51a3c41f8bSConrad Meyer 
52a3c41f8bSConrad Meyer /*
53a3c41f8bSConrad Meyer  * Implementation of a buffered RNG, described in § 1.2-1.4 of the whitepaper.
54a3c41f8bSConrad Meyer  */
55a3c41f8bSConrad Meyer 
56a3c41f8bSConrad Meyer /*
57a3c41f8bSConrad Meyer  * Initialize a buffered rng instance (either the static root instance, or a
58a3c41f8bSConrad Meyer  * per-cpu instance on the heap.  Both should be zero initialized before this
59a3c41f8bSConrad Meyer  * routine.
60a3c41f8bSConrad Meyer  */
61a3c41f8bSConrad Meyer void
fxrng_brng_init(struct fxrng_buffered_rng * rng)62a3c41f8bSConrad Meyer fxrng_brng_init(struct fxrng_buffered_rng *rng)
63a3c41f8bSConrad Meyer {
64a3c41f8bSConrad Meyer 	fxrng_rng_init(&rng->brng_rng, rng == &fxrng_root);
65a3c41f8bSConrad Meyer 
66a3c41f8bSConrad Meyer 	/* I.e., the buffer is empty. */
67a3c41f8bSConrad Meyer 	rng->brng_avail_idx = sizeof(rng->brng_buffer);
68a3c41f8bSConrad Meyer 
69a3c41f8bSConrad Meyer 	/*
70a3c41f8bSConrad Meyer 	 * It is fine and correct for brng_generation and brng_buffer to be
71a3c41f8bSConrad Meyer 	 * zero values.
72a3c41f8bSConrad Meyer 	 *
73a3c41f8bSConrad Meyer 	 * brng_prf and brng_generation must be initialized later.
74a3c41f8bSConrad Meyer 	 * Initialization is special for the root BRNG.  PCPU child instances
75a3c41f8bSConrad Meyer 	 * use fxrng_brng_produce_seed_data_internal() below.
76a3c41f8bSConrad Meyer 	 */
77a3c41f8bSConrad Meyer }
78a3c41f8bSConrad Meyer 
79a3c41f8bSConrad Meyer /*
80a3c41f8bSConrad Meyer  * Directly reseed the root BRNG from a first-time entropy source,
81a3c41f8bSConrad Meyer  * incorporating the existing BRNG state.  The main motivation for doing so "is
82a3c41f8bSConrad Meyer  * to ensure that as soon as an entropy source produces data, PRNG output
83a3c41f8bSConrad Meyer  * depends on the data from that source." (§ 3.1)
84a3c41f8bSConrad Meyer  *
85a3c41f8bSConrad Meyer  * The root BRNG is locked on entry and initial keying (brng_generation > 0)
86a3c41f8bSConrad Meyer  * has already been performed.  The root BRNG is unlocked on return.
87a3c41f8bSConrad Meyer  */
88a3c41f8bSConrad Meyer void
fxrng_brng_src_reseed(const struct harvest_event * event)89a3c41f8bSConrad Meyer fxrng_brng_src_reseed(const struct harvest_event *event)
90a3c41f8bSConrad Meyer {
91a3c41f8bSConrad Meyer 	struct fxrng_buffered_rng *rng;
92a3c41f8bSConrad Meyer 
93a3c41f8bSConrad Meyer 	rng = &fxrng_root;
94a3c41f8bSConrad Meyer 	FXRNG_BRNG_ASSERT(rng);
95a3c41f8bSConrad Meyer 	ASSERT_DEBUG(rng->brng_generation > 0, "root RNG not seeded");
96a3c41f8bSConrad Meyer 
97a3c41f8bSConrad Meyer 	fxrng_rng_src_reseed(&rng->brng_rng, event);
98a3c41f8bSConrad Meyer 	FXRNG_BRNG_ASSERT(rng);
99a3c41f8bSConrad Meyer 
100a3c41f8bSConrad Meyer 	/*
101a3c41f8bSConrad Meyer 	 * Bump root generation (which is costly) to force downstream BRNGs to
102a3c41f8bSConrad Meyer 	 * reseed and quickly incorporate the new entropy.  The intuition is
103a3c41f8bSConrad Meyer 	 * that this tradeoff is worth it because new sources show up extremely
104a3c41f8bSConrad Meyer 	 * rarely (limiting cost) and if they can contribute any entropy to a
105a3c41f8bSConrad Meyer 	 * weak state, we want to propagate it to all generators ASAP.
106a3c41f8bSConrad Meyer 	 */
107a3c41f8bSConrad Meyer 	rng->brng_generation++;
108a3c41f8bSConrad Meyer 	atomic_store_rel_64(&fxrng_root_generation, rng->brng_generation);
109f8e8a06dSConrad Meyer 	/* Update VDSO version. */
110f8e8a06dSConrad Meyer 	fxrng_push_seed_generation(rng->brng_generation);
111a3c41f8bSConrad Meyer 	FXRNG_BRNG_UNLOCK(rng);
112a3c41f8bSConrad Meyer }
113a3c41f8bSConrad Meyer 
114a3c41f8bSConrad Meyer /*
115a3c41f8bSConrad Meyer  * Reseed a brng from some amount of pooled entropy (determined in fx_pool.c by
116a3c41f8bSConrad Meyer  * fxent_timer_reseed_npools).  For initial seeding, we pool entropy in a
117a3c41f8bSConrad Meyer  * single pool and use this API as well (fxrng_alg_seeded).
118a3c41f8bSConrad Meyer  */
119a3c41f8bSConrad Meyer void
fxrng_brng_reseed(const void * entr,size_t sz)120a3c41f8bSConrad Meyer fxrng_brng_reseed(const void *entr, size_t sz)
121a3c41f8bSConrad Meyer {
122a3c41f8bSConrad Meyer 	struct fxrng_buffered_rng *rng;
123a3c41f8bSConrad Meyer 
124a3c41f8bSConrad Meyer 	rng = &fxrng_root;
125a3c41f8bSConrad Meyer 	FXRNG_BRNG_LOCK(rng);
126a3c41f8bSConrad Meyer 
127a3c41f8bSConrad Meyer 	fxrng_rng_reseed(&rng->brng_rng, (rng->brng_generation > 0), entr, sz);
128a3c41f8bSConrad Meyer 	FXRNG_BRNG_ASSERT(rng);
129a3c41f8bSConrad Meyer 
130a3c41f8bSConrad Meyer 	rng->brng_generation++;
131a3c41f8bSConrad Meyer 	atomic_store_rel_64(&fxrng_root_generation, rng->brng_generation);
132f8e8a06dSConrad Meyer 	/* Update VDSO version. */
133f8e8a06dSConrad Meyer 	fxrng_push_seed_generation(rng->brng_generation);
134a3c41f8bSConrad Meyer 	FXRNG_BRNG_UNLOCK(rng);
135a3c41f8bSConrad Meyer }
136a3c41f8bSConrad Meyer 
137a3c41f8bSConrad Meyer /*
138f8e8a06dSConrad Meyer  * Sysentvec and VDSO are initialized much later than SI_SUB_RANDOM.  When
139f8e8a06dSConrad Meyer  * they're online, go ahead and push an initial root seed version.
140f8e8a06dSConrad Meyer  * INIT_SYSENTVEC runs at SI_SUB_EXEC:SI_ORDER_ANY, and SI_ORDER_ANY is the
141f8e8a06dSConrad Meyer  * maximum value, so we must run at SI_SUB_EXEC+1.
142f8e8a06dSConrad Meyer  */
143f8e8a06dSConrad Meyer static void
fxrng_vdso_sysinit(void * dummy __unused)144f8e8a06dSConrad Meyer fxrng_vdso_sysinit(void *dummy __unused)
145f8e8a06dSConrad Meyer {
146f8e8a06dSConrad Meyer 	FXRNG_BRNG_LOCK(&fxrng_root);
147f8e8a06dSConrad Meyer 	fxrng_push_seed_generation(fxrng_root.brng_generation);
148f8e8a06dSConrad Meyer 	FXRNG_BRNG_UNLOCK(&fxrng_root);
149f8e8a06dSConrad Meyer }
150f8e8a06dSConrad Meyer SYSINIT(fxrng_vdso, SI_SUB_EXEC + 1, SI_ORDER_ANY, fxrng_vdso_sysinit, NULL);
151f8e8a06dSConrad Meyer 
152f8e8a06dSConrad Meyer /*
153a3c41f8bSConrad Meyer  * Grab some bytes off an initialized, current generation RNG.
154a3c41f8bSConrad Meyer  *
155a3c41f8bSConrad Meyer  * (Does not handle reseeding if our generation is stale.)
156a3c41f8bSConrad Meyer  *
157a3c41f8bSConrad Meyer  * Locking protocol is a bit odd.  The RNG is locked on entrance, but the lock
158a3c41f8bSConrad Meyer  * is dropped on exit.  This avoids holding a lock during expensive and slow
159a3c41f8bSConrad Meyer  * RNG generation.
160a3c41f8bSConrad Meyer  */
161a3c41f8bSConrad Meyer static void
fxrng_brng_getbytes_internal(struct fxrng_buffered_rng * rng,void * buf,size_t nbytes)162a3c41f8bSConrad Meyer fxrng_brng_getbytes_internal(struct fxrng_buffered_rng *rng, void *buf,
163a3c41f8bSConrad Meyer     size_t nbytes)
164a3c41f8bSConrad Meyer {
165a3c41f8bSConrad Meyer 
166a3c41f8bSConrad Meyer 	FXRNG_BRNG_ASSERT(rng);
167a3c41f8bSConrad Meyer 
168a3c41f8bSConrad Meyer 	/* Make the zero request impossible for the rest of the logic. */
169a3c41f8bSConrad Meyer 	if (__predict_false(nbytes == 0)) {
170a3c41f8bSConrad Meyer 		FXRNG_BRNG_UNLOCK(rng);
171a3c41f8bSConrad Meyer 		goto out;
172a3c41f8bSConrad Meyer 	}
173a3c41f8bSConrad Meyer 
174a3c41f8bSConrad Meyer 	/* Fast/easy case: Use some bytes from the buffer. */
175a3c41f8bSConrad Meyer 	if (rng->brng_avail_idx + nbytes <= sizeof(rng->brng_buffer)) {
176a3c41f8bSConrad Meyer 		memcpy(buf, &rng->brng_buffer[rng->brng_avail_idx], nbytes);
177a3c41f8bSConrad Meyer 		explicit_bzero(&rng->brng_buffer[rng->brng_avail_idx], nbytes);
178a3c41f8bSConrad Meyer 		rng->brng_avail_idx += nbytes;
179a3c41f8bSConrad Meyer 		FXRNG_BRNG_UNLOCK(rng);
180a3c41f8bSConrad Meyer 		goto out;
181a3c41f8bSConrad Meyer 	}
182a3c41f8bSConrad Meyer 
183a3c41f8bSConrad Meyer 	/* Buffer case: */
184a3c41f8bSConrad Meyer 	if (nbytes < sizeof(rng->brng_buffer)) {
185a3c41f8bSConrad Meyer 		size_t rem;
186a3c41f8bSConrad Meyer 
187a3c41f8bSConrad Meyer 		/* Drain anything left in the buffer first. */
188a3c41f8bSConrad Meyer 		if (rng->brng_avail_idx < sizeof(rng->brng_buffer)) {
189a3c41f8bSConrad Meyer 			rem = sizeof(rng->brng_buffer) - rng->brng_avail_idx;
190a3c41f8bSConrad Meyer 			ASSERT_DEBUG(nbytes > rem, "invariant");
191a3c41f8bSConrad Meyer 
192a3c41f8bSConrad Meyer 			memcpy(buf, &rng->brng_buffer[rng->brng_avail_idx], rem);
193a3c41f8bSConrad Meyer 
194a3c41f8bSConrad Meyer 			buf = (uint8_t*)buf + rem;
195a3c41f8bSConrad Meyer 			nbytes -= rem;
196a3c41f8bSConrad Meyer 			ASSERT_DEBUG(nbytes != 0, "invariant");
197a3c41f8bSConrad Meyer 		}
198a3c41f8bSConrad Meyer 
199a3c41f8bSConrad Meyer 		/*
200a3c41f8bSConrad Meyer 		 * Partial fill from first buffer, have to rekey and generate a
201a3c41f8bSConrad Meyer 		 * new buffer to do the rest.
202a3c41f8bSConrad Meyer 		 */
203a3c41f8bSConrad Meyer 		fxrng_rng_genrandom_internal(&rng->brng_rng, rng->brng_buffer,
204a3c41f8bSConrad Meyer 		    sizeof(rng->brng_buffer), false);
205a3c41f8bSConrad Meyer 		FXRNG_BRNG_ASSERT(rng);
206a3c41f8bSConrad Meyer 		rng->brng_avail_idx = 0;
207a3c41f8bSConrad Meyer 
208a3c41f8bSConrad Meyer 		memcpy(buf, &rng->brng_buffer[rng->brng_avail_idx], nbytes);
209a3c41f8bSConrad Meyer 		explicit_bzero(&rng->brng_buffer[rng->brng_avail_idx], nbytes);
210a3c41f8bSConrad Meyer 		rng->brng_avail_idx += nbytes;
211a3c41f8bSConrad Meyer 		FXRNG_BRNG_UNLOCK(rng);
212a3c41f8bSConrad Meyer 		goto out;
213a3c41f8bSConrad Meyer 	}
214a3c41f8bSConrad Meyer 
215a3c41f8bSConrad Meyer 	/* Large request; skip the buffer. */
216a3c41f8bSConrad Meyer 	fxrng_rng_genrandom_internal(&rng->brng_rng, buf, nbytes, true);
217a3c41f8bSConrad Meyer 
218a3c41f8bSConrad Meyer out:
219a3c41f8bSConrad Meyer 	FXRNG_BRNG_ASSERT_NOT(rng);
220a3c41f8bSConrad Meyer 	return;
221a3c41f8bSConrad Meyer }
222a3c41f8bSConrad Meyer 
223a3c41f8bSConrad Meyer /*
224a3c41f8bSConrad Meyer  * API to get a new key for a downstream RNG.  Returns the new key in 'buf', as
225a3c41f8bSConrad Meyer  * well as the generator's reseed_generation.
226a3c41f8bSConrad Meyer  *
227a3c41f8bSConrad Meyer  * 'rng' is locked on entry and unlocked on return.
228a3c41f8bSConrad Meyer  *
229a3c41f8bSConrad Meyer  * Only valid after confirming the caller's seed version or reseed_generation
230a3c41f8bSConrad Meyer  * matches roots (or we are root).  (For now, this is only used to reseed the
231a3c41f8bSConrad Meyer  * per-CPU generators from root.)
232a3c41f8bSConrad Meyer  */
233a3c41f8bSConrad Meyer void
fxrng_brng_produce_seed_data_internal(struct fxrng_buffered_rng * rng,void * buf,size_t keysz,uint64_t * seed_generation)234a3c41f8bSConrad Meyer fxrng_brng_produce_seed_data_internal(struct fxrng_buffered_rng *rng,
235a3c41f8bSConrad Meyer     void *buf, size_t keysz, uint64_t *seed_generation)
236a3c41f8bSConrad Meyer {
237a3c41f8bSConrad Meyer 	FXRNG_BRNG_ASSERT(rng);
238a3c41f8bSConrad Meyer 	ASSERT_DEBUG(keysz == FX_CHACHA20_KEYSIZE, "keysz: %zu", keysz);
239a3c41f8bSConrad Meyer 
240a3c41f8bSConrad Meyer 	*seed_generation = rng->brng_generation;
241a3c41f8bSConrad Meyer 	fxrng_brng_getbytes_internal(rng, buf, keysz);
242a3c41f8bSConrad Meyer 	FXRNG_BRNG_ASSERT_NOT(rng);
243a3c41f8bSConrad Meyer }
244a3c41f8bSConrad Meyer 
245a3c41f8bSConrad Meyer /*
246a3c41f8bSConrad Meyer  * Read from an allocated and initialized buffered BRNG.  This a high-level
247a3c41f8bSConrad Meyer  * API, but doesn't handle PCPU BRNG allocation.
248a3c41f8bSConrad Meyer  *
249a3c41f8bSConrad Meyer  * BRNG is locked on entry.  It is unlocked on return.
250a3c41f8bSConrad Meyer  */
251a3c41f8bSConrad Meyer void
fxrng_brng_read(struct fxrng_buffered_rng * rng,void * buf,size_t nbytes)252a3c41f8bSConrad Meyer fxrng_brng_read(struct fxrng_buffered_rng *rng, void *buf, size_t nbytes)
253a3c41f8bSConrad Meyer {
254a3c41f8bSConrad Meyer 	uint8_t newkey[FX_CHACHA20_KEYSIZE];
255a3c41f8bSConrad Meyer 
256a3c41f8bSConrad Meyer 	FXRNG_BRNG_ASSERT(rng);
257a3c41f8bSConrad Meyer 
258a3c41f8bSConrad Meyer 	/* Fast path: there hasn't been a global reseed since last read. */
259a3c41f8bSConrad Meyer 	if (rng->brng_generation == atomic_load_acq_64(&fxrng_root_generation))
260a3c41f8bSConrad Meyer 		goto done_reseeding;
261a3c41f8bSConrad Meyer 
262a3c41f8bSConrad Meyer 	ASSERT(rng != &fxrng_root, "root rng inconsistent seed version");
263a3c41f8bSConrad Meyer 
264a3c41f8bSConrad Meyer 	/*
265a3c41f8bSConrad Meyer 	 * Slow path: We need to rekey from the parent BRNG to incorporate new
266a3c41f8bSConrad Meyer 	 * entropy material.
267a3c41f8bSConrad Meyer 	 *
268a3c41f8bSConrad Meyer 	 * Lock order is always root -> percpu.
269a3c41f8bSConrad Meyer 	 */
270a3c41f8bSConrad Meyer 	FXRNG_BRNG_UNLOCK(rng);
271a3c41f8bSConrad Meyer 	FXRNG_BRNG_LOCK(&fxrng_root);
272a3c41f8bSConrad Meyer 	FXRNG_BRNG_LOCK(rng);
273a3c41f8bSConrad Meyer 
274a3c41f8bSConrad Meyer 	/*
275a3c41f8bSConrad Meyer 	 * If we lost the reseeding race when the lock was dropped, don't
276a3c41f8bSConrad Meyer 	 * duplicate work.
277a3c41f8bSConrad Meyer 	 */
278a3c41f8bSConrad Meyer 	if (__predict_false(rng->brng_generation ==
279a3c41f8bSConrad Meyer 	    atomic_load_acq_64(&fxrng_root_generation))) {
280a3c41f8bSConrad Meyer 		FXRNG_BRNG_UNLOCK(&fxrng_root);
281a3c41f8bSConrad Meyer 		goto done_reseeding;
282a3c41f8bSConrad Meyer 	}
283a3c41f8bSConrad Meyer 
284a3c41f8bSConrad Meyer 	fxrng_brng_produce_seed_data_internal(&fxrng_root, newkey,
285a3c41f8bSConrad Meyer 	    sizeof(newkey), &rng->brng_generation);
286a3c41f8bSConrad Meyer 
287a3c41f8bSConrad Meyer 	FXRNG_BRNG_ASSERT_NOT(&fxrng_root);
288a3c41f8bSConrad Meyer 	FXRNG_BRNG_ASSERT(rng);
289a3c41f8bSConrad Meyer 
290a3c41f8bSConrad Meyer 	fxrng_rng_setkey(&rng->brng_rng, newkey, sizeof(newkey));
291a3c41f8bSConrad Meyer 	explicit_bzero(newkey, sizeof(newkey));
292a3c41f8bSConrad Meyer 
293a3c41f8bSConrad Meyer 	/*
294a3c41f8bSConrad Meyer 	 * A reseed invalidates any previous buffered contents.  Here, we
295a3c41f8bSConrad Meyer 	 * forward the available index to the end of the buffer, i.e., empty.
296a3c41f8bSConrad Meyer 	 * Requests that would use the buffer (< 128 bytes) will refill its
297a3c41f8bSConrad Meyer 	 * contents on demand.
298a3c41f8bSConrad Meyer 	 *
299a3c41f8bSConrad Meyer 	 * It is explicitly ok that we do not zero out any remaining buffer
300a3c41f8bSConrad Meyer 	 * bytes; they will never be handed out to callers, and they reveal
301a3c41f8bSConrad Meyer 	 * nothing about the reseeded key (which came from the root BRNG).
302a3c41f8bSConrad Meyer 	 * (§ 1.3)
303a3c41f8bSConrad Meyer 	 */
304a3c41f8bSConrad Meyer 	rng->brng_avail_idx = sizeof(rng->brng_buffer);
305a3c41f8bSConrad Meyer 
306a3c41f8bSConrad Meyer done_reseeding:
307a3c41f8bSConrad Meyer 	if (rng != &fxrng_root)
308a3c41f8bSConrad Meyer 		FXRNG_BRNG_ASSERT_NOT(&fxrng_root);
309a3c41f8bSConrad Meyer 	FXRNG_BRNG_ASSERT(rng);
310a3c41f8bSConrad Meyer 
311a3c41f8bSConrad Meyer 	fxrng_brng_getbytes_internal(rng, buf, nbytes);
312a3c41f8bSConrad Meyer 	FXRNG_BRNG_ASSERT_NOT(rng);
313a3c41f8bSConrad Meyer }
314