catcrypt: Implement symmetric key-encapsulation and signature schemes.
[u/mdw/catacomb] / mpx.h
diff --git a/mpx.h b/mpx.h
index 88f547c..f79cffd 100644 (file)
--- a/mpx.h
+++ b/mpx.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: mpx.h,v 1.4 1999/11/17 18:04:43 mdw Exp $
+ * $Id: mpx.h,v 1.18 2004/04/08 01:36:15 mdw Exp $
  *
  * Low level multiprecision arithmetic
  *
  * MA 02111-1307, USA.
  */
 
-/*----- Revision history --------------------------------------------------* 
- *
- * $Log: mpx.h,v $
- * Revision 1.4  1999/11/17 18:04:43  mdw
- * Add two's complement support.  Fix a bug in MPX_UMLAN.
- *
- * Revision 1.3  1999/11/13 01:51:29  mdw
- * Minor interface changes.  Should be stable now.
- *
- * Revision 1.2  1999/11/11 17:47:55  mdw
- * Minor changes for different `mptypes.h' format.
- *
- * Revision 1.1  1999/09/03 08:41:12  mdw
- * Initial import.
- *
- */
-
-#ifndef MPX_H
-#define MPX_H
+#ifndef CATACOMB_MPX_H
+#define CATACOMB_MPX_H
 
 #ifdef __cplusplus
   extern "C" {
@@ -68,7 +51,7 @@
 
 #include <string.h>
 
-#ifndef MPW_H
+#ifndef CATACOMB_MPW_H
 #  include "mpw.h"
 #endif
 
  */
 
 #define MPX_OCTETS(o, v, vl) do {                                      \
-  const mpw *_v = (v), *_vl = (vl);                                    \
-  MPX_SHRINK(_v, _vl);                                                 \
-  if (_v == _vl)                                                       \
-    (o) = 0;                                                           \
-  else {                                                               \
-    size_t _o = (MPW_BITS / 8) * (_vl - _v - 1);                       \
-    mpw _w = _vl[-1];                                                  \
-    unsigned _k = MPW_BITS / 2;                                                \
-    while (_k >= 8) {                                                  \
-      if (_w >> _k) {                                                  \
-       _w >>= _k;                                                      \
-       _o += _k >> 3;                                                  \
-      }                                                                        \
-      _k >>= 1;                                                                \
-    }                                                                  \
-    if (_w)                                                            \
-      _o++;                                                            \
-    (o) = _o;                                                          \
-  }                                                                    \
+  unsigned long _bb;                                                   \
+  MPX_BITS(_bb, (v), (vl));                                            \
+  (o) = (_bb + 7) >> 3;                                                        \
+} while (0)
+
+/* --- @MPX_OCTETS2C@ --- *
+ *
+ * Arguments:  @size_t o@ = result variable
+ *             @const mpw *v, *vl@ = pointer to array of words
+ *
+ * Use:                Calculates the number of octets in a multiprecision value, if
+ *             you represent it as two's complement.
+ */
+
+#define MPX_OCTETS2C(o, v, vl) do {                                    \
+  unsigned long _bb;                                                   \
+  MPX_BITS(_bb, (v), (vl));                                            \
+  (o) = (_bb >> 3) + 1;                                                        \
 } while (0)
 
 /* --- @MPX_COPY@ --- *
     memset(_v, 0, MPWS(_vl - _v));                                     \
 } while (0)
 
+/* --- @MPX_ONE@ --- *
+ *
+ * Arguments:  @v, vl@ = base and limit of vector to clear
+ *
+ * Use:                Fills the area between the two vector pointers with ones.
+ */
+
+#define MPX_ONE(v, vl) do {                                            \
+  mpw * _v = (v);                                                      \
+  const mpw *_vl = (vl);                                               \
+  while (_v < _vl)                                                     \
+    *_v++ = MPW_MAX;                                                   \
+} while (0)
+
 /*----- Loading and storing -----------------------------------------------*/
 
 /* --- @mpx_storel@ --- *
@@ -251,6 +247,75 @@ extern void mpx_storeb(const mpw */*v*/, const mpw */*vl*/,
 extern void mpx_loadb(mpw */*v*/, mpw */*vl*/,
                      const void */*p*/, size_t /*sz*/);
 
+/* --- @mpx_storel2cn@ --- *
+ *
+ * Arguments:  @const mpw *v, *vl@ = base and limit of source vector
+ *             @void *pp@ = pointer to octet array
+ *             @size_t sz@ = size of octet array
+ *
+ * Returns:    ---
+ *
+ * Use:                Stores a negative MP in an octet array, least significant
+ *             octet first, as two's complement.  High-end octets are
+ *             silently discarded if there isn't enough space for them.
+ *             This obviously makes the output bad.
+ */
+
+extern void mpx_storel2cn(const mpw */*v*/, const mpw */*vl*/,
+                         void */*p*/, size_t /*sz*/);
+
+/* --- @mpx_loadl2cn@ --- *
+ *
+ * Arguments:  @mpw *v, *vl@ = base and limit of destination vector
+ *             @const void *pp@ = pointer to octet array
+ *             @size_t sz@ = size of octet array
+ *
+ * Returns:    ---
+ *
+ * Use:                Loads a negative MP in an octet array, least significant
+ *             octet first, as two's complement.  High-end octets are
+ *             ignored if there isn't enough space for them.  This probably
+ *             means you made the wrong choice coming here.
+ */
+
+extern void mpx_loadl2cn(mpw */*v*/, mpw */*vl*/,
+                        const void */*p*/, size_t /*sz*/);
+
+/* --- @mpx_storeb2cn@ --- *
+ *
+ * Arguments:  @const mpw *v, *vl@ = base and limit of source vector
+ *             @void *pp@ = pointer to octet array
+ *             @size_t sz@ = size of octet array
+ *
+ * Returns:    ---
+ *
+ * Use:                Stores a negative MP in an octet array, most significant
+ *             octet first, as two's complement.  High-end octets are
+ *             silently discarded if there isn't enough space for them,
+ *             which probably isn't what you meant.
+ */
+
+extern void mpx_storeb2cn(const mpw */*v*/, const mpw */*vl*/,
+                         void */*p*/, size_t /*sz*/);
+
+/* --- @mpx_loadb2cn@ --- *
+ *
+ * Arguments:  @mpw *v, *vl@ = base and limit of destination vector
+ *             @const void *pp@ = pointer to octet array
+ *             @size_t sz@ = size of octet array
+ *
+ * Returns:    ---
+ *
+ * Use:                Loads a negative MP in an octet array, most significant octet
+ *             first as two's complement.  High-end octets are ignored if
+ *             there isn't enough space for them.  This probably means you
+ *             chose this function wrongly.
+ */
+
+extern void mpx_loadb2cn(mpw */*v*/, mpw */*vl*/,
+                        const void */*p*/, size_t /*sz*/);
+
+
 /*----- Logical shifting --------------------------------------------------*/
 
 /* --- @mpx_lsl@ --- *
@@ -268,6 +333,22 @@ extern void mpx_lsl(mpw */*dv*/, mpw */*dvl*/,
                    const mpw */*av*/, const mpw */*avl*/,
                    size_t /*n*/);
 
+/* --- @mpx_lslc@ --- *
+ *
+ * Arguments:  @mpw *dv, *dvl@ = destination vector base and limit
+ *             @const mpw *av, *avl@ = source vector base and limit
+ *             @size_t n@ = number of bit positions to shift by
+ *
+ * Returns:    ---
+ *
+ * Use:                Performs a logical shift left operation on an integer, only
+ *             it fills in the bits with ones instead of zeroes.
+ */
+
+extern void mpx_lslc(mpw */*dv*/, mpw */*dvl*/,
+                    const mpw */*av*/, const mpw */*avl*/,
+                    size_t /*n*/);
+
 /* --- @mpx_lsr@ --- *
  *
  * Arguments:  @mpw *dv, *dvl@ = destination vector base and limit
@@ -283,6 +364,60 @@ extern void mpx_lsr(mpw */*dv*/, mpw */*dvl*/,
                    const mpw */*av*/, const mpw */*avl*/,
                    size_t /*n*/);
 
+/*----- Bitwise operations ------------------------------------------------*/
+
+/* --- @mpx_bitop@ --- *
+ *
+ * Arguments:  @mpw *dv, *dvl@ = destination vector
+ *             @const mpw *av, *avl@ = first source vector
+ *             @const mpw *bv, *bvl@ = second source vector
+ *
+ * Returns:    ---
+ *
+ * Use:                Provide the dyadic boolean functions.  The functions are
+ *             named after the truth table they generate:
+ *
+ *                     a:      0011
+ *                     b:      0101
+ *                     @mpx_bitXXXX@
+ */
+
+#define MPX_DOBIN(what)                                                        \
+  what(0000) what(0001) what(0010) what(0011)                          \
+  what(0100) what(0101) what(0110) what(0111)                          \
+  what(1000) what(1001) what(1010) what(1011)                          \
+  what(1100) what(1101) what(1110) what(1111)
+
+#define MPX_BITDECL(string)                                            \
+  extern void mpx_bit##string(mpw */*dv*/, mpw */*dvl*/,               \
+                             const mpw */*av*/, const mpw */*avl*/,    \
+                             const mpw */*bv*/, const mpw */*bvl*/);
+MPX_DOBIN(MPX_BITDECL)
+
+/* --- @mpx_[n]and@, @mpx_[n]or@, @mpx_xor@ --- *
+ *
+ * Synonyms for the commonly-used functions above.
+ */
+
+#define mpx_and  mpx_bit0001
+#define mpx_or   mpx_bit0111
+#define mpx_nand mpx_bit1110
+#define mpx_nor  mpx_bit1000
+#define mpx_xor  mpx_bit0110
+
+/* --- @mpx_not@ --- *
+ *
+ * Arguments:  @mpw *dv, *dvl@ = destination vector
+ *             @const mpw *av, *avl@ = first source vector
+ *
+ * Returns:    ---
+ *
+ * Use;                Bitwise NOT.
+ */
+
+extern void mpx_not(mpw */*dv*/, mpw */*dvl*/,
+                   const mpw */*av*/, const mpw */*avl*/);
+
 /*----- Unsigned arithmetic -----------------------------------------------*/
 
 /* --- @mpx_2c@ --- *
@@ -298,6 +433,19 @@ extern void mpx_lsr(mpw */*dv*/, mpw */*dvl*/,
 extern void mpx_2c(mpw */*dv*/, mpw */*dvl*/,
                   const mpw */*v*/, const mpw */*vl*/);
 
+/* --- @mpx_ueq@ --- *
+ *
+ * Arguments:  @const mpw *av, *avl@ = first argument vector base and limit
+ *             @const mpw *bv, *bvl@ = second argument vector base and limit
+ *
+ * Returns:    Nonzero if the two vectors are equal.
+ *
+ * Use:                Performs an unsigned integer test for equality.
+ */
+
+extern int mpx_ueq(const mpw */*av*/, const mpw */*avl*/,
+                  const mpw */*bv*/, const mpw */*bvl*/);
+
 /* --- @mpx_ucmp@ --- *
  *
  * Arguments:  @const mpw *av, *avl@ = first argument vector base and limit
@@ -336,10 +484,12 @@ extern void mpx_uadd(mpw */*dv*/, mpw */*dvl*/,
                     const mpw */*av*/, const mpw */*avl*/,
                     const mpw */*bv*/, const mpw */*bvl*/);
 
-/* --- @MPX_UADDN@ --- *
+/* --- @mpx_uaddn@ --- *
+ *
+ * Arguments:  @mpw *dv, *dvl@ = source and destination base and limit
+ *             @mpw n@ = other addend
  *
- * Arguments:  @dv, dvl@ = source and destination vector base and limit
- *             @n@ = other addend
+ * Returns:    ---
  *
  * Use:                Adds a small integer to a multiprecision number.
  */
@@ -355,6 +505,24 @@ extern void mpx_uadd(mpw */*dv*/, mpw */*dvl*/,
   }                                                                    \
 } while (0)
 
+extern void mpx_uaddn(mpw */*dv*/, mpw */*dvl*/, mpw /*n*/);
+
+/* --- @mpx_uaddnlsl@ --- *
+ *
+ * Arguments:  @mpw *dv, *dvl@ = destination and first argument vector
+ *             @mpw a@ = second argument
+ *             @unsigned o@ = offset in bits
+ *
+ * Returns:    ---
+ *
+ * Use:                Computes %$d + 2^o a$%.  If the result overflows then
+ *             high-order bits are discarded, as usual.  We must have
+ *             @0 < o < MPW_BITS@.
+ */
+
+extern void mpx_uaddnlsl(mpw */*dv*/, mpw */*dvl*/,
+                        mpw /*a*/, unsigned /*o*/);
+
 /* --- @mpx_usub@ --- *
  *
  * Arguments:  @mpw *dv, *dvl@ = destination vector base and limit
@@ -376,10 +544,12 @@ extern void mpx_usub(mpw */*dv*/, mpw */*dvl*/,
                     const mpw */*av*/, const mpw */*avl*/,
                     const mpw */*bv*/, const mpw */*bvl*/);
 
-/* --- @MPX_USUBN@ --- *
+/* --- @mpx_usubn@ --- *
+ *
+ * Arguments:  @mpw *dv, *dvl@ = source and destination base and limit
+ *             @n@ = subtrahend
  *
- * Arguments:  @@dv, dvl@ = destination vector base and limit
- *             @n@ = other addend
+ * Returns:    ---
  *
  * Use:                Subtracts a small integer from a multiprecision number.
  */
@@ -398,6 +568,25 @@ extern void mpx_usub(mpw */*dv*/, mpw */*dvl*/,
   }                                                                    \
 } while (0)
 
+extern void mpx_usubn(mpw */*dv*/, mpw */*dvl*/, mpw /*n*/);
+
+/* --- @mpx_usubnlsl@ --- *
+ *
+ * Arguments:  @mpw *dv, *dvl@ = destination and first argument vector
+ *             @mpw a@ = second argument
+ *             @unsigned o@ = offset in bits
+ *
+ * Returns:    ---
+ *
+ * Use:                Computes %$d - 2^o a$%.  If the result overflows then
+ *             high-order bits are discarded, as usual, so you get two's
+ *             complement.  Which might be what you wanted...  We must have
+ *             @0 < o < MPW_BITS@.
+ */
+
+extern void mpx_usubnlsl(mpw */*dv*/, mpw */*dvl*/,
+                        mpw /*a*/, unsigned /*o*/);
+
 /* --- @mpx_umul@ --- *
  *
  * Arguments:  @mpw *dv, *dvl@ = destination vector base and limit
@@ -416,11 +605,13 @@ extern void mpx_umul(mpw */*dv*/, mpw */*dvl*/,
                     const mpw */*av*/, const mpw */*avl*/,
                     const mpw */*bv*/, const mpw */*bvl*/);
 
-/* --- @MPX_UMULN@ --- *
+/* --- @mpx_umuln@ --- *
  *
- * Arguments:  @dv, dvl@ = destination vector base and limit
- *             @av, avl@ = multiplicand vector base and limit
- *             @m@ = multiplier
+ * Arguments:  @mpw *dv, *dvl@ = destination vector base and limit
+ *             @const mpw *av, *avl@ = multiplicand vector base and limit
+ *             @mpw m@ = multiplier
+ *
+ * Returns:    ---
  *
  * Use:                Multiplies a multiprecision integer by a single-word value.
  *             The destination and source may be equal.  The destination
@@ -447,11 +638,16 @@ extern void mpx_umul(mpw */*dv*/, mpw */*dvl*/,
   }                                                                    \
 } while (0)
 
-/* --- @MPX_UMLAN@ --- *
+extern void mpx_umuln(mpw */*dv*/, mpw */*dvl*/,
+                     const mpw */*av*/, const mpw */*avl*/, mpw m);
+
+/* --- @mpx_umlan@ --- *
  *
- * Arguments:  @dv, dvl@ = destination/accumulator vector base and limit
- *             @av, avl@ = multiplicand vector base and limit
- *             @m@ = multiplier
+ * Arguments:  @mpw *dv, *dvl@ = destination/accumulator base and limit
+ *             @const mpw *av, *avl@ = multiplicand vector base and limit
+ *             @mpw m@ = multiplier
+ *
+ * Returns:    ---
  *
  * Use:                Multiplies a multiprecision integer by a single-word value
  *             and adds the result to an accumulator.
@@ -463,10 +659,8 @@ extern void mpx_umul(mpw */*dv*/, mpw */*dvl*/,
   mpw _cc = 0;                                                         \
   mpd _m = (m);                                                                \
                                                                        \
-  while (_av < _avl) {                                                 \
+  while (_dv < _dvl && _av < _avl) {                                   \
     mpd _x;                                                            \
-    if (_dv >= _dvl)                                                   \
-      break;                                                           \
     _x = (mpd)*_dv + (mpd)_m * (mpd)*_av++ + _cc;                      \
     *_dv++ = MPW(_x);                                                  \
     _cc = _x >> MPW_BITS;                                              \
@@ -474,6 +668,9 @@ extern void mpx_umul(mpw */*dv*/, mpw */*dvl*/,
   MPX_UADDN(_dv, _dvl, _cc);                                           \
 } while (0)
 
+extern void mpx_umlan(mpw */*dv*/, mpw */*dvl*/,
+                     const mpw */*av*/, const mpw */*avl*/, mpw m);
+
 /* --- @mpx_usqr@ --- *
  *
  * Arguments:  @mpw *dv, *dvl@ = destination vector base and limit
@@ -511,6 +708,80 @@ extern void mpx_udiv(mpw */*qv*/, mpw */*qvl*/, mpw */*rv*/, mpw */*rvl*/,
                     const mpw */*dv*/, const mpw */*dvl*/,
                     mpw */*sv*/, mpw */*svl*/);
 
+/* --- @mpx_udivn@ --- *
+ *
+ * Arguments:  @mpw *qv, *qvl@ = storage for the quotient (may overlap
+ *                     dividend)
+ *             @const mpw *rv, *rvl@ = dividend
+ *             @mpw d@ = single-precision divisor
+ *
+ * Returns:    Remainder after divison.
+ *
+ * Use:                Performs a single-precision division operation.
+ */
+
+extern mpw mpx_udivn(mpw */*qv*/, mpw */*qvl*/,
+                    const mpw */*rv*/, const mpw */*rvl*/, mpw /*d*/);
+
+/*----- Karatsuba multiplication algorithms -------------------------------*/
+
+/* --- @MPK_THRESH@ --- *
+ *
+ * This is the limiting length for using Karatsuba algorithms.  It's best to
+ * use the simpler classical multiplication method on numbers smaller than
+ * this.  It is unsafe to make this constant less than four (i.e., the
+ * algorithms will fail).
+ */
+
+#define MPK_THRESH 16
+
+/* --- @mpx_kmul@ --- *
+ *
+ * Arguments:  @mpw *dv, *dvl@ = pointer to destination buffer
+ *             @const mpw *av, *avl@ = pointer to first argument
+ *             @const mpw *bv, *bvl@ = pointer to second argument
+ *             @mpw *sv, *svl@ = pointer to scratch workspace
+ *
+ * Returns:    ---
+ *
+ * Use:                Multiplies two multiprecision integers using Karatsuba's
+ *             algorithm.  This is rather faster than traditional long
+ *             multiplication (e.g., @mpx_umul@) on large numbers, although
+ *             more expensive on small ones.
+ *
+ *             The destination must be three times as large as the larger
+ *             argument.  The scratch space must be five times as large as
+ *             the larger argument.
+ */
+
+extern void mpx_kmul(mpw */*dv*/, mpw */*dvl*/,
+                    const mpw */*av*/, const mpw */*avl*/,
+                    const mpw */*bv*/, const mpw */*bvl*/,
+                    mpw */*sv*/, mpw */*svl*/);
+
+/* --- @mpx_ksqr@ --- *
+ *
+ * Arguments:  @mpw *dv, *dvl@ = pointer to destination buffer
+ *             @const mpw *av, *avl@ = pointer to first argument
+ *             @mpw *sv, *svl@ = pointer to scratch workspace
+ *
+ * Returns:    ---
+ *
+ * Use:                Squares a multiprecision integers using something similar to
+ *             Karatsuba's multiplication algorithm.  This is rather faster
+ *             than traditional long multiplication (e.g., @mpx_umul@) on
+ *             large numbers, although more expensive on small ones, and
+ *             rather simpler than full-blown Karatsuba multiplication.
+ *
+ *             The destination must be three times as large as the larger
+ *             argument.  The scratch space must be five times as large as
+ *             the larger argument.
+ */
+
+extern void mpx_ksqr(mpw */*dv*/, mpw */*dvl*/,
+                    const mpw */*av*/, const mpw */*avl*/,
+                    mpw */*sv*/, mpw */*svl*/);
+
 /*----- That's all, folks -------------------------------------------------*/
 
 #ifdef __cplusplus