endif
check: eax-aes-test.confirm eax-serpent-test.confirm \
- eax-serpentbe-test.confirm check-ipaddrset
+ eax-serpentbe-test.confirm check-ipaddrset \
+ msgcode-test.confirm
version.c: Makefile
echo "#include \"secnet.h\"" >$@.new
./$< <$(srcdir)/eax-$*-test.vectors >$@.new
mv -f $@.new $@
+msgcode-test: msgcode-test.o
+ $(CC) $(LDFLAGS) $(ALL_CFLAGS) -o $@ $^
+
+msgcode-test.confirm: msgcode-test
+ ./msgcode-test
+ touch $@
+
check-ipaddrset: ipaddrset-test.py ipaddrset.py ipaddrset-test.expected
$(srcdir)/ipaddrset-test.py >ipaddrset-test.new
diff -u $(srcdir)/ipaddrset-test.expected ipaddrset-test.new
clean:
$(RM) -f *.o *.yy.[ch] *.tab.[ch] $(TARGETS) core version.c
$(RM) -f *.d *.pyc *~ eax-*-test.confirm eax-*-test
+ $(RM) -f msgcode-test.confirm msgcode-test
realclean: clean
$(RM) -f *~ Makefile config.h *.d \
#ifndef magic_h
#define magic_h
-#define LABEL_NAK 0x00000000
-#define LABEL_MSG0 0x00020200
-#define LABEL_MSG1 0x01010101
-#define LABEL_MSG2 0x02020202
-#define LABEL_MSG3 0x03030303
-#define LABEL_MSG3BIS 0x13030313
-#define LABEL_MSG4 0x04040404
-#define LABEL_MSG5 0x05050505
-#define LABEL_MSG6 0x06060606
-#define LABEL_MSG7 0x07070707
-#define LABEL_MSG8 0x08080808
-#define LABEL_MSG9 0x09090909
-#define LABEL_PROD 0x0a0a0a0a
+/* Encode a pair of 16 bit major and minor codes as a single 32-bit label.
+ * The encoding is strange for historical reasons. Suppose that the nibbles
+ * of the major number are (from high to low) a, b, c, d, and the minor
+ * number has nibbles w, x, y, z. (Here, a, b, c, d are variables, not hex
+ * digits.) We scramble them to form a message label as follows.
+ *
+ * 0 d 0 d 0 d 0 d
+ * 0 0 0 a b c 0 0
+ * z 0 0 0 0 0 z 0
+ * w x y 0 0 0 0 0
+ * ---------------
+ * f g h i j k l m
+ *
+ * and calculate the nibbles f, g, ..., m of the message label (higher
+ * significance on the left) by XORing the columns. It can be shown that
+ * this is invertible using linear algebra in GF(16), but but it's easier to
+ * notice that d = m, z = l, c = k XOR d, b = j, a = i XOR d, y = h,
+ * x = g XOR d, and w = f XOR z.
+ *
+ * Encoding in the forward direction, from a major/minor pair to a label, is
+ * (almost?) always done on constants, so its performance is fairly
+ * unimportant. There is a compatibility constraint on the patterns produced
+ * with a = b = c = w = x = y = 0. Subject to that, I wanted to find an
+ * invertible GF(16)-linear transformation which would let me recover the
+ * major and minor numbers with relatively little calculation.
+ */
+
+#define MSGCODE(major, minor) \
+ ((((uint32_t)(major)&0x0000000fu) << 0) ^ \
+ (((uint32_t)(major)&0x0000000fu) << 8) ^ \
+ (((uint32_t)(major)&0x0000000fu) << 16) ^ \
+ (((uint32_t)(major)&0x0000000fu) << 24) ^ \
+ (((uint32_t)(major)&0x0000fff0u) << 4) ^ \
+ (((uint32_t)(minor)&0x0000000fu) << 4) ^ \
+ (((uint32_t)(minor)&0x0000000fu) << 28) ^ \
+ (((uint32_t)(minor)&0x0000fff0u) << 16))
+
+/* Extract major and minor codes from a 32-bit message label. */
+#define MSGMAJOR(label) \
+ ((((uint32_t)(label)&0x0000000fu) << 0) ^ \
+ (((uint32_t)(label)&0x0000000fu) << 4) ^ \
+ (((uint32_t)(label)&0x0000000fu) << 12) ^ \
+ (((uint32_t)(label)&0x000fff00u) >> 4))
+#define MSGMINOR(label) \
+ ((((uint32_t)(label)&0x000000ffu) << 8) ^ \
+ (((uint32_t)(label)&0x000000f0u) >> 4) ^ \
+ (((uint32_t)(label)&0xfff00000u) >> 16))
+
+#define LABEL_NAK MSGCODE( 0, 0)
+#define LABEL_MSG0 MSGCODE(0x2020, 0) /* ! */
+#define LABEL_MSG1 MSGCODE( 1, 0)
+#define LABEL_MSG2 MSGCODE( 2, 0)
+#define LABEL_MSG3 MSGCODE( 3, 0)
+#define LABEL_MSG3BIS MSGCODE( 3, 1)
+#define LABEL_MSG4 MSGCODE( 4, 0)
+#define LABEL_MSG5 MSGCODE( 5, 0)
+#define LABEL_MSG6 MSGCODE( 6, 0)
+#define LABEL_MSG7 MSGCODE( 7, 0)
+#define LABEL_MSG8 MSGCODE( 8, 0)
+#define LABEL_MSG9 MSGCODE( 9, 0)
+#define LABEL_PROD MSGCODE( 10, 0)
/*
* The capability mask is a set of bits, one for each optional feature
--- /dev/null
+/*
+ * msgcode-test.c: check that the new message encoding is correct
+ */
+/*
+ * This file is Free Software. It was originally written for secnet.
+ *
+ * Copyright 2017 Mark Wooding
+ *
+ * You may redistribute secnet as a whole and/or modify it under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3, or (at your option) any
+ * later version.
+ *
+ * You may redistribute this file and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, see
+ * https://www.gnu.org/licenses/gpl.html.
+ */
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "magic.h"
+
+#define OLD_LABEL_NAK 0x00000000
+#define OLD_LABEL_MSG0 0x00020200
+#define OLD_LABEL_MSG1 0x01010101
+#define OLD_LABEL_MSG2 0x02020202
+#define OLD_LABEL_MSG3 0x03030303
+#define OLD_LABEL_MSG3BIS 0x13030313
+#define OLD_LABEL_MSG4 0x04040404
+#define OLD_LABEL_MSG5 0x05050505
+#define OLD_LABEL_MSG6 0x06060606
+#define OLD_LABEL_MSG7 0x07070707
+#define OLD_LABEL_MSG8 0x08080808
+#define OLD_LABEL_MSG9 0x09090909
+#define OLD_LABEL_PROD 0x0a0a0a0a
+
+static void check_labels(const char *what, uint32_t new, uint32_t old)
+{
+ if (old != new) {
+ printf("mismatch for %s: %08"PRIx32" (new) /= %08"PRIx32" (old)\n",
+ what, new, old);
+ exit(2);
+ }
+}
+
+int main(void)
+{
+ unsigned i, j;
+ uint32_t m, r, s;
+
+#define CHECK(label) check_labels(#label, LABEL_##label, OLD_LABEL_##label)
+ CHECK(NAK);
+ CHECK(MSG0);
+ CHECK(MSG1);
+ CHECK(MSG2);
+ CHECK(MSG3);
+ CHECK(MSG3BIS);
+ CHECK(MSG4);
+ CHECK(MSG5);
+ CHECK(MSG6);
+ CHECK(MSG7);
+ CHECK(MSG8);
+ CHECK(MSG9);
+ CHECK(PROD);
+#undef CHECK
+ for (i = 0; i < 65536; i++) {
+ for (j = 0; j < 65536; j++) {
+ m = MSGCODE(i, j);
+ r = MSGMAJOR(m); s = MSGMINOR(m);
+ if (r != i || s != j) {
+ printf("roundtrip fail: %04x %04x -> %08"PRIx32" "
+ "-> %08"PRIx32" %08"PRIx32"\n",
+ i, j, m, r, s);
+ exit(2);
+ }
+ }
+ }
+
+ return (0);
+}
local PF = { } -- The table of protocol fields, filled in later.
local F = { } -- A table of field values, also filled in later.
+local function msgcode(major, minor)
+ -- Construct a Secnet message number according to the complicated rules.
+
+ local majlo = bit.band(major, 0x000f)
+ local majhi = bit.band(major, 0xfff0)
+ local minlo = bit.band(minor, 0x000f)
+ local minhi = bit.band(minor, 0xfff0)
+ return bit.bxor(bit.lshift(majlo, 0),
+ bit.lshift(majlo, 8),
+ bit.lshift(majlo, 16),
+ bit.lshift(majlo, 24),
+ bit.lshift(majhi, 4),
+ bit.lshift(minlo, 4),
+ bit.lshift(minlo, 28),
+ bit.lshift(minhi, 16))
+end
+
+local function msgmajor(label)
+ -- Return the major message number from a LABEL.
+
+ local lo = bit.band(label, 0x000f)
+ local hi = bit.band(bit.rshift(label, 4), 0xfff0)
+ return bit.bxor(lo, bit.lshift(lo, 4), bit.lshift(lo, 12), hi)
+end
+
+local function msgminor(label)
+ -- Return the minor message number from a LABEL.
+
+ return bit.bxor(bit.lshift(bit.band(label, 0x00ff), 8),
+ bit.band(bit.rshift(label, 4), 0x000f),
+ bit.band(bit.rshift(label, 16), 0xfff0))
+end
+
-- Main message-number table.
-local M = { NAK = 0x00000000
- MSG0 = 0x00020200
- MSG1 = 0x01010101
- MSG2 = 0x02020202
- MSG3 = 0x03030303
- MSG3BIS = 0x13030313
- MSG4 = 0x04040404
- MSG5 = 0x05050505
- MSG6 = 0x06060606
- MSG7 = 0x07070707
- MSG8 = 0x08080808
- MSG9 = 0x09090909
- PROD = 0x0a0a0a0a }
+local M = { NAK = msgcode( 0, 0),
+ MSG0 = msgcode(0x2020, 0), -- !
+ MSG1 = msgcode( 1, 0),
+ MSG2 = msgcode( 2, 0),
+ MSG3 = msgcode( 3, 0),
+ MSG3BIS = msgcode( 3, 1),
+ MSG4 = msgcode( 4, 0),
+ MSG5 = msgcode( 5, 0),
+ MSG6 = msgcode( 6, 0),
+ MSG7 = msgcode( 7, 0),
+ MSG8 = msgcode( 8, 0),
+ MSG9 = msgcode( 9, 0),
+ PROD = msgcode( 10, 0)}
-- The `dissect_*' functions follow a common protocol. They parse a thing
-- from a packet buffer BUF, of size SZ, starting from POS, and store