Module Name: src
Committed By: tls
Date: Sat Aug 9 06:19:50 UTC 2014
Modified Files:
src/sys/conf [tls-earlyentropy]: files
src/sys/kern [tls-earlyentropy]: subr_cprng.c
src/sys/rump/librump/rumpkern [tls-earlyentropy]: Makefile.rumpkern
src/sys/sys [tls-earlyentropy]: cprng.h rnd.h
src/usr.sbin/npf/npftest/libnpftest [tls-earlyentropy]: npf_test_subr.c
Added Files:
src/sys/crypto/cprng_fast [tls-earlyentropy]: cprng_fast.c cprng_fast.h
files.cprng_fast
Removed Files:
src/sys/crypto/ccrand [tls-earlyentropy]: ccrand.h ccrand2.c ccrand32.c
ccrand64.c ccrand_bytes.c ccrand_gen16.c ccrand_reseed.c
ccrand_seed.c ccrand_seed32.c ccrand_seed64.c ccrand_use.c
ccrand_var.h ccrand_words.c ccrandn.c files.ccrand
Log Message:
Replace "ccrand" ChaCha implementation of cprng_fast with Taylor's smaller
and somewhat simpler one. Fix rump builds so we can build a distribution.
To generate a diff of this commit:
cvs rdiff -u -r1.1090.2.1 -r1.1090.2.2 src/sys/conf/files
cvs rdiff -u -r1.1.2.1 -r0 src/sys/crypto/ccrand/ccrand.h \
src/sys/crypto/ccrand/ccrand2.c src/sys/crypto/ccrand/ccrand32.c \
src/sys/crypto/ccrand/ccrand64.c src/sys/crypto/ccrand/ccrand_bytes.c \
src/sys/crypto/ccrand/ccrand_gen16.c \
src/sys/crypto/ccrand/ccrand_reseed.c src/sys/crypto/ccrand/ccrand_seed.c \
src/sys/crypto/ccrand/ccrand_seed32.c \
src/sys/crypto/ccrand/ccrand_seed64.c src/sys/crypto/ccrand/ccrand_use.c \
src/sys/crypto/ccrand/ccrand_var.h src/sys/crypto/ccrand/ccrand_words.c \
src/sys/crypto/ccrand/ccrandn.c src/sys/crypto/ccrand/files.ccrand
cvs rdiff -u -r0 -r1.1.2.1 src/sys/crypto/cprng_fast/cprng_fast.c \
src/sys/crypto/cprng_fast/cprng_fast.h \
src/sys/crypto/cprng_fast/files.cprng_fast
cvs rdiff -u -r1.23.2.1 -r1.23.2.2 src/sys/kern/subr_cprng.c
cvs rdiff -u -r1.143 -r1.143.2.1 \
src/sys/rump/librump/rumpkern/Makefile.rumpkern
cvs rdiff -u -r1.9.2.1 -r1.9.2.2 src/sys/sys/cprng.h
cvs rdiff -u -r1.40.2.2 -r1.40.2.3 src/sys/sys/rnd.h
cvs rdiff -u -r1.9 -r1.9.2.1 \
src/usr.sbin/npf/npftest/libnpftest/npf_test_subr.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/conf/files
diff -u src/sys/conf/files:1.1090.2.1 src/sys/conf/files:1.1090.2.2
--- src/sys/conf/files:1.1090.2.1 Thu Jul 17 14:03:33 2014
+++ src/sys/conf/files Sat Aug 9 06:19:50 2014
@@ -1,4 +1,4 @@
-# $NetBSD: files,v 1.1090.2.1 2014/07/17 14:03:33 tls Exp $
+# $NetBSD: files,v 1.1090.2.2 2014/08/09 06:19:50 tls Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
version 20100430
@@ -160,13 +160,15 @@ include "crypto/cast128/files.cast128"
include "crypto/rijndael/files.rijndael"
include "crypto/skipjack/files.skipjack"
include "crypto/camellia/files.camellia"
-include "crypto/ccrand/files.ccrand"
# General-purpose crypto processing framework.
include "opencrypto/files.opencrypto"
# NIST SP800.90 CTR DRBG
include "crypto/nist_ctr_drbg/files.nist_ctr_drbg"
+# ChaCha-based fast PRNG
+include "crypto/cprng_fast/files.cprng_fast"
+
#
# Kernel history/tracing. Old UVMHIST depends upon this.
#
Index: src/sys/kern/subr_cprng.c
diff -u src/sys/kern/subr_cprng.c:1.23.2.1 src/sys/kern/subr_cprng.c:1.23.2.2
--- src/sys/kern/subr_cprng.c:1.23.2.1 Thu Jul 17 14:03:33 2014
+++ src/sys/kern/subr_cprng.c Sat Aug 9 06:19:50 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: subr_cprng.c,v 1.23.2.1 2014/07/17 14:03:33 tls Exp $ */
+/* $NetBSD: subr_cprng.c,v 1.23.2.2 2014/08/09 06:19:50 tls Exp $ */
/*-
* Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_cprng.c,v 1.23.2.1 2014/07/17 14:03:33 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_cprng.c,v 1.23.2.2 2014/08/09 06:19:50 tls Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -55,22 +55,11 @@ __KERNEL_RCSID(0, "$NetBSD: subr_cprng.c
#endif
#include <crypto/nist_ctr_drbg/nist_ctr_drbg.h>
-#include <crypto/ccrand/ccrand.h>
#if defined(__HAVE_CPU_COUNTER)
#include <machine/cpu_counter.h>
#endif
-#define CPRNGF_MAXBYTES (512 * 1024 * 1024)
-#define CPRNGF_HARDMAX (1 * 1024 * 1024 * 1024)
-#define CPRNGF_RESEED_SECONDS 600
-
-typedef struct {
- ccrand_t ccrand;
- int numbytes;
- time_t nextreseed;
-} cprng_fast_ctx_t;
-
static int sysctl_kern_urnd(SYSCTLFN_PROTO);
static int sysctl_kern_arnd(SYSCTLFN_PROTO);
@@ -78,19 +67,12 @@ static void cprng_strong_generate(struct
static void cprng_strong_reseed(struct cprng_strong *);
static void cprng_strong_reseed_from(struct cprng_strong *, const void *,
size_t, bool);
-static void cprng_fast_randrekey(cprng_fast_ctx_t *);
-void *cprng_fast_rekey_softintr = NULL;
-
#if DEBUG
static void cprng_strong_rngtest(struct cprng_strong *);
-static void cprng_fast_rngtest(void);
#endif
static rndsink_callback_t cprng_strong_rndsink_callback;
-percpu_t *percpu_cprng_fast_ctx;
-static int cprng_fast_initialized;
-
void
cprng_init(void)
{
@@ -134,6 +116,7 @@ struct cprng_strong {
char cs_name[16];
int cs_flags;
kmutex_t cs_lock;
+ percpu_t *cs_percpu;
kcondvar_t cs_cv;
struct selinfo cs_selq;
struct rndsink *cs_rndsink;
@@ -501,25 +484,6 @@ cprng_strong_rngtest(struct cprng_strong
explicit_memset(rt, 0, sizeof(*rt)); /* paranoia */
kmem_intr_free(rt, sizeof(*rt));
}
-
-static void cprng_fast_rngtest(void)
-{
- rngtest_t *const rt = kmem_intr_alloc(sizeof(*rt), KM_NOSLEEP);
- if (rt == NULL)
- /* XXX Warn? */
- return;
-
- (void)snprintf(rt->rt_name, sizeof(rt->rt_name),
- "cpu%d", curcpu()->ci_index);
- cprng_fast(rt->rt_b, sizeof(rt->rt_b));
-
- if (rngtest(rt)) {
- printf("cprng_fast for %s: failed statistical RNG test\n",
- rt->rt_name);
- }
- explicit_memset(rt, 0, sizeof(*rt));
- kmem_intr_free(rt, sizeof(*rt));
-}
#endif
/*
@@ -605,128 +569,3 @@ sysctl_kern_arnd(SYSCTLFN_ARGS)
return error;
}
}
-
-static void
-cprng_fast_randrekey(cprng_fast_ctx_t *ctx)
-{
- uint8_t key[16];
- int s;
-
- int have_initial = rnd_initial_entropy;
-
- cprng_strong(kern_cprng, key, sizeof(key), FASYNC);
- s = splhigh();
- ccrand_reseed(&ctx->ccrand, (uint32_t *)key,
- sizeof(key) / sizeof(uint32_t));
- splx(s);
- explicit_memset(key, 0, sizeof(key));
- /*
- * Reset for next reseed cycle.
- */
- ctx->nextreseed = time_uptime +
- (have_initial ? CPRNGF_RESEED_SECONDS : 0);
- ctx->numbytes = 0;
-
-#if DEBUG
- cprng_fast_rngtest();
-#endif
-}
-
-static void
-cprng_fast_init_ctx(void *v,
- void *arg __unused,
- struct cpu_info * ci __unused)
-{
- cprng_fast_ctx_t *ctx = v;
- cprng_fast_randrekey(ctx);
-}
-
-static void
-cprng_fast_rekey_one(void *arg __unused)
-{
- cprng_fast_ctx_t *ctx = percpu_getref(percpu_cprng_fast_ctx);
-
- cprng_fast_randrekey(ctx);
- percpu_putref(percpu_cprng_fast_ctx);
-}
-
-/*
- * Because we key the cprng_fast instances from the kernel_cprng,
- * and we try not to initialize the kernel_cprng until there is at
- * least some chance there's entropy available for it, this must
- * be called somewhat later than cprng_init() and is thus a separate
- * function.
- */
-void
-cprng_fast_init(void)
-{
- percpu_cprng_fast_ctx = percpu_alloc(sizeof(cprng_fast_ctx_t));
-
- percpu_foreach(percpu_cprng_fast_ctx, cprng_fast_init_ctx, NULL);
- cprng_fast_rekey_softintr =
- softint_establish(SOFTINT_CLOCK|SOFTINT_MPSAFE,
- cprng_fast_rekey_one, NULL);
- cprng_fast_initialized++;
-}
-
-static inline void
-cprng_fast_checkrekey(cprng_fast_ctx_t *ctx)
-{
- extern void *cprng_fast_rekey_softintr;
-
- if (__predict_false((ctx->numbytes > CPRNGF_MAXBYTES) ||
- (time_uptime > ctx->nextreseed))) {
- /* Schedule a deferred reseed */
- softint_schedule(cprng_fast_rekey_softintr);
- }
-}
-
-uint32_t
-cprng_fast32(void)
-{
- cprng_fast_ctx_t *ctx = percpu_getref(percpu_cprng_fast_ctx);
- int s;
- uint32_t ret;
-
- cprng_fast_checkrekey(ctx);
-
- s = splhigh();
- ret = ccrand32(&ctx->ccrand);
- splx(s);
- ctx->numbytes+= sizeof(ret);
- percpu_putref(percpu_cprng_fast_ctx);
- return ret;
-}
-
-uint64_t
-cprng_fast64(void)
-{
- cprng_fast_ctx_t *ctx = percpu_getref(percpu_cprng_fast_ctx);
- int s;
- uint64_t ret;
-
- cprng_fast_checkrekey(ctx);
-
- s = splhigh();
- ret = ccrand64(&ctx->ccrand);
- splx(s);
- ctx->numbytes += sizeof(ret);
- percpu_putref(percpu_cprng_fast_ctx);
- return ret;
-}
-
-size_t
-cprng_fast(void *p, size_t len)
-{
- cprng_fast_ctx_t *ctx = percpu_getref(percpu_cprng_fast_ctx);
- int s;
-
- cprng_fast_checkrekey(ctx);
-
- s = splhigh();
- ccrand_bytes(&ctx->ccrand, p, len);
- splx(s);
- ctx->numbytes += len;
- percpu_putref(percpu_cprng_fast_ctx);
- return len;
-}
Index: src/sys/rump/librump/rumpkern/Makefile.rumpkern
diff -u src/sys/rump/librump/rumpkern/Makefile.rumpkern:1.143 src/sys/rump/librump/rumpkern/Makefile.rumpkern:1.143.2.1
--- src/sys/rump/librump/rumpkern/Makefile.rumpkern:1.143 Fri Apr 4 18:20:28 2014
+++ src/sys/rump/librump/rumpkern/Makefile.rumpkern Sat Aug 9 06:19:50 2014
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile.rumpkern,v 1.143 2014/04/04 18:20:28 njoly Exp $
+# $NetBSD: Makefile.rumpkern,v 1.143.2.1 2014/08/09 06:19:50 tls Exp $
#
.include "${RUMPTOP}/Makefile.rump"
@@ -15,6 +15,7 @@ LIB= rump
${RUMPTOP}/../dev \
${RUMPTOP}/../crypto/nist_ctr_drbg \
${RUMPTOP}/../crypto/rijndael \
+ ${RUMPTOP}/../crypto/cprng_fast \
${RUMPTOP}/../secmodel \
${RUMPTOP}/../secmodel/suser \
${RUMPTOP}/../compat/common
@@ -149,7 +150,8 @@ SRCS+= clock_subr.c
SRCS+= nist_ctr_drbg.c
SRCS+= rijndael-alg-fst.c
SRCS+= rijndael-api-fst.c
-SRCS+= rijndael.c
+SRCS+= rijndael.c
+SRCS+= cprng_fast.c
# compat
SRCS+= kern_select_50.c
Index: src/sys/sys/cprng.h
diff -u src/sys/sys/cprng.h:1.9.2.1 src/sys/sys/cprng.h:1.9.2.2
--- src/sys/sys/cprng.h:1.9.2.1 Thu Jul 17 14:03:33 2014
+++ src/sys/sys/cprng.h Sat Aug 9 06:19:50 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: cprng.h,v 1.9.2.1 2014/07/17 14:03:33 tls Exp $ */
+/* $NetBSD: cprng.h,v 1.9.2.2 2014/08/09 06:19:50 tls Exp $ */
/*-
* Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
@@ -41,23 +41,16 @@
#include <sys/rnd.h> /* XXX users bogusly transitively need this */
#include <crypto/nist_ctr_drbg/nist_ctr_drbg.h>
-#include <sys/percpu.h>
-#include <sys/intr.h>
+#include <crypto/cprng_fast/cprng_fast.h>
/*
* NIST SP800-90 says 2^19 bytes per request for the CTR_DRBG.
*/
#define CPRNG_MAX_LEN 524288
-size_t cprng_fast(void *, size_t);
-
-uint32_t cprng_fast32(void);
-uint64_t cprng_fast64(void);
-
typedef struct cprng_strong cprng_strong_t;
void cprng_init(void);
-void cprng_fast_init(void);
#define CPRNG_INIT_ANY 0x00000001
#define CPRNG_REKEY_ANY 0x00000002
Index: src/sys/sys/rnd.h
diff -u src/sys/sys/rnd.h:1.40.2.2 src/sys/sys/rnd.h:1.40.2.3
--- src/sys/sys/rnd.h:1.40.2.2 Thu Jul 17 14:03:33 2014
+++ src/sys/sys/rnd.h Sat Aug 9 06:19:50 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: rnd.h,v 1.40.2.2 2014/07/17 14:03:33 tls Exp $ */
+/* $NetBSD: rnd.h,v 1.40.2.3 2014/08/09 06:19:50 tls Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -227,6 +227,8 @@ extern int rnd_initial_entropy;
extern int rnd_ready;
extern int rnd_printing; /* XXX recursion through printf */
+extern int rnd_blockonce;
+
#endif /* _KERNEL */
#define RND_MAXSTATCOUNT 10 /* 10 sources at once max */
Index: src/usr.sbin/npf/npftest/libnpftest/npf_test_subr.c
diff -u src/usr.sbin/npf/npftest/libnpftest/npf_test_subr.c:1.9 src/usr.sbin/npf/npftest/libnpftest/npf_test_subr.c:1.9.2.1
--- src/usr.sbin/npf/npftest/libnpftest/npf_test_subr.c:1.9 Thu Feb 13 03:34:40 2014
+++ src/usr.sbin/npf/npftest/libnpftest/npf_test_subr.c Sat Aug 9 06:19:50 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: npf_test_subr.c,v 1.9 2014/02/13 03:34:40 rmind Exp $ */
+/* $NetBSD: npf_test_subr.c,v 1.9.2.1 2014/08/09 06:19:50 tls Exp $ */
/*
* NPF initialisation and handler routines.
@@ -138,10 +138,10 @@ npf_inet_ntop(int af, const void *src, c
}
/*
- * Need to override for cprng_fast32() -- we need deterministic PRNG.
+ * Need to override cprng_fast32() -- we need deterministic PRNG.
*/
uint32_t
-_arc4random(void)
+cprng_fast32(void)
{
return (uint32_t)(_random_func ? _random_func() : random());
}
Added files:
Index: src/sys/crypto/cprng_fast/cprng_fast.c
diff -u /dev/null src/sys/crypto/cprng_fast/cprng_fast.c:1.1.2.1
--- /dev/null Sat Aug 9 06:19:50 2014
+++ src/sys/crypto/cprng_fast/cprng_fast.c Sat Aug 9 06:19:50 2014
@@ -0,0 +1,496 @@
+/* $NetBSD: cprng_fast.c,v 1.1.2.1 2014/08/09 06:19:50 tls Exp $ */
+
+/*-
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: cprng_fast.c,v 1.1.2.1 2014/08/09 06:19:50 tls Exp $");
+
+#include <sys/types.h>
+#include <sys/bitops.h>
+#include <sys/param.h>
+#include <sys/cpu.h>
+#include <sys/intr.h>
+#include <sys/percpu.h>
+#include <sys/cprng.h>
+
+
+/* ChaCha core */
+
+#define crypto_core_OUTPUTWORDS 16
+#define crypto_core_INPUTWORDS 4
+#define crypto_core_KEYWORDS 8
+#define crypto_core_CONSTWORDS 4
+
+#define crypto_core_ROUNDS 8
+
+static uint32_t
+rotate(uint32_t u, unsigned c)
+{
+
+ return (u << c) | (u >> (32 - c));
+}
+
+#define QUARTERROUND(a, b, c, d) do { \
+ (a) += (b); (d) ^= (a); (d) = rotate((d), 16); \
+ (c) += (d); (b) ^= (c); (b) = rotate((b), 12); \
+ (a) += (b); (d) ^= (a); (d) = rotate((d), 8); \
+ (c) += (d); (b) ^= (c); (b) = rotate((b), 7); \
+} while (0)
+
+static void
+crypto_core(uint32_t *out, const uint32_t *in, const uint32_t *k,
+ const uint32_t *c)
+{
+ uint32_t x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15;
+ int i;
+
+ x0 = c[0];
+ x1 = c[1];
+ x2 = c[2];
+ x3 = c[3];
+ x4 = k[0];
+ x5 = k[1];
+ x6 = k[2];
+ x7 = k[3];
+ x8 = k[4];
+ x9 = k[5];
+ x10 = k[6];
+ x11 = k[7];
+ x12 = in[0];
+ x13 = in[1];
+ x14 = in[2];
+ x15 = in[3];
+
+ for (i = crypto_core_ROUNDS; i > 0; i -= 2) {
+ QUARTERROUND( x0, x4, x8,x12);
+ QUARTERROUND( x1, x5, x9,x13);
+ QUARTERROUND( x2, x6,x10,x14);
+ QUARTERROUND( x3, x7,x11,x15);
+ QUARTERROUND( x0, x5,x10,x15);
+ QUARTERROUND( x1, x6,x11,x12);
+ QUARTERROUND( x2, x7, x8,x13);
+ QUARTERROUND( x3, x4, x9,x14);
+ }
+
+ out[0] = x0 + c[0];
+ out[1] = x1 + c[1];
+ out[2] = x2 + c[2];
+ out[3] = x3 + c[3];
+ out[4] = x4 + k[0];
+ out[5] = x5 + k[1];
+ out[6] = x6 + k[2];
+ out[7] = x7 + k[3];
+ out[8] = x8 + k[4];
+ out[9] = x9 + k[5];
+ out[10] = x10 + k[6];
+ out[11] = x11 + k[7];
+ out[12] = x12 + in[0];
+ out[13] = x13 + in[1];
+ out[14] = x14 + in[2];
+ out[15] = x15 + in[3];
+}
+
+/* `expand 32-byte k' */
+static const uint32_t crypto_core_constant32[4] = {
+ 0x61707865U, 0x3320646eU, 0x79622d32U, 0x6b206574U,
+};
+
+/*
+ * Test vector for ChaCha20 from
+ * <http://tools.ietf.org/html/draft-strombergson-chacha-test-vectors-00>,
+ * test vectors for ChaCha12 and ChaCha8 generated by the same
+ * crypto_core code with crypto_core_ROUNDS varied.
+ */
+
+#define check(E) do \
+{ \
+ if (!(E)) \
+ panic("crypto self-test failed: %s", #E); \
+} while (0)
+
+static void
+crypto_core_selftest(void)
+{
+ const uint32_t zero32[8] = {0};
+ const uint8_t sigma[] = "expand 32-byte k";
+ uint32_t block[16];
+ unsigned i;
+
+#if crypto_core_ROUNDS == 8
+ static const uint8_t out[64] = {
+ 0x3e,0x00,0xef,0x2f,0x89,0x5f,0x40,0xd6,
+ 0x7f,0x5b,0xb8,0xe8,0x1f,0x09,0xa5,0xa1,
+ 0x2c,0x84,0x0e,0xc3,0xce,0x9a,0x7f,0x3b,
+ 0x18,0x1b,0xe1,0x88,0xef,0x71,0x1a,0x1e,
+ 0x98,0x4c,0xe1,0x72,0xb9,0x21,0x6f,0x41,
+ 0x9f,0x44,0x53,0x67,0x45,0x6d,0x56,0x19,
+ 0x31,0x4a,0x42,0xa3,0xda,0x86,0xb0,0x01,
+ 0x38,0x7b,0xfd,0xb8,0x0e,0x0c,0xfe,0x42,
+ };
+#elif crypto_core_ROUNDS == 12
+ static const uint8_t out[64] = {
+ 0x9b,0xf4,0x9a,0x6a,0x07,0x55,0xf9,0x53,
+ 0x81,0x1f,0xce,0x12,0x5f,0x26,0x83,0xd5,
+ 0x04,0x29,0xc3,0xbb,0x49,0xe0,0x74,0x14,
+ 0x7e,0x00,0x89,0xa5,0x2e,0xae,0x15,0x5f,
+ 0x05,0x64,0xf8,0x79,0xd2,0x7a,0xe3,0xc0,
+ 0x2c,0xe8,0x28,0x34,0xac,0xfa,0x8c,0x79,
+ 0x3a,0x62,0x9f,0x2c,0xa0,0xde,0x69,0x19,
+ 0x61,0x0b,0xe8,0x2f,0x41,0x13,0x26,0xbe,
+ };
+#elif crypto_core_ROUNDS == 20
+ static const uint8_t out[64] = {
+ 0x76,0xb8,0xe0,0xad,0xa0,0xf1,0x3d,0x90,
+ 0x40,0x5d,0x6a,0xe5,0x53,0x86,0xbd,0x28,
+ 0xbd,0xd2,0x19,0xb8,0xa0,0x8d,0xed,0x1a,
+ 0xa8,0x36,0xef,0xcc,0x8b,0x77,0x0d,0xc7,
+ 0xda,0x41,0x59,0x7c,0x51,0x57,0x48,0x8d,
+ 0x77,0x24,0xe0,0x3f,0xb8,0xd8,0x4a,0x37,
+ 0x6a,0x43,0xb8,0xf4,0x15,0x18,0xa1,0x1c,
+ 0xc3,0x87,0xb6,0x69,0xb2,0xee,0x65,0x86,
+ };
+#else
+#error crypto_core_ROUNDS must be 8, 12, or 20.
+#endif
+
+ check(crypto_core_constant32[0] == le32dec(&sigma[0]));
+ check(crypto_core_constant32[1] == le32dec(&sigma[4]));
+ check(crypto_core_constant32[2] == le32dec(&sigma[8]));
+ check(crypto_core_constant32[3] == le32dec(&sigma[12]));
+
+ crypto_core(block, zero32, zero32, crypto_core_constant32);
+ for (i = 0; i < 16; i++)
+ check(block[i] == le32dec(&out[i*4]));
+}
+
+#undef check
+
+#define CPRNG_FAST_SEED_BYTES (crypto_core_KEYWORDS * sizeof(uint32_t))
+
+struct cprng_fast {
+ uint32_t buffer[crypto_core_OUTPUTWORDS];
+ uint32_t key[crypto_core_KEYWORDS];
+ uint32_t nonce[crypto_core_INPUTWORDS];
+ bool have_initial;
+};
+
+__CTASSERT(sizeof ((struct cprng_fast *)0)->key == CPRNG_FAST_SEED_BYTES);
+
+static void cprng_fast_schedule_reseed(struct cprng_fast *);
+static void cprng_fast_intr(void *);
+
+static void cprng_fast_seed(struct cprng_fast *, const void *);
+static void cprng_fast_buf(struct cprng_fast *, void *, unsigned);
+
+static void cprng_fast_buf_short(void *, size_t);
+static void cprng_fast_buf_long(void *, size_t);
+
+static percpu_t *cprng_fast_percpu __read_mostly;
+static void *cprng_fast_softint __read_mostly;
+
+extern int rnd_initial_entropy;
+
+void
+cprng_fast_init(void)
+{
+ struct cpu_info *ci;
+ CPU_INFO_ITERATOR cii;
+
+ crypto_core_selftest();
+ cprng_fast_percpu = percpu_alloc(sizeof(struct cprng_fast));
+ for (CPU_INFO_FOREACH(cii, ci)) {
+ struct cprng_fast *cprng;
+ uint8_t seed[CPRNG_FAST_SEED_BYTES];
+
+ percpu_traverse_enter();
+ cprng = percpu_getptr_remote(cprng_fast_percpu, ci);
+ cprng_strong(kern_cprng, seed, sizeof(seed), FASYNC);
+ /* Can't do anything about it if not full entropy. */
+ cprng_fast_seed(cprng, seed);
+ explicit_memset(seed, 0, sizeof(seed));
+ percpu_traverse_exit();
+ }
+ cprng_fast_softint = softint_establish(SOFTINT_SERIAL|SOFTINT_MPSAFE,
+ &cprng_fast_intr, NULL);
+}
+
+static inline int
+cprng_fast_get(struct cprng_fast **cprngp)
+{
+
+ *cprngp = percpu_getref(cprng_fast_percpu);
+ return splvm();
+}
+
+static inline void
+cprng_fast_put(struct cprng_fast *cprng, int s)
+{
+
+ KASSERT((cprng == percpu_getref(cprng_fast_percpu)) &&
+ (percpu_putref(cprng_fast_percpu), true));
+ splx(s);
+ percpu_putref(cprng_fast_percpu);
+}
+
+static inline void
+cprng_fast_schedule_reseed(struct cprng_fast *cprng __unused)
+{
+
+ softint_schedule(cprng_fast_softint);
+}
+
+static void
+cprng_fast_intr(void *cookie __unused)
+{
+ struct cprng_fast *cprng;
+ uint8_t seed[CPRNG_FAST_SEED_BYTES];
+
+ cprng_strong(kern_cprng, seed, sizeof(seed), FASYNC);
+
+ cprng = percpu_getref(cprng_fast_percpu);
+ cprng_fast_seed(cprng, seed);
+ percpu_putref(cprng_fast_percpu);
+
+ explicit_memset(seed, 0, sizeof(seed));
+}
+
+/* CPRNG algorithm */
+
+/*
+ * The state consists of a key, the current nonce, and a 64-byte buffer
+ * of output. Since we fill the buffer only when we need output, and
+ * eat a 32-bit word at a time, one 32-bit word of the buffer would be
+ * wasted. Instead, we repurpose it to count the number of entries in
+ * the buffer remaining, counting from high to low in order to allow
+ * comparison to zero to detect when we need to refill it.
+ */
+#define CPRNG_FAST_BUFIDX (crypto_core_OUTPUTWORDS - 1)
+
+static inline void
+cprng_fast_seed(struct cprng_fast *cprng, const void *seed)
+{
+
+ (void)memset(cprng->buffer, 0, sizeof cprng->buffer);
+ (void)memcpy(cprng->key, seed, sizeof cprng->key);
+ (void)memset(cprng->nonce, 0, sizeof cprng->nonce);
+
+ if (__predict_true(rnd_initial_entropy)) {
+ cprng->have_initial = true;
+ } else {
+ cprng->have_initial = false;
+ }
+}
+
+static inline uint32_t
+cprng_fast_word(struct cprng_fast *cprng)
+{
+ uint32_t v;
+
+ if (__predict_true(0 < cprng->buffer[CPRNG_FAST_BUFIDX])) {
+ v = cprng->buffer[--cprng->buffer[CPRNG_FAST_BUFIDX]];
+ } else {
+ /* If we don't have enough words, refill the buffer. */
+ crypto_core(cprng->buffer, cprng->nonce, cprng->key,
+ crypto_core_constant32);
+ if (__predict_false(++cprng->nonce[0] == 0)) {
+ cprng->nonce[1]++;
+ cprng_fast_schedule_reseed(cprng);
+ } else {
+ if (__predict_false(false == cprng->have_initial)) {
+ if (rnd_initial_entropy) {
+ cprng_fast_schedule_reseed(cprng);
+ }
+ }
+ }
+ v = cprng->buffer[CPRNG_FAST_BUFIDX];
+ cprng->buffer[CPRNG_FAST_BUFIDX] = CPRNG_FAST_BUFIDX;
+ }
+
+ return v;
+}
+
+static inline void
+cprng_fast_buf(struct cprng_fast *cprng, void *buf, unsigned n)
+{
+ uint8_t *p = buf;
+ uint32_t v;
+ unsigned r;
+
+ while (n) {
+ r = MIN(n, 4);
+ n -= r;
+ v = cprng_fast_word(cprng);
+ while (r--) {
+ *p++ = (v & 0xff);
+ v >>= 8;
+ }
+ }
+}
+
+/*
+ * crypto_onetimestream: Expand a short unpredictable one-time seed
+ * into a long unpredictable output.
+ */
+static void
+crypto_onetimestream(const uint32_t seed[crypto_core_KEYWORDS], void *buf,
+ size_t n)
+{
+ uint32_t block[crypto_core_OUTPUTWORDS];
+ uint32_t nonce[crypto_core_INPUTWORDS] = {0};
+ uint8_t *p8;
+ uint32_t *p32;
+ size_t ni, nb, nf;
+
+ /*
+ * Guarantee we can generate up to n bytes. We have
+ * 2^(32*INPUTWORDS) possible inputs yielding output of
+ * 4*OUTPUTWORDS*2^(32*INPUTWORDS) bytes. It suffices to
+ * require that sizeof n > (1/CHAR_BIT) log_2 n be less than
+ * (1/CHAR_BIT) log_2 of the total output stream length. We
+ * have
+ *
+ * log_2 (4 o 2^(32 i)) = log_2 (4 o) + log_2 2^(32 i)
+ * = 2 + log_2 o + 32 i.
+ */
+ __CTASSERT(CHAR_BIT*sizeof n <=
+ (2 + ilog2(crypto_core_OUTPUTWORDS) + 32*crypto_core_INPUTWORDS));
+
+ p8 = buf;
+ p32 = (uint32_t *)roundup2((uintptr_t)p8, sizeof(uint32_t));
+ ni = (uint8_t *)p32 - p8;
+ if (n < ni)
+ ni = n;
+ nb = (n - ni) / sizeof block;
+ nf = (n - ni) % sizeof block;
+
+ KASSERT(((uintptr_t)p32 & 3) == 0);
+ KASSERT(ni <= n);
+ KASSERT(nb <= (n / sizeof block));
+ KASSERT(nf <= n);
+ KASSERT(n == (ni + (nb * sizeof block) + nf));
+ KASSERT(ni < sizeof(uint32_t));
+ KASSERT(nf < sizeof block);
+
+ if (ni) {
+ crypto_core(block, nonce, seed, crypto_core_constant32);
+ nonce[0]++;
+ (void)memcpy(p8, block, ni);
+ }
+ while (nb--) {
+ crypto_core(p32, nonce, seed, crypto_core_constant32);
+ if (++nonce[0] == 0)
+ nonce[1]++;
+ p32 += crypto_core_OUTPUTWORDS;
+ }
+ if (nf) {
+ crypto_core(block, nonce, seed, crypto_core_constant32);
+ if (++nonce[0] == 0)
+ nonce[1]++;
+ (void)memcpy(p32, block, nf);
+ }
+
+ if (ni | nf)
+ (void)explicit_memset(block, 0, sizeof block);
+}
+
+/* Public API */
+
+uint32_t
+cprng_fast32(void)
+{
+ struct cprng_fast *cprng;
+ uint32_t v;
+ int s;
+
+ s = cprng_fast_get(&cprng);
+ v = cprng_fast_word(cprng);
+ cprng_fast_put(cprng, s);
+
+ return v;
+}
+
+uint64_t
+cprng_fast64(void)
+{
+ struct cprng_fast *cprng;
+ uint32_t hi, lo;
+ int s;
+
+ s = cprng_fast_get(&cprng);
+ hi = cprng_fast_word(cprng);
+ lo = cprng_fast_word(cprng);
+ cprng_fast_put(cprng, s);
+
+ return ((uint64_t)hi << 32) | lo;
+}
+
+static void
+cprng_fast_buf_short(void *buf, size_t len)
+{
+ struct cprng_fast *cprng;
+ int s;
+
+ s = cprng_fast_get(&cprng);
+ cprng_fast_buf(cprng, buf, len);
+ cprng_fast_put(cprng, s);
+}
+
+static __noinline void
+cprng_fast_buf_long(void *buf, size_t len)
+{
+ uint32_t seed[crypto_core_KEYWORDS];
+ struct cprng_fast *cprng;
+ int s;
+
+ s = cprng_fast_get(&cprng);
+ cprng_fast_buf(cprng, seed, sizeof seed);
+ cprng_fast_put(cprng, s);
+
+ crypto_onetimestream(seed, buf, len);
+
+ (void)explicit_memset(seed, 0, sizeof seed);
+}
+
+size_t
+cprng_fast(void *buf, size_t len)
+{
+
+ /*
+ * We don't want to hog the CPU, so we use the short version,
+ * to generate output without preemption, only if we can do it
+ * with at most one crypto_core.
+ */
+ if (len <= (sizeof(uint32_t) * crypto_core_OUTPUTWORDS))
+ cprng_fast_buf_short(buf, len);
+ else
+ cprng_fast_buf_long(buf, len);
+
+ return len;
+}
Index: src/sys/crypto/cprng_fast/cprng_fast.h
diff -u /dev/null src/sys/crypto/cprng_fast/cprng_fast.h:1.1.2.1
--- /dev/null Sat Aug 9 06:19:50 2014
+++ src/sys/crypto/cprng_fast/cprng_fast.h Sat Aug 9 06:19:50 2014
@@ -0,0 +1,9 @@
+#ifndef _SYS_CPRNG_FAST_H_
+#define _SYS_CPRNG_FAST_H_
+
+size_t cprng_fast(void *, size_t);
+uint32_t cprng_fast32(void);
+uint64_t cprng_fast64(void);
+void cprng_fast_init(void);
+
+#endif /* _SYS_CPRNG_FAST_H_ */
Index: src/sys/crypto/cprng_fast/files.cprng_fast
diff -u /dev/null src/sys/crypto/cprng_fast/files.cprng_fast:1.1.2.1
--- /dev/null Sat Aug 9 06:19:50 2014
+++ src/sys/crypto/cprng_fast/files.cprng_fast Sat Aug 9 06:19:50 2014
@@ -0,0 +1,3 @@
+# $NetBSD: files.cprng_fast,v 1.1.2.1 2014/08/09 06:19:50 tls Exp $
+
+file crypto/cprng_fast/cprng_fast.c