symm: Implement Bernstein's ChaCha stream cipher.
[catacomb] / symm / chacha-core.h
diff --git a/symm/chacha-core.h b/symm/chacha-core.h
new file mode 100644 (file)
index 0000000..ad6b05f
--- /dev/null
@@ -0,0 +1,137 @@
+/* -*-c-*-
+ *
+ * ChaCha core definitions
+ *
+ * (c) 2015 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_CHACHA_CORE_H
+#define CATACOMB_CHACHA_CORE_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+#include <mLib/macros.h>
+
+#ifndef CATACOMB_CHACHA_H
+#  include "chacha.h"
+#endif
+
+#ifndef CATACOMB_SALSA20_CORE_H
+#  include "salsa20-core.h"
+#endif
+
+/*----- Magic constants ---------------------------------------------------*/
+
+/* The magic ChaCha constants are the same as the Salsa20 ones.  For 256-bit
+ * keys ...
+ */
+#define CHACHA_A256 SALSA20_A256       /* e x p a */
+#define CHACHA_B256 SALSA20_B256       /* n d   3 */
+#define CHACHA_C256 SALSA20_C256       /* 2 - b y */
+#define CHACHA_D256 SALSA20_D256       /* t e   k */
+
+/* ... and for 128-bit keys ... */
+#define CHACHA_A128 SALSA20_A128       /* e x p a */
+#define CHACHA_B128 SALSA20_B128       /* n d   1 */
+#define CHACHA_C128 SALSA20_C128       /* 6 - b y */
+#define CHACHA_D128 SALSA20_D128       /* t e   k */
+
+/* ... and for 80-bit keys, for completeness's sake. */
+#define CHACHA_A80 SALSA20_A80         /* e x p a */
+#define CHACHA_B80 SALSA20_B80         /* n d   1 */
+#define CHACHA_C80 SALSA20_C80         /* 0 - b y */
+#define CHACHA_D80 SALSA20_D80         /* t e   k */
+
+/*----- The ChaCha core function ------------------------------------------*/
+
+/* The ChaCha quarter round.  Read from the matrix @y@ at indices @a@, @b@,
+ * @c@, and @d@; and write to the corresponding elements of @z@.
+ */
+#define CHACHA_QR(z, y, a, b, c, d) do {                               \
+  (z)[a] = (y)[a] + (y)[b]; (z)[d] = ROL32((y)[d] ^ (z)[a], 16);       \
+  (z)[c] = (y)[c] + (z)[d]; (z)[b] = ROL32((y)[b] ^ (z)[c], 12);       \
+  (z)[a] = (z)[a] + (z)[b]; (z)[d] = ROL32((z)[d] ^ (z)[a],  8);       \
+  (z)[c] = (z)[c] + (z)[d]; (z)[b] = ROL32((z)[b] ^ (z)[c],  7);       \
+} while (0)
+
+/* The ChaCha double-round.  Read from matrix @y@, writing the result to
+ * @z@.
+ */
+#define CHACHA_DR(z, y) do {                                           \
+  CHACHA_QR(z, y,  0,  4,  8, 12);                                     \
+  CHACHA_QR(z, y,  1,  5,  9, 13);                                     \
+  CHACHA_QR(z, y,  2,  6, 10, 14);                                     \
+  CHACHA_QR(z, y,  3,  7, 11, 15);                                     \
+  CHACHA_QR(z, z,  0,  5, 10, 15);                                     \
+  CHACHA_QR(z, z,  1,  6, 11, 12);                                     \
+  CHACHA_QR(z, z,  2,  7,  8, 13);                                     \
+  CHACHA_QR(z, z,  3,  4,  9, 14);                                     \
+} while (0)
+
+/* The ChaCha feedforward step, used at the end of the core function.  Here,
+ * @y@ contains the original input matrix; @z@ contains the final one, and is
+ * updated.  This is the same as Salsa20.
+ */
+#define CHACHA_FFWD(z, y) SALSA20_FFWD(z, y)
+
+/* Various numbers of rounds, unrolled.  Read from @y@, and write to @z@. */
+#define CHACHA_4R(z, y)                                                        \
+  do { CHACHA_DR(z, y); CHACHA_DR(z, z); } while (0)
+#define CHACHA_8R(z, y)                                                        \
+  do { CHACHA_4R(z, y); CHACHA_4R(z, z); } while (0)
+#define CHACHA_12R(z, y)                                               \
+  do { CHACHA_8R(z, y); CHACHA_4R(z, z); } while (0)
+#define CHACHA_20R(z, y)                                               \
+  do { CHACHA_12R(z, y); CHACHA_8R(z, z); } while (0)
+
+/* Apply @n@ (must be even) rounds, rolled.  (This seems to be faster,
+ * probably because it fits in cache better).  Read from @y@, and write to
+ * @z@.
+ */
+#define CHACHA_nR(z, y, n) do {                                                \
+  int _i;                                                              \
+  CHACHA_DR(z, y);                                                     \
+  for (_i = 0; _i < (n)/2 - 1; _i++) CHACHA_DR(z, z);                  \
+} while (0)
+
+/* Step the counter in the Chacha state matrix @a@. */
+#define CHACHA_STEP(a)                                                 \
+  do { (a)[12] = U32((a)[12] + 1); (a)[13] += !(a)[12]; } while (0)
+
+/*----- Variants and naming -----------------------------------------------*/
+
+/* Common numbers of rounds, for which we generate definitions. */
+#define CHACHA_VARS(_) _(8) _(12) _(20)
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif