lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Tue, 31 Mar 2015 13:28:09 -0400
From:	Waiman Long <Waiman.Long@...com>
To:	Peter Zijlstra <peterz@...radead.org>,
	Ingo Molnar <mingo@...hat.com>
Cc:	linux-kernel@...r.kernel.org, Shuah Khan <shuahkh@....samsung.com>,
	Scott J Norton <scott.norton@...com>,
	Douglas Hatch <doug.hatch@...com>,
	Waiman Long <Waiman.Long@...com>
Subject: [PATCH] lfsr: a simple binary Galois linear feedback shift register

This patch is based on the code sent out by Peter Zijstra as part
of his queue spinlock patch to provide a hashing function with open
addressing.  The lfsr() function can be used to return a sequence of
numbers that cycle through all the bit patterns (2^n -1) of a given
bit width n except the value 0 in a somewhat random fashion depending
on the LFSR tap that is being used.

This code should be a standalone patch and not part of a larger
patch series.  I have also modified and extended it and added some
testing code to verify the correctness of the taps that are being used.

Signed-off-by: Waiman Long <Waiman.Long@...com>
---
 include/linux/lfsr.h                     |   84 ++++++++++++++++++++++++++++++
 tools/testing/selftests/lfsr/Makefile    |   11 ++++
 tools/testing/selftests/lfsr/test-lfsr.c |   70 +++++++++++++++++++++++++
 3 files changed, 165 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/lfsr.h
 create mode 100644 tools/testing/selftests/lfsr/Makefile
 create mode 100644 tools/testing/selftests/lfsr/test-lfsr.c

diff --git a/include/linux/lfsr.h b/include/linux/lfsr.h
new file mode 100644
index 0000000..3e2a168
--- /dev/null
+++ b/include/linux/lfsr.h
@@ -0,0 +1,84 @@
+#ifndef _LINUX_LFSR_H
+#define _LINUX_LFSR_H
+
+/*
+ * Simple Binary Galois Linear Feedback Shift Register
+ *
+ * http://en.wikipedia.org/wiki/Linear_feedback_shift_register
+ *
+ * This function only currently supports only bits values of 4-30. Callers
+ * that doesn't pass in a constant bits value can optionally define
+ * LFSR_MIN_BITS and LFSR_MAX_BITS before including the lfsr.h header file
+ * to reduce the size of the jump table in the compiled code, if desired.
+ */
+#ifndef LFSR_MIN_BITS
+#define LFSR_MIN_BITS	4
+#endif
+
+#ifndef LFSR_MAX_BITS
+#define LFSR_MAX_BITS	30
+#endif
+
+static __always_inline u32 lfsr_taps(int bits)
+{
+	BUG_ON((bits < LFSR_MIN_BITS) || (bits > LFSR_MAX_BITS));
+	BUILD_BUG_ON((LFSR_MIN_BITS < 4) || (LFSR_MAX_BITS > 30));
+
+#define _IF_BITS_EQ(x)	\
+	if (((x) >= LFSR_MIN_BITS) && ((x) <= LFSR_MAX_BITS) && ((x) == bits))
+
+	/*
+	 * Feedback terms copied from
+	 * http://users.ece.cmu.edu/~koopman/lfsr/index.html
+	 */
+	_IF_BITS_EQ(4)  return 0x0009;
+	_IF_BITS_EQ(5)  return 0x0012;
+	_IF_BITS_EQ(6)  return 0x0021;
+	_IF_BITS_EQ(7)  return 0x0041;
+	_IF_BITS_EQ(8)  return 0x008E;
+	_IF_BITS_EQ(9)  return 0x0108;
+	_IF_BITS_EQ(10) return 0x0204;
+	_IF_BITS_EQ(11) return 0x0402;
+	_IF_BITS_EQ(12) return 0x0829;
+	_IF_BITS_EQ(13) return 0x100D;
+	_IF_BITS_EQ(14) return 0x2015;
+	_IF_BITS_EQ(15) return 0x4122;
+	_IF_BITS_EQ(16) return 0x8112;
+	_IF_BITS_EQ(17) return 0x102C9;
+	_IF_BITS_EQ(18) return 0x20195;
+	_IF_BITS_EQ(19) return 0x403FE;
+	_IF_BITS_EQ(20) return 0x80637;
+	_IF_BITS_EQ(21) return 0x100478;
+	_IF_BITS_EQ(22) return 0x20069E;
+	_IF_BITS_EQ(23) return 0x4004B2;
+	_IF_BITS_EQ(24) return 0x800B87;
+	_IF_BITS_EQ(25) return 0x10004F3;
+	_IF_BITS_EQ(26) return 0x200072D;
+	_IF_BITS_EQ(27) return 0x40006AE;
+	_IF_BITS_EQ(28) return 0x80009E3;
+	_IF_BITS_EQ(29) return 0x10000583;
+	_IF_BITS_EQ(30) return 0x20000C92;
+#undef _IF_BITS_EQ
+
+	/* Unreachable */
+	return 0;
+}
+
+static inline u32 lfsr(u32 val, int bits)
+{
+	u32 bit = val & 1;
+
+	/*
+	 * LFSR doesn't work with a start state of 0, so force it to a
+	 * non-zero value (bits) as the next state.
+	 */
+	if (val == 0)
+		return bits;
+
+	val >>= 1;
+	if (bit)
+		val ^= lfsr_taps(bits);
+	return val;
+}
+
+#endif /* _LINUX_LFSR_H */
diff --git a/tools/testing/selftests/lfsr/Makefile b/tools/testing/selftests/lfsr/Makefile
new file mode 100644
index 0000000..62a4ae4
--- /dev/null
+++ b/tools/testing/selftests/lfsr/Makefile
@@ -0,0 +1,11 @@
+# Makefile for lfsr self test
+
+CFLAGS += -O -I../../../../include/
+
+all: run-test
+
+run-test: test-lfsr
+	@./test-lfsr -v
+
+clean:
+	@rm -f test-lfsr test-lfsr.[so]
diff --git a/tools/testing/selftests/lfsr/test-lfsr.c b/tools/testing/selftests/lfsr/test-lfsr.c
new file mode 100644
index 0000000..156c643
--- /dev/null
+++ b/tools/testing/selftests/lfsr/test-lfsr.c
@@ -0,0 +1,70 @@
+/*
+ * Test the correctness of the lfsr.h header file.
+ * Usage: test-lfsr [-v]
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+typedef unsigned int u32;
+#define	BUG_ON(x)
+#define	BUILD_BUG_ON(x)
+#include <linux/lfsr.h>
+
+int verbose;
+
+int main(int argc, char **argv)
+{
+	int bit, value, initvalue, count, limit;
+	char errbuf[256];
+
+	if ((argc > 1) && (strncmp(argv[1], "-v", 2) == 0))
+		verbose++;
+	for (bit = LFSR_MIN_BITS; bit <= LFSR_MAX_BITS; bit++) {
+		if (verbose)
+			printf("Checking %2d-bit value cycling ...", bit);
+		/*
+		 * Test 1: an input value of 0 should give an non-zero output
+		 */
+		initvalue = lfsr(0, bit);
+		if (initvalue == 0) {
+			snprintf(errbuf, sizeof(errbuf),
+				"lfsr(0, %d) returns 0!", bit);
+			goto err_exit;
+		}
+		/*
+		 * Test 2: successive calls to lfsr() should cycle through
+		 *         (2^bit - 1) different values before going back
+		 *         to the initial value.
+		 */
+		count = 0;
+		value = initvalue;
+		limit = (1U << bit) - 1;
+		do {
+			value = lfsr(value, bit);
+			if (++count > limit) {
+				snprintf(errbuf, sizeof(errbuf),
+					"lfsr(*,%d) doesn't return to initial "
+					"value %d", bit, initvalue);
+				goto err_exit;
+			}
+		} while (value != initvalue);
+
+		if (count != limit) {
+			snprintf(errbuf, sizeof(errbuf),
+				"lfsr(*, %d) cycles through only 0x%x "
+				"different values!", bit, count);
+			goto err_exit;
+		}
+		if (verbose)
+			printf(" done.\n");
+	}
+	if (verbose)
+		printf("lfsr check completed successfully.\n");
+	return 0;
+
+err_exit:
+	fflush(stdout);
+	fprintf(stderr, "\nError: %s\n", errbuf);
+	exit(1);
+}
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ