Import implementations of X25519 and X448 from Catacomb.
[secnet] / qfarith.h
diff --git a/qfarith.h b/qfarith.h
new file mode 100644 (file)
index 0000000..abcd293
--- /dev/null
+++ b/qfarith.h
@@ -0,0 +1,229 @@
+/* -*-c-*-
+ *
+ * Utilities for quick field arithmetic
+ *
+ * (c) 2017 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_QFARITH_H
+#define CATACOMB_QFARITH_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <limits.h>
+
+#include <mLib/bits.h>
+
+/*----- Signed integer types ----------------------------------------------*/
+
+/* See if we can find a suitable 64-bit or wider type.  Don't bother if we
+ * don't have a corresponding unsigned type, because we really need both.
+ */
+#ifdef HAVE_UINT64
+#  if INT_MAX >> 31 == 0xffffffff
+#    define HAVE_INT64
+     typedef int int64;
+#  elif LONG_MAX >> 31 == 0xffffffff
+#    define HAVE_INT64
+     typedef long int64;
+#  elif defined(LLONG_MAX)
+#    define HAVE_INT64
+     MLIB_BITS_EXTENSION typedef long long int64;
+#  endif
+#endif
+
+/* Choose suitable 32- and 16-bit types. */
+#if INT_MAX >= 0x7fffffff
+   typedef int int32;
+#else
+   typedef long int32;
+#endif
+
+typedef short int16;
+
+/*----- General bit-hacking utilities -------------------------------------*/
+
+/* Individual bits, and masks for low bits. */
+#define BIT(n) (1ul << (n))
+#define MASK(n) (BIT(n) - 1)
+
+/* Arithmetic right shift.  If X is a value of type TY, and N is a
+ * nonnegative integer, then return the value of X shifted right by N bits;
+ * alternatively, this is floor(X/2^N).
+ *
+ * GCC manages to compile this into a simple shift operation if one is
+ * available, but it's correct for all C targets.
+ */
+#define ASR(ty, x, n) (((x) - (ty)((u##ty)(x)&MASK(n)))/(ty)BIT(n))
+
+/*----- Constant-time utilities -------------------------------------------*/
+
+/* The following have better implementations on a two's complement target. */
+#ifdef NEG_TWOC
+
+  /* If we have two's complement arithmetic then masks are signed; this
+   * avoids a switch to unsigned representation, with the consequent problem
+   * of overflow when we convert back.
+   */
+  typedef int32 mask32;
+
+  /* Convert an unsigned mask M into a `mask32'.  This is a hairy-looking
+   * no-op on many targets, but, given that we have two's complement
+   * integers, it is free of arithmetic overflow.
+   */
+# define FIX_MASK32(m) \
+    ((mask32)((m)&0x7fffffffu) + (-(mask32)0x7fffffff - 1)*(((m) >> 31)&1u))
+
+  /* If Z is zero and M has its low 32 bits set, then copy (at least) the low
+   * 32 bits of X to Z; if M is zero, do nothing.  Otherwise, scramble Z
+   * unhelpfully.
+   */
+# define CONDPICK(z, x, m) do { (z) |= (x)&(m); } while (0)
+
+  /* If M has its low 32 bits set, then return (at least) the low 32 bits of
+   * X in Z; if M is zero, then return (at least) the low 32 bits of Y in Z.
+   * Otherwise, return an unhelful result.
+   */
+# define PICK2(x, y, m) (((x)&(m)) | ((y)&~(m)))
+
+  /* If M has its low 32 bits set then swap (at least) the low 32 bits of X
+   * and Y; if M is zero, then do nothing.  Otherwise, scramble X and Y
+   * unhelpfully.
+   */
+# define CONDSWAP(x, y, m)                                             \
+    do { mask32 t_ = ((x) ^ (y))&(m); (x) ^= t_; (y) ^= t_; } while (0)
+#else
+
+  /* We don't have two's complement arithmetic.  We can't use bithacking at
+   * all: if we try to hack on the bits of signed numbers we'll come unstuck
+   * when we hit the other representation of zero; and if we switch to
+   * unsigned arithmetic then we'll have overflow when we try to convert a
+   * negative number back.  So fall back to simple arithmetic.
+   */
+  typedef uint32 mask32;
+
+  /* Convert an unsigned mask M into a `mask32'.  Our masks are unsigned, so
+   * this does nothing.
+   */
+# define FIX_MASK32(m) ((mask32)(m))
+
+  /* If Z is zero and M has its low 32 bits set, then copy (at least) the low
+   * 32 bits of X to Z; if M is zero, do nothing.  Otherwise, scramble Z
+   * unhelpfully.
+   */
+# define CONDPICK(z, x, m)                                             \
+    do { (z) += (x)*(int)((unsigned)(m)&1u); } while (0)
+
+  /* If M has its low 32 bits set, then return (at least) the low 32 bits of
+   * X in Z; if M is zero, then return (at least) the low 32 bits of Y in Z.
+   * Otherwise, return an unhelful result.
+   */
+# define PICK2(x, y, m)                                                        \
+    ((x)*(int)((unsigned)(m)&1u) + (y)*(int)(1 - ((unsigned)(m)&1u)))
+
+  /* If M has its low 32 bits set then swap (at least) the low 32 bits of X
+   * and Y; if M is zero, then do nothing.  Otherwise, scramble X and Y
+   * unhelpfully.
+   */
+# define CONDSWAP(x, y, m) do {                                                \
+    int32 x_ = PICK2((y), (x), (m)), y_ = PICK2((x), (y), (m));                \
+    (x) = x_; (y) = y_;                                                        \
+  } while (0)
+#endif
+
+/* Return zero if bit 31 of X is clear, or a mask with (at least) the low 32
+ * bits set if bit 31 of X is set.
+ */
+#define SIGN(x) (-(mask32)(((uint32)(x) >> 31)&1))
+
+/* Return zero if X is zero, or a mask with (at least) the low 32 bits set if
+ * X is nonzero.
+ */
+#define NONZEROP(x) SIGN((U32(x) >> 1) - U32(x))
+
+/*----- Debugging utilities -----------------------------------------------*/
+
+/* Define a debugging function DUMPFN, which will dump an integer represented
+ * modulo M.  The integer is represented as a vector of NPIECE pieces of type
+ * PIECETY.  The pieces are assembled at possibly irregular offsets: piece i
+ * logically has width PIECEWD(i), but may overhang the next piece.  The
+ * pieces may be signed.  GETMOD is an expression which calculates and
+ * returns the value of M, as an `mp *'.
+ *
+ * The generated function writes the value of such an integer X to the stream
+ * FP, labelled with the string WHAT.
+ *
+ * The definition assumes that <stdio.h>, <catacomb/mp.h>, and
+ * <catacomb/mptext.h> have been included.
+ */
+#define DEF_FDUMP(dumpfn, piecety, piecewd, npiece, noctet, getmod)    \
+  static void dumpfn(FILE *fp, const char *what, const piecety *x)     \
+  {                                                                    \
+    mpw w;                                                             \
+    mp m, *y = MP_ZERO, *t = MP_NEW, *p;                               \
+    octet b[noctet];                                                   \
+    unsigned i, o;                                                     \
+                                                                       \
+    p = getmod;                                                                \
+    mp_build(&m, &w, &w + 1);                                          \
+    for (i = o = 0; i < npiece; i++) {                                 \
+      if (x[i] >= 0) { w = x[i]; m.f &= ~MP_NEG; }                     \
+      else { w = -x[i]; m.f |= MP_NEG; }                               \
+      t = mp_lsl(t, &m, o);                                            \
+      y = mp_add(y, y, t);                                             \
+      o += piecewd(i);                                                 \
+    }                                                                  \
+                                                                       \
+    fprintf(fp, "%s = <", what);                                       \
+    for (i = 0; i < npiece; i++) {                                     \
+      if (i) fputs(", ", fp);                                          \
+      fprintf(fp, "%ld", (long)x[i]);                                  \
+    }                                                                  \
+    fputs(">\n\t= ", fp);                                              \
+    mp_writefile(y, fp, 10);                                           \
+    fputs("\n\t== ", fp);                                              \
+    mp_div(0, &y, y, p);                                               \
+    mp_writefile(y, fp, 10);                                           \
+    fputs("\n\t= 0x", fp);                                             \
+    mp_writefile(y, fp, 16);                                           \
+    fputs(" (mod 2^255 - 19)\n\t= [", fp);                             \
+    mp_storel(y, b, sizeof(b));                                                \
+    for (i = 0; i < 32; i++) {                                         \
+      if (i && !(i%4)) fputc(':', fp);                                 \
+      fprintf(fp, "%02x", b[i]);                                       \
+    }                                                                  \
+    fputs("]\n", fp);                                                  \
+    mp_drop(y); mp_drop(p); mp_drop(t);                                        \
+  }
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif