catcrypt.c, catsign.c: Shorten chunk sizes.
[u/mdw/catacomb] / mp.h
diff --git a/mp.h b/mp.h
index fcccee2..13f97d1 100644 (file)
--- a/mp.h
+++ b/mp.h
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: mp.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ * $Id$
  *
- * Multiprecision arithmetic
+ * Simple multiprecision arithmetic
  *
  * (c) 1999 Straylight/Edgeware
  */
 
-/*----- Licensing notice --------------------------------------------------* 
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of Catacomb.
  *
  * 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.
  */
 
-/*----- Revision history --------------------------------------------------* 
- *
- * $Log: mp.h,v $
- * Revision 1.1  1999/09/03 08:41:12  mdw
- * Initial import.
- *
- */
-
-#ifndef MP_H
-#define MP_H
+#ifndef CATACOMB_MP_H
+#define CATACOMB_MP_H
 
 #ifdef __cplusplus
   extern "C" {
 
 /*----- Header files ------------------------------------------------------*/
 
-#include <stdlib.h>
+#include <assert.h>
 #include <string.h>
 
-#ifndef MPTYPES_H
-#  include "mptypes.h"
+#include <mLib/sub.h>
+
+#ifndef CATACOMB_MPW_H
+#  include "mpw.h"
 #endif
 
-#ifndef MPX_H
-#  include "mpx.h"
+#ifndef CATACOMB_ARENA_H
+#  include "arena.h"
 #endif
 
-#ifndef MPSCAN_H
-#  include "mpscan.h"
+#ifndef CATACOMB_MPARENA_H
+#  include "mparena.h"
+#endif
+
+#ifndef CATACOMB_MPX_H
+#  include "mpx.h"
 #endif
 
 /*----- Data structures ---------------------------------------------------*/
 
+/* --- A multiprecision integer --- */
+
 typedef struct mp {
-  mpw *v;                              /* Vector of words */
-  unsigned f;                          /* Various flags */
-  size_t sz;                           /* Size allocated to word vector */
-  size_t len;                          /* Length of current word vector */
+  mpw *v, *vl;                         /* Vector of digits, current limit */
+  size_t sz;                           /* Size of digit buffer in words */
+  mparena *a;                          /* Arena for buffer allocation */
+  unsigned f;                          /* Flags (see below) */
+  unsigned ref;                                /* Reference counter */
 } mp;
 
-enum {
-  MPF_SIGN = 1,                                /* Sign bit */
-  MPF_BURN = 2                         /* Burn word vector after use */
-};
+#define MP_NEG 1u                      /* Negative (signed magnitude) */
+#define MP_BURN 2u                     /* Secret (viral flag) */
+#define MP_CONST 4u                    /* Uses strange memory allocation */
+#define MP_UNDEF 8u                    /* Contains nothing interesting */
+#define MP_DESTROYED 16u               /* Has been destroyed */
+
+/* --- A factor for simultaneous exponentation --- *
+ *
+ * Used by the Montgomery and Barrett exponentiators.
+ */
+
+typedef struct mp_expfactor {
+  mp *base;
+  mp *exp;
+} mp_expfactor;
+
+/*----- Useful constants --------------------------------------------------*/
+
+extern mp mp_const[];
 
-typedef struct mp_bitscan {
-  const mp *x;                         /* Pointer to target MP */
-  size_t i;                            /* Index into MP vector */
-  mpw w;                               /* Current value being examined */
-  unsigned bits;                       /* Number of bits left in @w@ */
-} mp_bitscan;
+#define MP_ZERO         (&mp_const[0])
+#define MP_ONE  (&mp_const[1])
+#define MP_TWO  (&mp_const[2])
+#define MP_THREE (&mp_const[3])
+#define MP_FOUR         (&mp_const[4])
+#define MP_FIVE         (&mp_const[5])
+#define MP_TEN  (&mp_const[6])
+#define MP_256  (&mp_const[7])
+#define MP_MONE         (&mp_const[8])
 
-/*----- External variables ------------------------------------------------*/
+#define MP_NEW ((mp *)0)
+#define MP_NEWSEC (&mp_const[9])
 
-extern mp mp_std;
+/*----- Trivial macros ----------------------------------------------------*/
+
+/* --- @MP_LEN@ --- *
+ *
+ * Arguments:  @mp *m@ = pointer to a multiprecision integer
+ *
+ * Returns:    Length of the integer, in words.
+ */
 
-#define MP_ZERO (mp_std + 0)
-#define MP_ONE (mp_std + 1)
-#define MP_TWO (mp_std + 2)
-#define MP_THREE (mp_std + 3)
-#define MP_FOUR (mp_std + 4)
-#define MP_FIVE (mp_std + 5)
-#define MP_TEN (mp_std + 6)
-#define MP_MONE (mp_std + 7)
+#define MP_LEN(m) ((m)->vl - ((m)->v))
 
-/*----- Memory allocation and low-level fiddling --------------------------*/
+/*----- Memory management and reference counting --------------------------*/
+
+/* --- @mp_new@ --- *
+ *
+ * Arguments:  @size_t sz@ = size of vector required
+ *             @unsigned f@ = flags to set
+ *
+ * Returns:    Pointer to a new MP structure.
+ *
+ * Use:                Allocates a new multiprecision integer.  The data space is
+ *             allocated from either the standard global or secret arena,
+ *             depending on the initial flags requested.
+ */
+
+extern mp *mp_new(size_t /*sz*/, unsigned /*f*/);
 
 /* --- @mp_create@ --- *
  *
- * Arguments   @mp *x@ = pointer to MP head
+ * Arguments:  @size_t sz@ = size of vector required
+ *
+ * Returns:    Pointer to pristine new MP structure with enough memory
+ *             bolted onto it.
+ *
+ * Use:                Creates a new multiprecision integer with indeterminate
+ *             contents.  The integer has a single reference.
+ */
+
+extern mp *mp_create(size_t /*sz*/);
+
+/* --- @mp_createsecure@ --- *
+ *
+ * Arguments:  @size_t sz@ = size of vector required
+ *
+ * Returns:    Pointer to pristine new MP structure with enough memory
+ *             bolted onto it.
+ *
+ * Use:                Creates a new multiprecision integer with indeterminate
+ *             contents.  The integer has a single reference.  The integer's
+ *             data space is allocated from the secure arena.  Its burn flag
+ *             is set.
+ */
+
+extern mp *mp_createsecure(size_t /*sz*/);
+
+/* --- @mp_build@ --- *
+ *
+ * Arguments:  @mp *m@ = pointer to an MP block to fill in
+ *             @mpw *v@ = pointer to a word array
+ *             @mpw *vl@ = pointer just past end of array
  *
  * Returns:    ---
  *
- * Use:                Initializes an MP ready for use.  The initial value is zero.
+ * Use:                Creates a multiprecision integer representing some smallish
+ *             number.  You must provide storage for the number and dispose
+ *             of it when you've finished with it.  The number is marked as
+ *             constant while it exists.
  */
 
-#define MP_INIT { 0, 0, 0, 0 }
+extern void mp_build(mp */*m*/, mpw */*v*/, mpw */*vl*/);
+
+/* --- @mp_destroy@ --- *
+ *
+ * Arguments:  @mp *m@ = pointer to a multiprecision integer
+ *
+ * Returns:    ---
+ *
+ * Use:                Destroys a multiprecision integer. The reference count isn't
+ *             checked.  Don't use this function if you don't know what
+ *             you're doing: use @mp_drop@ instead.
+ */
 
-extern void mp_create(mp */*x*/);
+extern void mp_destroy(mp */*m*/);
 
-/* --- @MP_BURN@ --- *
+/* --- @mp_copy@ --- *
+ *
+ * Arguments:  @mp *m@ = pointer to a multiprecision integer
  *
- * Arguments:  @x@ = pointer to MP head
+ * Returns:    A copy of the given multiprecision integer.
  *
- * Use:                Burns the contents of the MP, if it contains sensitive data.
+ * Use:                Copies the given integer.  In fact you just get another
+ *             reference to the same old one again.
  */
 
-#define MP_BURN(x) do {                                                        \
-  mp *_y = (x)                                                         \
-  if (_y->v && _y->f & mpf_burn) {                                     \
-    memset(_y->v, 0, _y->sz * sizeof(mpw));                            \
-    _y->f &= ~MPF_BURN;                                                        \
-  }                                                                    \
-} while (0)
+extern mp *mp_copy(mp */*m*/);
 
-/* --- @mp_free@ --- *
+#define MP_COPY(m) ((m)->ref++, (m))
+
+/* --- @mp_drop@ --- *
  *
- * Arguments:  @mp *x@ = pointer to MP head
+ * Arguments:  @mp *m@ = pointer to a multiprecision integer
  *
  * Returns:    ---
  *
- * Use:                Releases the memory used by an MP.
+ * Use:                Drops a reference to an integer which isn't wanted any more.
+ *             If there are no more references, the integer is destroyed.
  */
 
-#define MP_DESTROY(x) do {                                             \
-  mp *_x = (x);                                                                \
-  MP_BURN(_x);                                                         \
-  if (_x->v)                                                           \
-    free(_x->v);                                                       \
-  _x->v = 0;                                                           \
-  _x->f = 0;                                                           \
-  _x->sz = 0;                                                          \
-  _x->len = 0;                                                         \
-} while (0)  
-                  
-extern void mp_free(mp */*x*/);
+extern void mp_drop(mp */*m*/);
 
-/* --- @MP_ENSURE@ --- *
+#define MP_DROP(m) do {                                                        \
+  mp *_mm = (m);                                                       \
+  _mm->ref--;                                                          \
+  if (_mm->ref == 0 && !(_mm->f & MP_CONST))                           \
+    mp_destroy(_mm);                                                   \
+} while (0)
+
+/* --- @mp_split@ --- *
+ *
+ * Arguments:  @mp *m@ = pointer to a multiprecision integer
  *
- * Arguments:  @x@ = pointer to MP head
- *             @len@ = length required (in words)
+ * Returns:    A reference to the same integer, possibly with a different
+ *             address.
  *
- * Use:                Ensures that the MP has enough memory to store a @len@-word
- *             value.
+ * Use:                Splits off a modifiable version of the integer referred to.
  */
 
-#define MP_ENSURE(x, len) do {                                         \
-  mp *_x = (x);                                                                \
-  size_t _len = (len);                                                 \
-  if (_x->sz < _len)                                                   \
-    mp_resize(_x, _len);                                               \
+extern mp *mp_split(mp */*m*/);
+
+#define MP_SPLIT(m) do {                                               \
+  mp *_m = (m);                                                                \
+  if ((_m->f & MP_CONST) || _m->ref > 1) {                             \
+    size_t _len = MP_LEN(_m);                                          \
+    mp *_mm = mp_new(_len, _m->f);                                     \
+    if (!(_m->f & MP_UNDEF))                                           \
+      memcpy(_mm->v, _m->v, MPWS(_len));                               \
+    _m->ref--;                                                         \
+    _m = _mm;                                                          \
+  }                                                                    \
+  (m) = _m;                                                            \
 } while (0)
 
 /* --- @mp_resize@ --- *
  *
- * Arguments:  @mp *x@ = pointer to MP head
- *             @size_t sz@ = size required (in words)
+ * Arguments:  @mp *m@ = pointer to a multiprecision integer
+ *             @size_t sz@ = new size
  *
  * Returns:    ---
  *
- * Use:                Resizes the MP so that its word vector has space for
- *             exactly @sz@ words.
+ * Use:                Resizes the vector containing the integer's digits.  The new
+ *             size must be at least as large as the current integer's
+ *             length.  This isn't really intended for client use.
  */
 
-extern void mp_resize(mp */*x*/, size_t /*sz*/);
+extern void mp_resize(mp */*m*/, size_t /*sz*/);
+
+#define MP_RESIZE(m, ssz) do {                                         \
+  mp *_m = (m);                                                                \
+  size_t _sz = (ssz);                                                  \
+  mparena *_a = (_m->f & MP_BURN) ? MPARENA_SECURE : MPARENA_GLOBAL;   \
+  mpw *_v;                                                             \
+  size_t _len = MP_LEN(_m);                                            \
+  assert(((void)"can't make size less than length", _sz >= _len));     \
+  _v = mpalloc(_a, _sz);                                               \
+  if (!(_m->f & MP_UNDEF))                                             \
+    memcpy(_v, _m->v, MPWS(_len));                                     \
+  if (_m->f & MP_BURN)                                                 \
+    memset(_m->v, 0, MPWS(_m->sz));                                    \
+  mpfree(_m->a, _m->v);                                                        \
+  _m->a = _a;                                                          \
+  _m->v = _v;                                                          \
+  _m->vl = _v + _len;                                                  \
+} while (0)
 
-/* --- @mp_norm@ --- *
+/* --- @mp_ensure@ --- *
  *
- * Arguments:  @mp *x@ = pointer to MP head
+ * Arguments:  @mp *m@ = pointer to a multiprecision integer
+ *             @size_t sz@ = required size
  *
  * Returns:    ---
  *
- * Use:                `Normalizes' an MP.  Fixes the @len@ field so that it's
- *             correct.  Assumes that @len@ is either already correct or
- *             too large.
+ * Use:                Ensures that the integer has enough space for @sz@ digits.
+ *             The value is not changed.
+ */
+
+extern void mp_ensure(mp */*m*/, size_t /*sz*/);
+
+#define MP_ENSURE(m, ssz) do {                                         \
+  mp *_m = (m);                                                                \
+  size_t _ssz = (ssz);                                                 \
+  size_t _len = MP_LEN(_m);                                            \
+  if (_ssz >= _len) {                                                  \
+    if (_ssz > _m->sz)                                                 \
+      mp_resize(_m, _ssz);                                             \
+    if (!(_m->f & MP_UNDEF) && _ssz > _len)                            \
+      memset(_m->vl, 0, MPWS(_ssz - _len));                            \
+    _m->vl = _m->v + _ssz;                                             \
+  }                                                                    \
+} while (0)
+
+/* --- @mp_dest@ --- *
+ *
+ * Arguments:  @mp *m@ = a suggested destination integer
+ *             @size_t sz@ = size required for result, in digits
+ *             @unsigned f@ = various flags
+ *
+ * Returns:    A pointer to an appropriate destination.
+ *
+ * Use:                Converts a suggested destination into a real destination with
+ *             the required properties.  If the real destination is @d@,
+ *             then the following properties will hold:
+ *
+ *               * @d@ will have exactly one reference.
+ *
+ *               * If @m@ is not @MP_NEW@, then the contents of @m@ will not
+ *                 change, unless @f@ has the @MP_UNDEF@ flag set.
+ *
+ *               * If @m@ is not @MP_NEW@, then he reference count of @m@ on
+ *                 entry is equal to the sum of the counts of @d@ and @m@ on
+ *                 exit.
+ *
+ *               * The size of @d@ will be at least @sz@.
+ *
+ *               * If @f@ has the @MP_BURN@ flag set, then @d@ will be
+ *                 allocated from @MPARENA_SECURE@.
+ *
+ *             Understanding this function is crucial to using Catacomb's
+ *             multiprecision integer library effectively.
  */
 
-#define MP_NORM(x) do {                                                        \
-  mp *_y = (x);                                                                \
-  MPX_LEN(_y->len, _y->v, _y->len);                                    \
+extern mp *mp_dest(mp */*m*/, size_t /*sz*/, unsigned /*f*/);
+
+#define MP_DEST(m, ssz, f) do {                                                \
+  mp *_m = (m);                                                                \
+  size_t _ssz = (ssz);                                                 \
+  unsigned _f = (f);                                                   \
+  _m = mp_dest(_m, _ssz, _f);                                          \
+  (m) = _m;                                                            \
 } while (0)
 
-extern void mp_norm(mp */*x*/);
+/*----- Size manipulation -------------------------------------------------*/
 
-/* --- @mp_dump@ --- *
+/* --- @mp_shrink@ --- *
  *
- * Arguments:  @mp *x@ = pointer to MP head
- *             @FILE *fp@ = pointer to stream to write on
+ * Arguments:  @mp *m@ = pointer to a multiprecision integer
  *
  * Returns:    ---
  *
- * Use:                Dumps an MP to a stream.
+ * Use:                Reduces the recorded length of an integer.  This doesn't
+ *             reduce the amount of memory used, although it can improve
+ *             performance a bit.  To reduce memory, use @mp_minimize@
+ *             instead.  This can't change the value of an integer, and is
+ *             therefore safe to use even when there are multiple
+ *             references.
  */
 
-extern void mp_dump(mp */*x*/, FILE */*fp*/);
+extern void mp_shrink(mp */*m*/);
 
-/* --- @MP_PARANOID@ --- *
+#define MP_SHRINK(m) do {                                              \
+  mp *_mm = (m);                                                       \
+  MPX_SHRINK(_mm->v, _mm->vl);                                         \
+  if (MP_ZEROP(_mm))                                                   \
+    _mm->f &= ~MP_NEG;                                                 \
+} while (0)
+
+/* --- @mp_minimize@ --- *
+ *
+ * Arguments:  @mp *m@ = pointer to a multiprecision integer
  *
- * Arguments:  @x@ = pointer to MP head
+ * Returns:    ---
  *
- * Use:                Marks the MP as containing sensitive data which should be
- *             burnt when no longer required.
+ * Use:                Reduces the amount of memory an integer uses.  It's best to
+ *             do this to numbers which aren't going to change in the
+ *             future.
  */
 
-#define MP_PARANOID(x) ((x)->f |= MPF_BURN)
+extern void mp_minimize(mp */*m*/);
 
-/* --- @mp_copy@ --- *
+/*----- Bit scanning ------------------------------------------------------*/
+
+#ifndef CATACOMB_MPSCAN_H
+#  include "mpscan.h"
+#endif
+
+/* --- @mp_scan@ --- *
  *
- * Arguments:  @mp *d@ = pointer to MP head for destination
- *             @const mp *s@ = pointer to MP head for source
+ * Arguments:  @mpscan *sc@ = pointer to bitscanner block
+ *             @const mp *m@ = pointer to a multiprecision integer
  *
  * Returns:    ---
  *
- * Use:                Copies an MP.
+ * Use:                Initializes a bitscanner on a multiprecision integer.
  */
 
-extern void mp_copy(mp */*d*/, const mp */*s*/);
+extern void mp_scan(mpscan */*sc*/, const mp */*m*/);
 
-/* --- @mp_bits@ --- *
+#define MP_SCAN(sc, m) do {                                            \
+  const mp *_mm = (m);                                                 \
+  mpscan *_sc = (sc);                                                  \
+  MPSCAN_INITX(_sc, _mm->v, _mm->vl);                                  \
+} while (0)
+
+/* --- @mp_rscan@ --- *
  *
- * Arguments:  @mp *x@ = pointer to MP head
+ * Arguments:  @mpscan *sc@ = pointer to bitscanner block
+ *             @const mp *m@ = pointer to a multiprecision integer
  *
- * Returns:    Length of the number in bits.
+ * Returns:    ---
  *
- * Use:                Calculates the number of bits required to represent a number.
- *             The number must be normalized.
+ * Use:                Initializes a reverse bitscanner on a multiprecision
+ *             integer.
  */
 
-unsigned long mp_bits(mp */*x*/);
+extern void mp_rscan(mpscan */*sc*/, const mp */*m*/);
+
+#define MP_RSCAN(sc, m) do {                                           \
+  const mp *_mm = (m);                                                 \
+  mpscan *_sc = (sc);                                                  \
+  MPSCAN_RINITX(_sc, _mm->v, _mm->vl);                                 \
+} while (0)
+
+/* --- Other bitscanning aliases --- */
+
+#define mp_step mpscan_step
+#define mp_bit mpscan_bit
+#define mp_rstep mpscan_rstep
+#define mp_rbit mpscan_rbit
+
+#define MP_STEP MPSCAN_STEP
+#define MP_BIT MPSCAN_BIT
+#define MP_RSTEP MPSCAN_RSTEP
+#define MP_RBIT MPSCAN_RBIT
+
+/*----- Loading and storing -----------------------------------------------*/
 
 /* --- @mp_octets@ --- *
  *
- * Arguments:  @mp *x@ = pointer to MP head
+ * Arguments:  @const mp *m@ = a multiprecision integer
  *
- * Returns:    Length of number in octets.
+ * Returns:    The number of octets required to represent @m@.
  *
- * Use:                Calculates the number of octets required to represent a
- *             number.  The number must be normalized.
+ * Use:                Calculates the external storage required for a multiprecision
+ *             integer.
  */
 
-extern size_t mp_octets(mp */*x*/);
+extern size_t mp_octets(const mp */*m*/);
+
+/* --- @mp_octets2c@ --- *
+ *
+ * Arguments:  @const mp *m@ = a multiprecision integer
+ *
+ * Returns:    The number of octets required to represent @m@.
+ *
+ * Use:                Calculates the external storage required for a multiprecision
+ *             integer represented as two's complement.
+ */
 
-/*----- Loading and storing as binary data --------------------------------*/
+extern size_t mp_octets2c(const mp */*m*/);
 
-/* --- @mp_storel@ --- *
+/* --- @mp_bits@ --- *
  *
- * Arguments:  @mp *x@ = pointer to MP head
- *             @octet *p@ = pointer to octet array
- *             @size_t sz@ = size of octet array
+ * Arguments:  @const mp *m@ = a multiprecision integer
  *
- * Returns:    ---
+ * Returns:    The number of bits required to represent @m@.
  *
- * Use:                Stores an MP in an octet array, least significant octet
- *             first.  High-end octets are silently discarded if there
- *             isn't enough space for them.
+ * Use:                Calculates the external storage required for a multiprecision
+ *             integer.
  */
 
-extern void mp_storel(mp */*x*/, octet */*p*/, size_t /*sz*/);
+extern unsigned long mp_bits(const mp */*m*/);
 
 /* --- @mp_loadl@ --- *
  *
- * Arguments:  @mp *x@ = pointer to MP head
- *             @const octet *p@ = pointer to octet array
- *             @size_t sz@ = size of octet array
+ * Arguments:  @mp *d@ = destination
+ *             @const void *pv@ = pointer to source data
+ *             @size_t sz@ = size of the source data
+ *
+ * Returns:    Resulting multiprecision number.
+ *
+ * Use:                Loads a multiprecision number from an array of octets.  The
+ *             first byte in the array is the least significant.  More
+ *             formally, if the bytes are %$b_0, b_1, \ldots, b_{n-1}$%
+ *             then the result is %$N = \sum_{0 \le i < n} b_i 2^{8i}$%.
+ */
+
+extern mp *mp_loadl(mp */*d*/, const void */*pv*/, size_t /*sz*/);
+
+/* --- @mp_storel@ --- *
+ *
+ * Arguments:  @const mp *m@ = source
+ *             @void *pv@ = pointer to output array
+ *             @size_t sz@ = size of the output array
  *
  * Returns:    ---
  *
- * Use:                Loads an MP in an octet array, least significant octet
- *             first.
+ * Use:                Stores a multiprecision number in an array of octets.  The
+ *             first byte in the array is the least significant.  If the
+ *             array is too small to represent the number, high-order bits
+ *             are truncated; if the array is too large, high order bytes
+ *             are filled with zeros.  More formally, if the number is
+ *             %$N = \sum{0 \le i} b_i 2^{8i}$% where %$0 \le b_i < 256$%,
+ *             then the array is %$b_0, b_1, \ldots, b_{n-1}$%.
+ */
+
+extern void mp_storel(const mp */*m*/, void */*pv*/, size_t /*sz*/);
+
+/* --- @mp_loadb@ --- *
+ *
+ * Arguments:  @mp *d@ = destination
+ *             @const void *pv@ = pointer to source data
+ *             @size_t sz@ = size of the source data
+ *
+ * Returns:    Resulting multiprecision number.
+ *
+ * Use:                Loads a multiprecision number from an array of octets.  The
+ *             last byte in the array is the least significant.  More
+ *             formally, if the bytes are %$b_{n-1}, b_{n-2}, \ldots, b_0$%
+ *             then the result is %$N = \sum_{0 \le i < n} b_i 2^{8i}$%.
  */
 
-extern void mp_loadl(mp */*x*/, const octet */*p*/, size_t /*sz*/);
+extern mp *mp_loadb(mp */*d*/, const void */*pv*/, size_t /*sz*/);
 
 /* --- @mp_storeb@ --- *
  *
- * Arguments:  @mp *x@ = pointer to MP head
- *             @octet *p@ = pointer to octet array
- *             @size_t sz@ = size of octet array
+ * Arguments:  @const mp *m@ = source
+ *             @void *pv@ = pointer to output array
+ *             @size_t sz@ = size of the output array
  *
  * Returns:    ---
  *
- * Use:                Stores an MP in an octet array, most significant octet
- *             first.  High-end octets are silently discarded if there
- *             isn't enough space for them.
+ * Use:                Stores a multiprecision number in an array of octets.  The
+ *             last byte in the array is the least significant.  If the
+ *             array is too small to represent the number, high-order bits
+ *             are truncated; if the array is too large, high order bytes
+ *             are filled with zeros.  More formally, if the number is
+ *             %$N = \sum{0 \le i} b_i 2^{8i}$% where %$0 \le b_i < 256$%,
+ *             then the array is %$b_{n-1}, b_{n-2}, \ldots, b_0$%.
  */
 
-extern void mp_storeb(mp */*x*/, octet */*p*/, size_t /*sz*/);
+extern void mp_storeb(const mp */*m*/, void */*pv*/, size_t /*sz*/);
 
-/* --- @mp_loadb@ --- *
+/* --- @mp_loadl2c@ --- *
+ *
+ * Arguments:  @mp *d@ = destination
+ *             @const void *pv@ = pointer to source data
+ *             @size_t sz@ = size of the source data
+ *
+ * Returns:    Resulting multiprecision number.
+ *
+ * Use:                Loads a multiprecision number from an array of octets as
+ *             two's complement.  The first byte in the array is the least
+ *             significant.
+ */
+
+extern mp *mp_loadl2c(mp */*d*/, const void */*pv*/, size_t /*sz*/);
+
+/* --- @mp_storel2c@ --- *
  *
- * Arguments:  @mp *x@ = pointer to MP head
- *             @const octet *p@ = pointer to octet array
- *             @size_t sz@ = size of octet array
+ * Arguments:  @const mp *m@ = source
+ *             @void *pv@ = pointer to output array
+ *             @size_t sz@ = size of the output array
  *
  * Returns:    ---
  *
- * Use:                Loads an MP in an octet array, most significant octet
- *             first.
+ * Use:                Stores a multiprecision number in an array of octets as two's
+ *             complement.  The first byte in the array is the least
+ *             significant.  If the array is too small to represent the
+ *             number, high-order bits are truncated; if the array is too
+ *             large, high order bytes are sign-extended.
  */
 
-extern void mp_loadb(mp */*x*/, const octet */*p*/, size_t /*sz*/);
+extern void mp_storel2c(const mp */*m*/, void */*pv*/, size_t /*sz*/);
 
-/*----- Iterating through bits --------------------------------------------*/
+/* --- @mp_loadb2c@ --- *
+ *
+ * Arguments:  @mp *d@ = destination
+ *             @const void *pv@ = pointer to source data
+ *             @size_t sz@ = size of the source data
+ *
+ * Returns:    Resulting multiprecision number.
+ *
+ * Use:                Loads a multiprecision number from an array of octets as
+ *             two's complement.  The last byte in the array is the least
+ *             significant.
+ */
 
-/* --- @mp_mkbitscan@ --- *
+extern mp *mp_loadb2c(mp */*d*/, const void */*pv*/, size_t /*sz*/);
+
+/* --- @mp_storeb2c@ --- *
  *
- * Arguments:  @mp_bitscan *sc@ = pointer to bitscan object
- *             @const mp *x@ = pointer to MP head
+ * Arguments:  @const mp *m@ = source
+ *             @void *pv@ = pointer to output array
+ *             @size_t sz@ = size of the output array
  *
  * Returns:    ---
  *
- * Use:                Initializes a bitscan object.
+ * Use:                Stores a multiprecision number in an array of octets, as
+ *             two's complement.  The last byte in the array is the least
+ *             significant.  If the array is too small to represent the
+ *             number, high-order bits are truncated; if the array is too
+ *             large, high order bytes are sign-extended.
  */
 
-extern void mp_mkbitscan(mp_bitscan */*sc*/, const mp */*x*/);
+extern void mp_storeb2c(const mp */*m*/, void */*pv*/, size_t /*sz*/);
+
+/*----- Bit operations ----------------------------------------------------*/
 
-/* --- @mp_bstep@ --- *
+/* --- @mp_not@ --- *
  *
- * Arguments:  @mp_bitscan *sc@ = pointer to bitscanner object
+ * Arguments:  @mp *d@ = destination
+ *             @mp *a@ = source
  *
- * Returns:    Nonzero if there is another bit to read.
+ * Returns:    The bitwise complement of the source.
+ */
+
+extern mp *mp_not(mp */*d*/, mp */*a*/);
+
+/* --- @mp_bitop@ --- *
+ *
+ * Arguments:  @mp *d@ = destination
+ *             @mp *a, *b@ = sources
  *
- * Use:                Steps on to the next bit, and tells the caller whether one
- *             exists.
+ * Returns:    The result of the given bitwise operation.  These functions
+ *             don't handle negative numbers at all sensibly.  For that, use
+ *             the @...2c@ variants.  The functions are named after the
+ *             truth tables they generate:
+ *
+ *                     a:      0011
+ *                     b:      0101
+ *                     @mpx_bitXXXX@
  */
 
-extern int mp_bstep(mp_bitscan */*sc*/);
+#define MP_BITDECL(string)                                             \
+  extern mp *mp_bit##string(mp */*d*/, mp */*a*/, mp */*b*/);
+MPX_DOBIN(MP_BITDECL)
 
-/* --- @mp_bit@ --- *
+/* --- @mp_[n]and@, @mp_[n]or@, @mp_[n]xor@, @mp_not@ --- *
  *
- * Arguments:  @const mp_bitscan *sc@ = pointer to bitscanner
+ * Synonyms for the commonly-used functions.
+ */
+
+#define mp_and mp_bit0001
+#define mp_or  mp_bit0111
+#define mp_nand mp_bit1110
+#define mp_nor mp_bit1000
+#define mp_xor mp_bit0110
+
+/* --- @mp_testbit@ --- *
  *
- * Returns:    Current bit value.
+ * Arguments:  @mp *x@ = a large integer
+ *             @unsigned long n@ = which bit to test
  *
- * Use:                Returns the value of the current bit.
+ * Returns:    Nonzero if the bit is set, zero if not.
  */
 
-#define MP_BIT(sc) ((sc)->w & 1)
+extern int mp_testbit(mp */*x*/, unsigned long /*n*/);
 
-extern int mp_bit(const mp_bitscan */*sc*/);
+/* --- @mp_setbit@, @mp_clearbit@ --- *
+ *
+ * Arguments:  @mp *d@ = a destination
+ *             @mp *x@ = a large integer
+ *             @unsigned long n@ = which bit to modify
+ *
+ * Returns:    The argument @x@, with the appropriate bit set or cleared.
+ */
 
-/*----- Shifting ----------------------------------------------------------*/
+extern mp *mp_setbit(mp */*d*/, mp */*x*/, unsigned long /*n*/);
+extern mp *mp_clearbit(mp */*d*/, mp */*x*/, unsigned long /*n*/);
 
-/* --- @mp_lsl@ --- *
+/* --- @mp_lsl@, @mp_lslc@, @mp_lsr@ --- *
  *
- * Arguments:  @mp *d@ = pointer to MP head of destination
- *             @const mp *x@ = pointer to MP head of source
- *             @size_t n@ = number of bits to shift
+ * Arguments:  @mp *d@ = destination
+ *             @mp *a@ = source
+ *             @size_t n@ = number of bits to move
  *
- * Returns:    ---
+ * Returns:    Result, @a@ shifted left or right by @n@.
  *
- * Use:                Shifts a number left by a given number of bit positions.
+ * Use:                Bitwise shift operators.  @mp_lslc@ fills the bits introduced
+ *             on the right with ones instead of zeroes: it's used
+ *             internally by @mp_lsl2c@, though it may be useful on its
+ *             own.
  */
 
-extern void mp_lsl(mp */*d*/, const mp */*x*/, size_t /*n*/);
+extern mp *mp_lsl(mp */*d*/, mp */*a*/, size_t /*n*/);
+extern mp *mp_lslc(mp */*d*/, mp */*a*/, size_t /*n*/);
+extern mp *mp_lsr(mp */*d*/, mp */*a*/, size_t /*n*/);
 
-/* --- @mp_lsr@ --- *
+/* --- @mp_not2c@ --- *
  *
- * Arguments:  @mp *d@ = pointer to MP head of destination
- *             @const mp *x@ = pointer to MP head of source
- *             @size_t n@ = number of bits to shift
+ * Arguments:  @mp *d@ = destination
+ *             @mp *a@ = source
  *
- * Returns:    ---
+ * Returns:    The sign-extended complement of the argument.
+ */
+
+extern mp *mp_not2c(mp */*d*/, mp */*a*/);
+
+/* --- @mp_bitop2c@ --- *
+ *
+ * Arguments:  @mp *d@ = destination
+ *             @mp *a, *b@ = sources
  *
- * Use:                Shifts a number right by a given number of bit positions.
+ * Returns:    The result of the given bitwise operation.  Negative numbers
+ *             are treated as two's complement, sign-extended infinitely to
+ *             the left.  The functions are named after the truth tables
+ *             they generate:
+ *
+ *                     a:      0011
+ *                     b:      0101
+ *                     @mpx_bitXXXX@
  */
 
-extern void mp_lsr(mp */*d*/, const mp */*x*/, size_t /*n*/);
+#define MP_BIT2CDECL(string)                                           \
+  extern mp *mp_bit##string##2c(mp */*d*/, mp */*a*/, mp */*b*/);
+MPX_DOBIN(MP_BIT2CDECL)
+
+/* --- @mp_[n]and@, @mp_[n]or@, @mp_[n]xor@, @mp_not@ --- *
+ *
+ * Synonyms for the commonly-used functions.
+ */
 
-/*----- Unsigned arithmetic -----------------------------------------------*/
+#define mp_and2c  mp_bit00012c
+#define mp_or2c          mp_bit01112c
+#define mp_nand2c mp_bit11102c
+#define mp_nor2c  mp_bit10002c
+#define mp_xor2c  mp_bit01102c
 
-/* --- @mp_uadd@ --- *
+/* --- @mp_lsl2c@, @mp_lsr2c@ --- *
  *
- * Arguments:  @const mp *d@ = pointers to MP head of destination
- *             @const mp *x, *y@ = pointers to MP heads of operands
+ * Arguments:  @mp *d@ = destination
+ *             @mp *a@ = source
+ *             @size_t n@ = number of bits to move
  *
- * Returns:    ---
+ * Returns:    Result, @a@ shifted left or right by @n@.  Handles the
+ *             pretence of sign-extension for negative numbers.
+ */
+
+extern mp *mp_lsl2c(mp */*d*/, mp */*a*/, size_t /*n*/);
+extern mp *mp_lsr2c(mp */*d*/, mp */*a*/, size_t /*n*/);
+
+/* --- @mp_testbit2c@ --- *
+ *
+ * Arguments:  @mp *x@ = a large integer
+ *             @unsigned long n@ = which bit to test
  *
- * Use:                Performs unsigned MP addition.
+ * Returns:    Nonzero if the bit is set, zero if not.  Fakes up two's
+ *             complement representation.
  */
 
-extern void mp_uadd(mp */*d*/, const mp */*x*/, const mp */*y*/);
+extern int mp_testbit2c(mp */*x*/, unsigned long /*n*/);
 
-/* --- @mp_usub@ --- *
+/* --- @mp_setbit2c@, @mp_clearbit2c@ --- *
  *
- * Arguments:  @const mp *d@ = pointers to MP head of destination
- *             @const mp *x, *y@ = pointers to MP heads of operands
+ * Arguments:  @mp *d@ = a destination
+ *             @mp *x@ = a large integer
+ *             @unsigned long n@ = which bit to modify
  *
- * Returns:    ---
+ * Returns:    The argument @x@, with the appropriate bit set or cleared.
+ *             Fakes up two's complement representation.
+ */
+
+extern mp *mp_setbit2c(mp */*d*/, mp */*x*/, unsigned long /*n*/);
+extern mp *mp_clearbit2c(mp */*d*/, mp */*x*/, unsigned long /*n*/);
+
+/*----- Comparisons -------------------------------------------------------*/
+
+/* --- @mp_eq@ --- *
+ *
+ * Arguments:  @const mp *a, *b@ = two numbers
  *
- * Use:                Performs unsigned MP subtraction.
+ * Returns:    Nonzero if the numbers are equal.
  */
 
-extern void mp_usub(mp */*d*/, const mp */*x*/, const mp */*y*/);
+extern int mp_eq(const mp */*a*/, const mp */*b*/);
+
+#define MP_EQ(a, b)                                                    \
+  ((((a)->f ^ (b)->f) & MP_NEG) == 0 &&                                        \
+   mpx_ueq((a)->v, (a)->vl, (b)->v, (b)->vl))
+
+/* --- @mp_cmp@ --- *
+ *
+ * Arguments:  @const mp *a, *b@ = two numbers
+ *
+ * Returns:    Less than, equal to or greater than zero, according to
+ *             whether @a@ is less than, equal to or greater than @b@.
+ */
+
+extern int mp_cmp(const mp */*a*/, const mp */*b*/);
+
+#define MP_CMP(a, op, b) (mp_cmp((a), (b)) op 0)
 
-/* --- @mp_ucmp@ --- *
+/* --- Other handy macros --- */
+
+#define MP_NEGP(x) ((x)->f & MP_NEG)
+#define MP_ZEROP(x) (!MP_LEN(x))
+#define MP_POSP(x) (!MP_NEGP(x) && !MP_ZEROP(x))
+#define MP_ODDP(x) (!MP_ZEROP(x) && ((x)->v[0] & 1u))
+#define MP_EVENP(x) (!MP_ODDP(x))
+
+/*----- Arithmetic operations ---------------------------------------------*/
+
+/* --- @mp_neg@ --- *
  *
- * Arguments:  @const mp *x, *y@ = pointers to MP heads of operands
+ * Arguments:  @mp *d@ = destination
+ *             @mp *a@ = argument
  *
- * Returns:    Less than, equal to, or greater than zero.
+ * Returns:    The negation of the argument.
  *
- * Use:                Performs unsigned MP comparison.
+ * Use:                Negates its argument.
  */
 
-#define MP_UCMP(x, op, y) (mp_ucmp((x), (y)) op 0)
+extern mp *mp_neg(mp */*d*/, mp */*a*/);
+
+/* --- @mp_add@ --- *
+ *
+ * Arguments:  @mp *d@ = destination
+ *             @mp *a, *b@ = sources
+ *
+ * Returns:    Result, @a@ added to @b@.
+ */
 
-extern int mp_ucmp(const mp */*x*/, const mp */*y*/);
+extern mp *mp_add(mp */*d*/, mp */*a*/, mp */*b*/);
 
-/* --- @mp_umul@ --- *
+/* --- @mp_sub@ --- *
  *
- * Arguments:  @mp *d@ = pointer to MP head of destination
- *             @const mp *x, *y@ = pointes to MP heads of operands
+ * Arguments:  @mp *d@ = destination
+ *             @mp *a, *b@ = sources
  *
- * Returns:    ---
+ * Returns:    Result, @b@ subtracted from @a@.
+ */
+
+extern mp *mp_sub(mp */*d*/, mp */*a*/, mp */*b*/);
+
+/* --- @mp_mul@ --- *
+ *
+ * Arguments:  @mp *d@ = destination
+ *             @mp *a, *b@ = sources
+ *
+ * Returns:    Result, @a@ multiplied by @b@.
+ */
+
+extern mp *mp_mul(mp */*d*/, mp */*a*/, mp */*b*/);
+
+/* --- @mp_sqr@ --- *
+ *
+ * Arguments:  @mp *d@ = destination
+ *             @mp *a@ = source
+ *
+ * Returns:    Result, @a@ squared.
+ */
+
+extern mp *mp_sqr(mp */*d*/, mp */*a*/);
+
+/* --- @mp_div@ --- *
+ *
+ * Arguments:  @mp **qq, **rr@ = destination, quotient and remainder
+ *             @mp *a, *b@ = sources
+ *
+ * Use:                Calculates the quotient and remainder when @a@ is divided by
+ *             @b@.
+ */
+
+extern void mp_div(mp **/*qq*/, mp **/*rr*/, mp */*a*/, mp */*b*/);
+
+/* --- @mp_exp@ --- *
+ *
+ * Arguments:  @mp *d@ = fake destination
+ *             @mp *a@ = base
+ *             @mp *e@ = exponent
+ *
+ * Returns:    Result, %$a^e$%.
+ */
+
+extern mp *mp_exp(mp */*d*/, mp */*a*/, mp */*e*/);
+
+/* --- @mp_odd@ --- *
+ *
+ * Arguments:  @mp *d@ = pointer to destination integer
+ *             @mp *m@ = pointer to source integer
+ *             @size_t *s@ = where to store the power of 2
  *
- * Use:                Performs unsigned MP multiplication.
+ * Returns:    An odd integer integer %$t$% such that %$m = 2^s t$%.
+ *
+ * Use:                Computes a power of two and an odd integer which, when
+ *             multiplied, give a specified result.  This sort of thing is
+ *             useful in number theory quite often.
  */
 
-extern void mp_umul(mp */*d*/, const mp */*x*/, const mp */*y*/);
+extern mp *mp_odd(mp */*d*/, mp */*m*/, size_t */*s*/);
+
+/*----- More advanced algorithms ------------------------------------------*/
 
-/* --- @mp_udiv@ --- *
+/* --- @mp_sqrt@ --- *
  *
- * Arguments:  @mp *q, *r@ = pointers to MP heads for quotient, remainder
- *             @const mp *x, *y@ = pointers to MP heads for operands
+ * Arguments:  @mp *d@ = pointer to destination integer
+ *             @mp *a@ = (nonnegative) integer to take square root of
+ *
+ * Returns:    The largest integer %$x$% such that %$x^2 \le a$%.
+ *
+ * Use:                Computes integer square roots.
+ *
+ *             The current implementation isn't very good: it uses the
+ *             Newton-Raphson method to find an approximation to %$a$%.  If
+ *             there's any demand for a better version, I'll write one.
+ */
+
+extern mp *mp_sqrt(mp */*d*/, mp */*a*/);
+
+/* --- @mp_gcd@ --- *
+ *
+ * Arguments:  @mp **gcd, **xx, **yy@ = where to write the results
+ *             @mp *a, *b@ = sources (must be nonzero)
  *
  * Returns:    ---
  *
- * Use:                Performs unsigned MP division.
+ * Use:                Calculates @gcd(a, b)@, and two numbers @x@ and @y@ such that
+ *             @ax + by = gcd(a, b)@.  This is useful for computing modular
+ *             inverses.  Neither @a@ nor @b@ may be zero.
+ */
+
+extern void mp_gcd(mp **/*gcd*/, mp **/*xx*/, mp **/*yy*/,
+                  mp */*a*/, mp */*b*/);
+
+/* -- @mp_modinv@ --- *
+ *
+ * Arguments:  @mp *d@ = destination
+ *             @mp *x@ = argument
+ *             @mp *p@ = modulus
+ *
+ * Returns:    The inverse %$x^{-1} \bmod p$%.
+ *
+ * Use:                Computes a modular inverse.    An assertion fails if %$p$%
+ *             has no inverse.
+ */
+
+extern mp *mp_modinv(mp */*d*/, mp */*x*/, mp */*p*/);
+
+/* --- @mp_jacobi@ --- *
+ *
+ * Arguments:  @mp *a@ = an integer
+ *             @mp *n@ = another integer
+ *
+ * Returns:    @-1@, @0@ or @1@ -- the Jacobi symbol %$J(a, n)$%.
+ *
+ * Use:                Computes the Kronecker symbol %$\jacobi{a}{n}$%.  If @n@ is
+ *             prime, this is the Legendre symbol and is equal to 1 if and
+ *             only if @a@ is a quadratic residue mod @n@.  The result is
+ *             zero if and only if @a@ and @n@ have a common factor greater
+ *             than one.
+ *
+ *             If @n@ is composite, then this computes the Kronecker symbol
+ *
+ *               %$\jacobi{a}{n}=\jacobi{a}{u}\prod_i\jacobi{a}{p_i}^{e_i}$%
+ *
+ *             where %$n = u p_0^{e_0} \ldots p_{n-1}^{e_{n-1}}$% is the
+ *             prime factorization of %$n$%.  The missing bits are:
+ *
+ *               * %$\jacobi{a}{1} = 1$%;
+ *               * %$\jacobi{a}{-1} = 1$% if @a@ is negative, or 1 if
+ *                 positive;
+ *               * %$\jacobi{a}{0} = 0$%;
+ *               * %$\jacobi{a}{2}$ is 0 if @a@ is even, 1 if @a@ is
+ *                 congruent to 1 or 7 (mod 8), or %$-1$% otherwise.
+ *
+ *             If %$n$% is positive and odd, then this is the Jacobi
+ *             symbol.  (The Kronecker symbol is a consistant domain
+ *             extension; the Jacobi symbol was implemented first, and the
+ *             name stuck.)
+ */
+
+extern int mp_jacobi(mp */*a*/, mp */*n*/);
+
+/* --- @mp_modsqrt@ --- *
+ *
+ * Arguments:  @mp *d@ = destination integer
+ *             @mp *a@ = source integer
+ *             @mp *p@ = modulus (must be prime)
+ *
+ * Returns:    If %$a$% is a quadratic residue, a square root of %$a$%; else
+ *             a null pointer.
+ *
+ * Use:                Returns an integer %$x$% such that %$x^2 \equiv a \pmod{p}$%,
+ *             if one exists; else a null pointer.  This function will not
+ *             work if %$p$% is composite: you must factor the modulus, take
+ *             a square root mod each factor, and recombine the results
+ *             using the Chinese Remainder Theorem.
+ *
+ *             We guarantee that the square root returned is the smallest
+ *             one (i.e., the `positive' square root).
  */
 
-extern void mp_udiv(mp */*q*/, mp */*r*/, const mp */*x*/, const mp */*y*/);
+extern mp *mp_modsqrt(mp */*d*/, mp */*a*/, mp */*p*/);
+
+/* --- @mp_modexp@ --- *
+ *
+ * Arguments:  @mp *d@ = fake destination
+ *             @mp *x@ = base of exponentiation
+ *             @mp *e@ = exponent
+ *             @mp *n@ = modulus (must be positive)
+ *
+ * Returns:    The value %$x^e \bmod n$%.
+ */
+
+extern mp *mp_modexp(mp */*d*/, mp */*x*/, mp */*e*/, mp */*n*/);
+
+/*----- Test harness support ----------------------------------------------*/
+
+#include <mLib/testrig.h>
+
+#ifndef CATACOMB_MPTEXT_H
+#  include "mptext.h"
+#endif
+
+extern const test_type type_mp;
 
 /*----- That's all, folks -------------------------------------------------*/