summaryrefslogtreecommitdiffstats
path: root/lib/isc/lfsr.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/isc/lfsr.c')
-rw-r--r--lib/isc/lfsr.c153
1 files changed, 153 insertions, 0 deletions
diff --git a/lib/isc/lfsr.c b/lib/isc/lfsr.c
new file mode 100644
index 0000000..633b4a9
--- /dev/null
+++ b/lib/isc/lfsr.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <isc/assertions.h>
+#include <isc/lfsr.h>
+#include <isc/util.h>
+
+#define VALID_LFSR(x) (x != NULL)
+
+void
+isc_lfsr_init(isc_lfsr_t *lfsr, uint32_t state, unsigned int bits, uint32_t tap,
+ unsigned int count, isc_lfsrreseed_t reseed, void *arg) {
+ REQUIRE(VALID_LFSR(lfsr));
+ REQUIRE(8 <= bits && bits <= 32);
+ REQUIRE(tap != 0);
+
+ lfsr->state = state;
+ lfsr->bits = bits;
+ lfsr->tap = tap;
+ lfsr->count = count;
+ lfsr->reseed = reseed;
+ lfsr->arg = arg;
+
+ if (count == 0 && reseed != NULL) {
+ reseed(lfsr, arg);
+ }
+ if (lfsr->state == 0) {
+ lfsr->state = 0xffffffffU >> (32 - lfsr->bits);
+ }
+}
+
+/*!
+ * Return the next state of the lfsr.
+ */
+static uint32_t
+lfsr_generate(isc_lfsr_t *lfsr) {
+ /*
+ * If the previous state is zero, we must fill it with something
+ * here, or we will begin to generate an extremely predictable output.
+ *
+ * First, give the reseed function a crack at it. If the state is
+ * still 0, set it to all ones.
+ */
+ if (lfsr->state == 0) {
+ if (lfsr->reseed != NULL) {
+ lfsr->reseed(lfsr, lfsr->arg);
+ }
+ if (lfsr->state == 0) {
+ lfsr->state = 0xffffffffU >> (32 - lfsr->bits);
+ }
+ }
+
+ if (lfsr->state & 0x01) {
+ lfsr->state = (lfsr->state >> 1) ^ lfsr->tap;
+ return (1);
+ } else {
+ lfsr->state >>= 1;
+ return (0);
+ }
+}
+
+void
+isc_lfsr_generate(isc_lfsr_t *lfsr, void *data, unsigned int count) {
+ unsigned char *p;
+ unsigned int bit;
+ unsigned int byte;
+
+ REQUIRE(VALID_LFSR(lfsr));
+ REQUIRE(data != NULL);
+ REQUIRE(count > 0);
+
+ p = data;
+ byte = count;
+
+ while (byte--) {
+ *p = 0;
+ for (bit = 0; bit < 7; bit++) {
+ *p |= lfsr_generate(lfsr);
+ *p <<= 1;
+ }
+ *p |= lfsr_generate(lfsr);
+ p++;
+ }
+
+ if (lfsr->count != 0 && lfsr->reseed != NULL) {
+ if (lfsr->count <= count * 8) {
+ lfsr->reseed(lfsr, lfsr->arg);
+ } else {
+ lfsr->count -= (count * 8);
+ }
+ }
+}
+
+static uint32_t
+lfsr_skipgenerate(isc_lfsr_t *lfsr, unsigned int skip) {
+ while (skip--) {
+ (void)lfsr_generate(lfsr);
+ }
+
+ (void)lfsr_generate(lfsr);
+
+ return (lfsr->state);
+}
+
+/*
+ * Skip "skip" states in "lfsr".
+ */
+void
+isc_lfsr_skip(isc_lfsr_t *lfsr, unsigned int skip) {
+ REQUIRE(VALID_LFSR(lfsr));
+
+ while (skip--) {
+ (void)lfsr_generate(lfsr);
+ }
+}
+
+/*
+ * Skip states in lfsr1 and lfsr2 using the other's current state.
+ * Return the final state of lfsr1 ^ lfsr2.
+ */
+uint32_t
+isc_lfsr_generate32(isc_lfsr_t *lfsr1, isc_lfsr_t *lfsr2) {
+ uint32_t state1, state2;
+ uint32_t skip1, skip2;
+
+ REQUIRE(VALID_LFSR(lfsr1));
+ REQUIRE(VALID_LFSR(lfsr2));
+
+ skip1 = lfsr1->state & 0x01;
+ skip2 = lfsr2->state & 0x01;
+
+ /* cross-skip. */
+ state1 = lfsr_skipgenerate(lfsr1, skip2);
+ state2 = lfsr_skipgenerate(lfsr2, skip1);
+
+ return (state1 ^ state2);
+}