/* -*-c-*-
*
- * $Id: mp.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ * $Id: mp.h,v 1.3 1999/11/19 13:19:14 mdw Exp $
*
- * Multiprecision arithmetic
+ * Simple multiprecision arithmetic
*
* (c) 1999 Straylight/Edgeware
*/
/*----- Revision history --------------------------------------------------*
*
* $Log: mp.h,v $
- * Revision 1.1 1999/09/03 08:41:12 mdw
- * Initial import.
+ * Revision 1.3 1999/11/19 13:19:14 mdw
+ * Fix const annotation.
+ *
+ * Revision 1.2 1999/11/17 18:02:16 mdw
+ * New multiprecision integer arithmetic suite.
*
*/
/*----- Header files ------------------------------------------------------*/
-#include <stdlib.h>
+#include <assert.h>
#include <string.h>
-#ifndef MPTYPES_H
-# include "mptypes.h"
+#include <mLib/sub.h>
+
+#ifndef MPW_H
+# include "mpw.h"
#endif
#ifndef MPX_H
# include "mpx.h"
#endif
-#ifndef MPSCAN_H
-# include "mpscan.h"
-#endif
-
/*----- Data structures ---------------------------------------------------*/
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;
+ size_t sz;
+ unsigned f;
+ unsigned ref;
} mp;
-enum {
- MPF_SIGN = 1, /* Sign bit */
- MPF_BURN = 2 /* Burn word vector after use */
-};
+#define MP_NEG 1u
+#define MP_BURN 2u
+#define MP_CONST 4u
+#define MP_UNDEF 8u
-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;
+/*----- Useful constants --------------------------------------------------*/
-/*----- External variables ------------------------------------------------*/
+extern mp mp_const[];
-extern mp mp_std;
+#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_MONE (&mp_const[7])
-#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_NEW ((mp *)0)
-/*----- Memory allocation and low-level fiddling --------------------------*/
+/*----- Memory allocation hooks -------------------------------------------*/
-/* --- @mp_create@ --- *
+#ifndef MPARENA_H
+# include "mparena.h"
+#endif
+
+/* --- @MP_ARENA@ --- *
*
- * Arguments @mp *x@ = pointer to MP head
+ * This selects where memory is allocated from. Tweak to use more fancy
+ * things like custom arenas.
+ */
+
+#ifndef MP_ARENA
+# define MP_ARENA MPARENA_GLOBAL
+#endif
+
+/* --- @MP_ALLOC@ --- *
*
- * Returns: ---
+ * Arguments: @size_t sz@ = size required
+ *
+ * Returns: Pointer to an allocated vector of the requested size.
*
- * Use: Initializes an MP ready for use. The initial value is zero.
+ * Use: Hook for vector allocation.
*/
-#define MP_INIT { 0, 0, 0, 0 }
-
-extern void mp_create(mp */*x*/);
+#ifndef MP_ALLOC
+# define MP_ALLOC(sz) mpalloc(MP_ARENA, (sz))
+#endif
-/* --- @MP_BURN@ --- *
+/* --- @MP_FREE@ --- *
*
- * Arguments: @x@ = pointer to MP head
+ * Arguments: @mpw *v@ = pointer to vector
+ *
+ * Returns: ---
*
- * Use: Burns the contents of the MP, if it contains sensitive data.
+ * Use: Hook for vector deallocation.
*/
-#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)
+#ifndef MP_FREE
+# define MP_FREE(v) mpfree(MP_ARENA, (v))
+#endif
+
+/*----- Paranoia management -----------------------------------------------*/
-/* --- @mp_free@ --- *
+/* --- @mp_burn@ --- *
*
- * 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: Marks the integer as `burn-after-use'. When the integer's
+ * memory is deallocated, it is deleted so that traces can't
+ * remain in the swap file. In theory.
*/
-#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_burn(mp */*m*/);
+
+/*----- Trivial macros ----------------------------------------------------*/
-/* --- @MP_ENSURE@ --- *
+/* --- @MP_LEN@ --- *
*
- * Arguments: @x@ = pointer to MP head
- * @len@ = length required (in words)
+ * Arguments: @mp *m@ = pointer to a multiprecision integer
*
- * Use: Ensures that the MP has enough memory to store a @len@-word
- * value.
+ * Returns: Length of the integer, in words.
*/
-#define MP_ENSURE(x, len) do { \
- mp *_x = (x); \
- size_t _len = (len); \
- if (_x->sz < _len) \
- mp_resize(_x, _len); \
-} while (0)
+#define MP_LEN(m) ((m)->vl - ((m)->v))
-/* --- @mp_resize@ --- *
+/*----- Memory management and reference counting --------------------------*/
+
+/* --- @mp_create@ --- *
*
- * Arguments: @mp *x@ = pointer to MP head
- * @size_t sz@ = size required (in words)
+ * Arguments: @size_t sz@ = size of vector required
*
- * Returns: ---
+ * Returns: Pointer to pristine new MP structure with enough memory
+ * bolted onto it.
*
- * Use: Resizes the MP so that its word vector has space for
- * exactly @sz@ words.
+ * Use: Creates a new multiprecision integer with indeterminate
+ * contents. The integer has a single reference.
*/
-extern void mp_resize(mp */*x*/, size_t /*sz*/);
+extern mp *mp_create(size_t /*sz*/);
-/* --- @mp_norm@ --- *
+/* --- @mp_build@ --- *
*
- * Arguments: @mp *x@ = pointer to MP head
+ * 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: `Normalizes' an MP. Fixes the @len@ field so that it's
- * correct. Assumes that @len@ is either already correct or
- * too large.
+ * 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_NORM(x) do { \
- mp *_y = (x); \
- MPX_LEN(_y->len, _y->v, _y->len); \
-} while (0)
-
-extern void mp_norm(mp */*x*/);
+extern void mp_build(mp */*m*/, mpw */*v*/, mpw */*vl*/);
-/* --- @mp_dump@ --- *
+/* --- @mp_destroy@ --- *
*
- * 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: 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_dump(mp */*x*/, FILE */*fp*/);
+extern void mp_destroy(mp */*m*/);
-/* --- @MP_PARANOID@ --- *
+/* --- @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: Marks the MP as containing sensitive data which should be
- * burnt when no longer required.
+ * Use: Copies the given integer. In fact you just get another
+ * reference to the same old one again.
*/
-#define MP_PARANOID(x) ((x)->f |= MPF_BURN)
+extern mp *mp_copy(mp */*m*/);
-/* --- @mp_copy@ --- *
+#define MP_COPY(m) ((m)->ref++, (m))
+
+/* --- @mp_drop@ --- *
*
- * Arguments: @mp *d@ = pointer to MP head for destination
- * @const mp *s@ = pointer to MP head for source
+ * Arguments: @mp *m@ = pointer to a multiprecision integer
*
* Returns: ---
*
- * Use: Copies 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.
*/
-extern void mp_copy(mp */*d*/, const mp */*s*/);
+extern void mp_drop(mp */*m*/);
-/* --- @mp_bits@ --- *
+#define MP_DROP(m) do { \
+ mp *_mm = (m); \
+ if (_mm->ref > 1) \
+ _mm->ref--; \
+ else if (!(_mm->f & MP_CONST)) \
+ mp_destroy(_mm); \
+} while (0)
+
+/* --- @mp_split@ --- *
*
- * Arguments: @mp *x@ = pointer to MP head
+ * Arguments: @mp *m@ = pointer to a multiprecision integer
*
- * Returns: Length of the number in bits.
+ * Returns: A reference to the same integer, possibly with a different
+ * address.
*
- * Use: Calculates the number of bits required to represent a number.
- * The number must be normalized.
+ * Use: Splits off a modifiable version of the integer referred to.
*/
-unsigned long mp_bits(mp */*x*/);
+extern mp *mp_split(mp */*m*/);
+
+#define MP_SPLIT(m) do { \
+ mp *_mm = (m); \
+ if ((_mm->f & MP_CONST) || _mm->ref != 1) { \
+ mp *_dd = mp_create(_mm->sz); \
+ _dd->vl = _dd->v + MP_LEN(_mm); \
+ _dd->f = _mm->f & (MP_NEG | MP_BURN); \
+ memcpy(_dd->v, _mm->v, MPWS(MP_LEN(_mm))); \
+ _dd->ref = 1; \
+ _mm->ref--; \
+ (m) = _dd; \
+ } \
+} while (0)
-/* --- @mp_octets@ --- *
+/* --- @mp_resize@ --- *
*
- * Arguments: @mp *x@ = pointer to MP head
+ * Arguments: @mp *m@ = pointer to a multiprecision integer
+ * @size_t sz@ = new size
*
- * Returns: Length of number in octets.
+ * Returns: ---
*
- * Use: Calculates the number of octets required to represent a
- * number. The number must be normalized.
+ * Use: Resizes the vector containing the integer's digits. The new
+ * size must be at least as large as the current integer's
+ * length. The integer's length is increased and new digits are
+ * filled with zeroes. This isn't really intended for client
+ * use.
*/
-extern size_t mp_octets(mp */*x*/);
-
-/*----- Loading and storing as binary data --------------------------------*/
+extern void mp_resize(mp */*m*/, size_t /*sz*/);
+
+#define MP_RESIZE(m, ssz) do { \
+ mp *_m = (m); \
+ size_t _sz = (ssz); \
+ size_t _len = MP_LEN(_m); \
+ mpw *_v = MP_ALLOC(_sz); \
+ memcpy(_v, _m->v, MPWS(_len)); \
+ if (_m->f & MP_BURN) \
+ memset(_m->v, 0, MPWS(_m->sz)); \
+ MP_FREE(_m->v); \
+ _m->v = _v; \
+ _m->vl = _v + _len; \
+ _m->sz = _sz; \
+} while (0)
-/* --- @mp_storel@ --- *
+/* --- @mp_ensure@ --- *
*
- * Arguments: @mp *x@ = pointer to MP head
- * @octet *p@ = pointer to octet array
- * @size_t sz@ = size of octet array
+ * Arguments: @mp *m@ = pointer to a multiprecision integer
+ * @size_t sz@ = required size
*
* Returns: ---
*
- * 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: Ensures that the integer has enough space for @sz@ digits.
+ * The value is not changed.
*/
-extern void mp_storel(mp */*x*/, octet */*p*/, size_t /*sz*/);
+extern void mp_ensure(mp */*m*/, size_t /*sz*/);
+
+#define MP_ENSURE(m, ssz) do { \
+ mp *_mm = (m); \
+ size_t _ssz = (ssz); \
+ size_t _len = MP_LEN(_mm); \
+ if (_ssz > _mm->sz) \
+ MP_RESIZE(_mm, _ssz); \
+ if (!(_mm->f & MP_UNDEF) && _ssz > _len) { \
+ memset(_mm->vl, 0, MPWS(_ssz - _len)); \
+ _mm->vl = _mm->v + _ssz; \
+ } \
+} while (0)
-/* --- @mp_loadl@ --- *
+/* --- @mp_modify@ --- *
*
- * Arguments: @mp *x@ = pointer to MP head
- * @const octet *p@ = pointer to octet array
- * @size_t sz@ = size of octet array
+ * Arguments: @mp *m@ = pointer to a multiprecision integer
+ * @size_t sz@ = size required
*
- * Returns: ---
+ * Returns: Pointer to the integer (possibly different).
*
- * Use: Loads an MP in an octet array, least significant octet
- * first.
+ * Use: Prepares an integer to be overwritten. It's split off from
+ * other references to the same integer, and sufficient space is
+ * allocated.
*/
-extern void mp_loadl(mp */*x*/, const octet */*p*/, size_t /*sz*/);
+extern mp *mp_modify(mp */*m*/, size_t /*sz*/);
-/* --- @mp_storeb@ --- *
+#define MP_MODIFY(m, sz) do { \
+ size_t _rq = (sz); \
+ mp *_m = (m); \
+ if (_m == MP_NEW) \
+ _m = mp_create(_rq); \
+ else { \
+ MP_SPLIT(_m); \
+ MP_ENSURE(_m, _rq); \
+ } \
+ _m->vl = _m->v + _rq; \
+ (m) = _m; \
+} while (0)
+
+/*----- Size manipulation -------------------------------------------------*/
+
+/* --- @mp_shrink@ --- *
*
- * Arguments: @mp *x@ = pointer to MP head
- * @octet *p@ = pointer to octet array
- * @size_t sz@ = size of octet array
+ * Arguments: @mp *m@ = pointer to a multiprecision integer
*
* 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: 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_storeb(mp */*x*/, octet */*p*/, size_t /*sz*/);
+extern void mp_shrink(mp */*m*/);
-/* --- @mp_loadb@ --- *
+#define MP_SHRINK(m) do { \
+ mp *_mm = (m); \
+ MPX_SHRINK(_mm->v, _mm->vl); \
+ if (!MP_LEN(_mm)) \
+ _mm->f &= ~MP_NEG; \
+} while (0)
+
+/* --- @mp_minimize@ --- *
*
- * Arguments: @mp *x@ = pointer to MP head
- * @const octet *p@ = pointer to octet array
- * @size_t sz@ = size of octet array
+ * Arguments: @mp *m@ = pointer to a multiprecision integer
*
* Returns: ---
*
- * Use: Loads an MP in an octet array, most significant octet
- * first.
+ * 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.
*/
-extern void mp_loadb(mp */*x*/, const octet */*p*/, size_t /*sz*/);
+extern void mp_minimize(mp */*m*/);
+
+/*----- Bit scanning ------------------------------------------------------*/
-/*----- Iterating through bits --------------------------------------------*/
+#ifndef MPSCAN_H
+# include "mpscan.h"
+#endif
-/* --- @mp_mkbitscan@ --- *
+/* --- @mp_scan@ --- *
*
- * Arguments: @mp_bitscan *sc@ = pointer to bitscan object
- * @const mp *x@ = pointer to MP head
+ * Arguments: @mpscan *sc@ = pointer to bitscanner block
+ * @const mp *m@ = pointer to a multiprecision integer
*
* Returns: ---
*
- * Use: Initializes a bitscan object.
+ * Use: Initializes a bitscanner on a multiprecision integer.
*/
-extern void mp_mkbitscan(mp_bitscan */*sc*/, const mp */*x*/);
+extern void mp_scan(mpscan */*sc*/, const mp */*m*/);
+
+#define MP_SCAN(sc, m) do { \
+ const mp *_mm = (m); \
+ mpscan *_sc = (sc); \
+ MPSCAN_INITX(_sc, _mm->v, _mm->vl); \
+} while (0)
+
+/* --- Other bitscanning aliases --- */
+
+#define mp_step mpscan_step
+#define mp_bit mpscan_bit
+
+#define MP_STEP MPSCAN_STEP
+#define MP_BIT MPSCAN_BIT
-/* --- @mp_bstep@ --- *
+/*----- Loading and storing -----------------------------------------------*/
+
+/* --- @mp_octets@ --- *
*
- * Arguments: @mp_bitscan *sc@ = pointer to bitscanner object
+ * Arguments: @const mp *m@ = a multiprecision integer
*
- * Returns: Nonzero if there is another bit to read.
+ * Returns: The number of octets required to represent @m@.
*
- * Use: Steps on to the next bit, and tells the caller whether one
- * exists.
+ * Use: Calculates the external storage required for a multiprecision
+ * integer.
*/
-extern int mp_bstep(mp_bitscan */*sc*/);
+extern size_t mp_octets(const mp *m);
-/* --- @mp_bit@ --- *
+/* --- @mp_loadl@ --- *
*
- * Arguments: @const mp_bitscan *sc@ = pointer to bitscanner
+ * Arguments: @mp *d@ = destination
+ * @const void *pv@ = pointer to source data
+ * @size_t sz@ = size of the source data
*
- * Returns: Current bit value.
+ * Returns: Resulting multiprecision number.
*
- * Use: Returns the value of the current bit.
+ * 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}$%.
*/
-#define MP_BIT(sc) ((sc)->w & 1)
+extern mp *mp_loadl(mp */*d*/, const void */*pv*/, size_t /*sz*/);
-extern int mp_bit(const mp_bitscan */*sc*/);
+/* --- @mp_storel@ --- *
+ *
+ * Arguments: @const mp *m@ = source
+ * @void *pv@ = pointer to output array
+ * @size_t sz@ = size of the output array
+ *
+ * Returns: ---
+ *
+ * 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}$%.
+ */
-/*----- Shifting ----------------------------------------------------------*/
+extern void mp_storel(const mp */*m*/, void */*pv*/, size_t /*sz*/);
-/* --- @mp_lsl@ --- *
+/* --- @mp_loadb@ --- *
*
- * 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
+ * @const void *pv@ = pointer to source data
+ * @size_t sz@ = size of the source data
*
- * Returns: ---
+ * Returns: Resulting multiprecision number.
*
- * Use: Shifts a number left by a given number of bit positions.
+ * 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_lsl(mp */*d*/, const mp */*x*/, size_t /*n*/);
+extern mp *mp_loadb(mp */*d*/, const void */*pv*/, size_t /*sz*/);
-/* --- @mp_lsr@ --- *
+/* --- @mp_storeb@ --- *
*
- * 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: @const mp *m@ = source
+ * @void *pv@ = pointer to output array
+ * @size_t sz@ = size of the output array
*
* Returns: ---
*
- * Use: Shifts a number right by a given number of bit positions.
+ * 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_lsr(mp */*d*/, const mp */*x*/, size_t /*n*/);
+extern void mp_storeb(const mp */*m*/, void */*pv*/, size_t /*sz*/);
-/*----- Unsigned arithmetic -----------------------------------------------*/
+/*----- Simple arithmetic -------------------------------------------------*/
-/* --- @mp_uadd@ --- *
+/* --- @mp_2c@ --- *
*
- * 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
*
- * Returns: ---
+ * Returns: Result, @a@ converted to two's complement notation.
+ */
+
+extern mp *mp_2c(mp */*d*/, mp */*a*/);
+
+/* --- @mp_sm@ --- *
+ *
+ * Arguments: @mp *d@ = destination
+ * @mp *a@ = source
*
- * Use: Performs unsigned MP addition.
+ * Returns: Result, @a@ converted to the native signed-magnitude
+ * notation.
*/
-extern void mp_uadd(mp */*d*/, const mp */*x*/, const mp */*y*/);
+extern mp *mp_sm(mp */*d*/, mp */*a*/);
-/* --- @mp_usub@ --- *
+/* --- @mp_lsl@ --- *
*
- * Arguments: @const mp *d@ = pointers to MP head of destination
- * @const mp *x, *y@ = pointers to MP heads of operands
+ * Arguments: @mp *d@ = destination
+ * @const mp *a@ = source
+ * @size_t n@ = number of bits to move
*
- * Returns: ---
+ * Returns: Result, @a@ shifted left by @n@.
+ */
+
+extern mp *mp_lsl(mp */*d*/, const mp */*a*/, size_t /*n*/);
+
+/* --- @mp_lsr@ --- *
+ *
+ * Arguments: @mp *d@ = destination
+ * @const mp *a@ = source
+ * @size_t n@ = number of bits to move
*
- * Use: Performs unsigned MP subtraction.
+ * Returns: Result, @a@ shifted left by @n@.
*/
-extern void mp_usub(mp */*d*/, const mp */*x*/, const mp */*y*/);
+extern mp *mp_lsr(mp */*d*/, const mp */*a*/, size_t /*n*/);
-/* --- @mp_ucmp@ --- *
+/* --- @mp_cmp@ --- *
*
- * Arguments: @const mp *x, *y@ = pointers to MP heads of operands
+ * Arguments: @const mp *a, *b@ = two numbers
*
- * Returns: Less than, equal to, or greater than zero.
+ * 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_add@ --- *
*
- * Use: Performs unsigned MP comparison.
+ * Arguments: @mp *d@ = destination
+ * @const mp *a, *b@ = sources
+ *
+ * Returns: Result, @a@ added to @b@.
*/
-#define MP_UCMP(x, op, y) (mp_ucmp((x), (y)) op 0)
+extern mp *mp_add(mp */*d*/, const mp */*a*/, const mp */*b*/);
-extern int mp_ucmp(const mp */*x*/, const mp */*y*/);
+/* --- @mp_sub@ --- *
+ *
+ * Arguments: @mp *d@ = destination
+ * @const mp *a, *b@ = sources
+ *
+ * Returns: Result, @b@ subtracted from @a@.
+ */
-/* --- @mp_umul@ --- *
+extern mp *mp_sub(mp */*d*/, const mp */*a*/, const mp */*b*/);
+
+/* --- @mp_mul@ --- *
*
- * Arguments: @mp *d@ = pointer to MP head of destination
- * @const mp *x, *y@ = pointes to MP heads of operands
+ * Arguments: @mp *d@ = destination
+ * @const mp *a, *b@ = sources
*
- * Returns: ---
+ * Returns: Result, @a@ multiplied by @b@.
+ */
+
+extern mp *mp_mul(mp */*d*/, const mp */*a*/, const mp */*b*/);
+
+/* --- @mp_sqr@ --- *
+ *
+ * Arguments: @mp *d@ = destination
+ * @const mp *a@ = source
+ *
+ * Returns: Result, @a@ squared.
+ */
+
+extern mp *mp_sqr(mp */*d*/, const mp */*a*/);
+
+/* --- @mp_div@ --- *
*
- * Use: Performs unsigned MP multiplication.
+ * Arguments: @mp **qq, **rr@ = destination, quotient and remainder
+ * @const mp *a, *b@ = sources
+ *
+ * Use: Calculates the quotient and remainder when @a@ is divided by
+ * @b@.
*/
-extern void mp_umul(mp */*d*/, const mp */*x*/, const mp */*y*/);
+extern void mp_div(mp **/*qq*/, mp **/*rr*/,
+ const mp */*a*/, const mp */*b*/);
+
+/*----- More advanced algorithms ------------------------------------------*/
-/* --- @mp_udiv@ --- *
+/* --- @mp_gcd@ --- *
*
- * Arguments: @mp *q, *r@ = pointers to MP heads for quotient, remainder
- * @const mp *x, *y@ = pointers to MP heads for operands
+ * 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. Note that,
+ * unlike @mp_div@ for example, it is not possible to specify
+ * explicit destinations -- new MPs are always allocated.
*/
-extern void mp_udiv(mp */*q*/, mp */*r*/, const mp */*x*/, const mp */*y*/);
+extern void mp_gcd(mp **/*gcd*/, mp **/*xx*/, mp **/*yy*/,
+ mp */*a*/, mp */*b*/);
+
+/*----- Test harness support ----------------------------------------------*/
+
+#include <mLib/testrig.h>
+
+#ifndef MPTEXT_H
+# include "mptext.h"
+#endif
+
+extern const test_type type_mp;
/*----- That's all, folks -------------------------------------------------*/