--- /dev/null
+/* -*-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