symm/ocb1.h, symm/pmac1.h, ...: Implement PMAC1 and OCB1.
[catacomb] / symm / ocb.h
diff --git a/symm/ocb.h b/symm/ocb.h
new file mode 100644 (file)
index 0000000..d87aed3
--- /dev/null
@@ -0,0 +1,117 @@
+/* -*-c-*-
+ *
+ * Common definitions for OCB and related modes
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef CATACOMB_OCB_H
+#define CATACOMB_OCB_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+#include <mLib/compiler.h>
+
+/*----- Constants ---------------------------------------------------------*/
+
+/* The number of offsets to maintain.  Rather than calculate and store all
+ * possible offset values in advance, or calculate new ones on demand (and
+ * have to allocate space for them), we calculate a number in advance, and
+ * determine any others every time they're needed.  If we calculate the first
+ * %$n$% offsets only, then we spend %$i - n + 1$% time calculating offset
+ * %$L_i$% when %$i \ge n$%.  But the offset %$L_i$% is used only for a
+ * %$2^{-i-1}$% fraction of the blocks.  Summing up this geometric series
+ * shows us that we add only a small constant overhead, and save storage
+ * space for many offsets.
+ */
+#define OCB_NCALC 16
+#define OCB_CALCMASK ((1ul << OCB_NCALC) - 1)
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @ocb_ctz@, @ocb_ctzl@ --- *
+ *
+ * Arguments:  @unsigned i@ or @unsigned long i@ = operand, assumed nonzero
+ *
+ * Returns:    The number of trailing zero bits in @i@, or nonsense if
+ *             %$i = 0$%.
+ */
+
+extern unsigned ocb_ctz(unsigned /*i*/);
+extern unsigned ocb_ctzl(unsigned long /*i*/);
+
+#if GCC_VERSION_P(3, 4)
+#  define OCB_CTZ(i) __builtin_ctz(i)
+#  define OCB_CTZL(i) __builtin_ctzl(i)
+#else
+#  define OCB_CTZ(i) ocb_ctz(i)
+#  define OCB_CTZL(i) ocb_ctzl(i)
+#endif
+
+/* --- @OCB_OFFSET@ --- *
+ *
+ * Arguments:  @PRE@ = block cipher prefix
+ *             @uint32 *o@ = pointer to offset accumulator
+ *             @uint32 (*l)[PRE_BLKSZ]@ = pointer to offset mask table
+ *             @unsigned long i@ = block index
+ *
+ * Returns:    ---
+ *
+ * Use:                Update the per-block offset for Grey-code-based OCB
+ *             variants.  On entry, @o@ is assumed to hold the offset for
+ *             block @i - 1@; on exit @o@ is updated to hold the offset for
+ *             block @i@.
+ */
+
+#define OCB_OFFSET(PRE, o, l, i) do {                                  \
+  uint32 (*_l)[PRE##_BLKSZ/4] = (l);                                   \
+  uint32 *_o = (o);                                                    \
+  unsigned long _i = (i);                                              \
+  unsigned _j;                                                         \
+                                                                       \
+  if (_i&OCB_CALCMASK) {                                               \
+    _j = OCB_CTZ(_i);                                                  \
+    BLKC_XMOVE(PRE, _o, _l[_j]);                                       \
+  } else {                                                             \
+    uint32 _t[PRE##_BLKSZ];                                            \
+    _j = OCB_CTZL(_i) - OCB_NCALC;                                     \
+    BLKC_BLSHIFT(PRE, IRRED, _t, _l[OCB_NCALC - 1]);                   \
+    while (_j--) BLKC_BLSHIFT(PRE, IRRED, _t, _t);                     \
+    BLKC_XMOVE(PRE, _t, _l[_j]);                                       \
+  }                                                                    \
+} while (0)
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif