Merge branch 'mdw/cpu-dispatch'
authorMark Wooding <mdw@distorted.org.uk>
Wed, 18 May 2016 09:29:03 +0000 (10:29 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 21 May 2016 16:56:04 +0000 (17:56 +0100)
* mdw/cpu-dispatch:
  Add support machinery for ARM hosts.
  base/dispatch.c: Add (unused) machinery for probing ELF auxilary vector.
  Add support for AMD64 processors and Microsoft Windows.
  symm/rijndael-x86-aseni.S: Unify encryption and decryption with a macro.
  symm/rijndael-x86-aesni.S: Use xmm5 instead of xmm7.
  symm/*.S: Symbolic names for shuffles.
  symm/chacha-x86-sse2.S: Fix the register allocation comment.
  Preprocess the assembler files.
  configure.ac: Improve the host CPU family detection.
  base/dispatch.c: Indent some preprocessor definitions properly.
  Add a pile of debug output around the CPU dispatching machinery.
  base/dispatch.c: Add documentation for some internal functions.
  base/dispatch.c: Add in more useful section markers.
  Support Intel's AES Native Instructions where available on x86 hardware.
  symm/: New SSE2 implementations of Salsa20 and ChaCha.
  symm/salsa20.c, symm/salsa20-core.h: Permute input matrix for SIMD.
  debian/rules: Run tests twice, once without any detected CPU features.
  base/dispatch.c: Check operating system support for XMM registers.
  configure.ac, base/dispatch.[ch]: CPU-specific implementations.
  configure.ac: Arrange to have an assembler available.

Conflicts:
configure.ac
symm/Makefile.am

36 files changed:
Makefile.am
build-setup
configure.ac
debian/changelog
debian/control
debian/source/format [new file with mode: 0644]
math/Makefile.am
math/mp-fibonacci.c
math/mp.h
math/mptext.c
math/mptypes.c [deleted file]
misc/Makefile.am
pub/Makefile.am
pub/bbs-rand.c
rand/Makefile.am
rand/dsarand.c
rand/grand.c
rand/grand.h
rand/lcrand.c
rand/noise.c
rand/rand.c
rand/sslprf.c
rand/tlsprf.c
symm/Makefile.am
symm/cbc-def.h
symm/cfb-def.h
symm/chacha.c
symm/counter-def.h
symm/ecb-def.h
symm/mgf-def.h
symm/modes.am.in
symm/ofb-def.h
symm/rc4.c
symm/salsa20.c
symm/seal.c
vars.am

index d18ac3a..a2ae433 100644 (file)
@@ -33,7 +33,8 @@ SUBDIRS                        =
 ### The main library.
 
 lib_LTLIBRARIES                 = libcatacomb.la
-libcatacomb_la_LDFLAGS  = -version-info $(LIBTOOL_VERSION_INFO)
+libcatacomb_la_LDFLAGS  = -version-info $(LIBTOOL_VERSION_INFO) \
+                               -no-undefined
 libcatacomb_la_LIBADD   = $(MATHLIBS) $(mLib_LIBS)
 libcatacomb_la_SOURCES  =
 
@@ -112,6 +113,7 @@ EXTRA_DIST          += debian/control
 EXTRA_DIST             += debian/changelog
 EXTRA_DIST             += debian/copyright
 EXTRA_DIST             += debian/compat
+EXTRA_DIST             += debian/source/format
 
 ## catacomb2
 EXTRA_DIST             += debian/catacomb2.install
index ded8b11..2bbf56f 100755 (executable)
@@ -1,4 +1,4 @@
 #! /bin/sh -ex
 for gen in symm/modes.am symm/stubs.am; do
-  if [ ! -r $gen ]; then touch -t197001010000.00 $gen; fi
+  if [ ! -r $gen ]; then touch -t197101010000.00 $gen; fi
 done
index e3e5c21..715a5c2 100644 (file)
@@ -31,7 +31,7 @@ mdw_AUTO_VERSION
 AC_INIT([catacomb], AUTO_VERSION, [mdw@distorted.org.uk])
 AC_CONFIG_SRCDIR([catacomb.pc.in])
 AC_CONFIG_AUX_DIR([config])
-AM_INIT_AUTOMAKE([foreign parallel-tests])
+AM_INIT_AUTOMAKE([foreign parallel-tests color-tests subdir-objects])
 AC_CANONICAL_HOST
 mdw_SILENT_RULES
 
@@ -248,7 +248,7 @@ dnl Memory locking support.
 AC_CHECK_FUNCS([mlock])
 
 dnl Necessary support libraries.
-PKG_CHECK_MODULES([mLib], [mLib >= 2.2.1])
+PKG_CHECK_MODULES([mLib], [mLib >= 2.2.2.1])
 AM_CFLAGS="$AM_CFLAGS $mLib_CFLAGS"
 
 dnl--------------------------------------------------------------------------
index 2d1989d..2792ff9 100644 (file)
@@ -1,3 +1,35 @@
+catacomb (2.2.1) experimental; urgency=low
+
+  * Some internal improvements.
+  * Debian packaging cleanups (fix build-depends, update mLib dependency).
+
+ -- Mark Wooding <mdw@distorted.org.uk>  Thu, 18 Feb 2016 16:43:09 +0000
+
+catacomb (2.2.0) experimental; urgency=low
+
+  * catacomb2: Fix rsa_recover crash on even modulus.
+  * catacomb-bin: Report error taking factorial of negative input.
+  * catacomb2: Fix EC_FIND and EC_NEG on 2-torsion points of prime curves.
+  * catacomb-dev: Support multiple flavours of EC point compression.
+  * catacomb2: Fix theoretical rsa_recover crash if factoring loop runs
+    out of prime numbers.
+  * catacomb2: Overhaul crypto primitives used in true-random generator.
+  * catacomb-bin: Improve rspit: high-resolution timing, and 64-bit size
+    support.
+  * catacomb-dev: New conversions between MP integers and C integer types.
+  * catacomb2: Change gcipher for Seal incompatibly.  The IV is now
+    big-endian bytes (rather than `uint32'), and the `block size' is 4.
+  * catacomb2: Mix a constant string into DSA nonce generation to improve
+    resistance to protocol interference.
+  * catacomb2: Fix the freewheel random source, which hasn't been enabled
+    for ages due to a configure-script bug.
+  * catacomb-bin: The key tool can now read and write multiple
+    presentations for key fingerprints.
+  * catacomb2, catacomb-dev: Support Daniel Bernstein's Salsa20 and ChaCha
+    stream ciphers.
+
+ -- Mark Wooding <mdw@distorted.org.uk>  Mon, 20 Jul 2015 14:15:31 +0100
+
 catacomb (2.1.7) experimental; urgency=low
 
   * A number of entropy-source fixes.
index 507a222..9bbe802 100644 (file)
@@ -1,7 +1,7 @@
 Source: catacomb
 Section: libs
 Priority: extra
-Build-Depends: mlib-dev (>= 2.2.1), debhelper (>= 9)
+Build-Depends: debhelper (>= 9), python, pkg-config, mlib-dev (>= 2.2.2.1)
 Maintainer: Mark Wooding <mdw@distorted.org.uk>
 Standards-Version: 3.1.1
 
diff --git a/debian/source/format b/debian/source/format
new file mode 100644 (file)
index 0000000..d3827e7
--- /dev/null
@@ -0,0 +1 @@
+1.0
index 7cabf89..908d268 100644 (file)
@@ -84,29 +84,29 @@ libmath_la_SOURCES  += exp.c
 ## Main user-visible multiprecision arithmetic.
 pkginclude_HEADERS     += mp.h
 libmath_la_SOURCES     += mp-arith.c
-TESTS                  += mp-arith.$t
+TESTS                  += mp-arith.t$(EXEEXT)
 libmath_la_SOURCES     += mp-const.c
 libmath_la_SOURCES     += mp-exp.c mp-exp.h
 libmath_la_SOURCES     += mp-gcd.c
-TESTS                  += mp-gcd.$t
+TESTS                  += mp-gcd.t$(EXEEXT)
 libmath_la_SOURCES     += mp-io.c
 libmath_la_SOURCES     += mp-jacobi.c
-TESTS                  += mp-jacobi.$t
+TESTS                  += mp-jacobi.t$(EXEEXT)
 libmath_la_SOURCES     += mp-mem.c
 libmath_la_SOURCES     += mp-misc.c
 libmath_la_SOURCES     += mp-modexp.c
-TESTS                  += mp-modexp.$t
+TESTS                  += mp-modexp.t$(EXEEXT)
 libmath_la_SOURCES     += mp-modsqrt.c
-TESTS                  += mp-modsqrt.$t
+TESTS                  += mp-modsqrt.t$(EXEEXT)
 libmath_la_SOURCES     += mp-sqrt.c
-TESTS                  += mp-sqrt.$t
+TESTS                  += mp-sqrt.t$(EXEEXT)
 libmath_la_SOURCES     += mp-test.c
 EXTRA_DIST             += t/mp
 
 ## Computing Fibonacci numbers.
 pkginclude_HEADERS     += mp-fibonacci.h
 libmath_la_SOURCES     += mp-fibonacci.c
-TESTS                  += mp-fibonacci.$t
+TESTS                  += mp-fibonacci.t$(EXEEXT)
 
 ## Special memory allocation for multiprecision integers.
 pkginclude_HEADERS     += mparena.h
@@ -115,36 +115,36 @@ libmath_la_SOURCES        += mparena.c
 ## Barrett reduction, an efficient method for modular reduction.
 pkginclude_HEADERS     += mpbarrett.h
 libmath_la_SOURCES     += mpbarrett.c
-TESTS                  += mpbarrett.$t
+TESTS                  += mpbarrett.t$(EXEEXT)
 libmath_la_SOURCES     += mpbarrett-exp.c mpbarrett-mexp.c mpbarrett-exp.h
-TESTS                  += mpbarrett-exp.$t mpbarrett-mexp.$t
-TESTS                  += mpbarrett.$t
+TESTS                  += mpbarrett-exp.t$(EXEEXT) mpbarrett-mexp.t$(EXEEXT)
+TESTS                  += mpbarrett.t$(EXEEXT)
 EXTRA_DIST             += t/mpbarrett
 
 ## Solving congruences using the Chinese Remainder Theorem.
 pkginclude_HEADERS     += mpcrt.h
 libmath_la_SOURCES     += mpcrt.c
-TESTS                  += mpcrt.$t
+TESTS                  += mpcrt.t$(EXEEXT)
 EXTRA_DIST             += t/mpcrt
 
 ## Conversions between machine-native and multiprecision integers.
 pkginclude_HEADERS     += mpint.h
 libmath_la_SOURCES     += mpint.c
-TESTS                  += mpint.$t
+TESTS                  += mpint.t$(EXEEXT)
 EXTRA_DIST             += t/mpint
 
 ## Montgomery reduction, a clever method for modular arithmetic.
 pkginclude_HEADERS     += mpmont.h
 libmath_la_SOURCES     += mpmont.c
-TESTS                  += mpmont.$t
+TESTS                  += mpmont.t$(EXEEXT)
 libmath_la_SOURCES     += mpmont-exp.c mpmont-mexp.c mpmont-exp.h
-TESTS                  += mpmont-exp.$t mpmont-mexp.$t
+TESTS                  += mpmont-exp.t$(EXEEXT) mpmont-mexp.t$(EXEEXT)
 EXTRA_DIST             += t/mpmont
 
 ## Efficient multiplication of many small numbers.
 pkginclude_HEADERS     += mpmul.h
 libmath_la_SOURCES     += mpmul.c
-TESTS                  += mpmul.$t
+TESTS                  += mpmul.t$(EXEEXT)
 
 ## Generating random numbers.
 pkginclude_HEADERS     += mprand.h
@@ -154,7 +154,7 @@ libmath_la_SOURCES  += mprand.c
 ## representations.
 pkginclude_HEADERS     += mpreduce.h
 libmath_la_SOURCES     += mpreduce.c mpreduce-exp.h
-TESTS                  += mpreduce.$t
+TESTS                  += mpreduce.t$(EXEEXT)
 EXTRA_DIST             += t/mpreduce
 
 ## Iteratiion over the bianry representation of multiprecision integers.
@@ -165,7 +165,7 @@ libmath_la_SOURCES  += mpscan.c
 ## representations.
 pkginclude_HEADERS     += mptext.h
 libmath_la_SOURCES     += mptext.c
-TESTS                  += mptext.$t
+TESTS                  += mptext.t$(EXEEXT)
 libmath_la_SOURCES     += mptext-dstr.c
 libmath_la_SOURCES     += mptext-file.c
 libmath_la_SOURCES     += mptext-len.c
@@ -175,9 +175,9 @@ EXTRA_DIST          += t/mptext
 ## Low-level multiprecision arithmetic.
 pkginclude_HEADERS     += mpx.h bitops.h mpw.h
 libmath_la_SOURCES     += mpx.c
-TESTS                  += mpx.$t
+TESTS                  += mpx.t$(EXEEXT)
 libmath_la_SOURCES     += karatsuba.h mpx-kmul.c mpx-ksqr.c
-TESTS                  += mpx-kmul.$t mpx-ksqr.$t
+TESTS                  += mpx-kmul.t$(EXEEXT) mpx-ksqr.t$(EXEEXT)
 noinst_PROGRAMS                += bittest
 TESTS                  += bittest
 EXTRA_DIST             += t/mpx
@@ -190,7 +190,7 @@ libmath_la_SOURCES  += qdparse.c
 ## Pollard's `rho' algorithm for determining discrete logarithms.
 pkginclude_HEADERS     += rho.h
 libmath_la_SOURCES     += rho.c
-TESTS                  += rho.$t
+TESTS                  += rho.t$(EXEEXT)
 
 ###--------------------------------------------------------------------------
 ### Prime number checking, searching, and related jobs.
@@ -201,18 +201,19 @@ pkginclude_HEADERS        += limlee.h
 libmath_la_SOURCES     += limlee.c
 
 ## A table of small prime numbers.
-pkginclude_HEADERS     += $(precomp)/primetab.h
-libmath_la_SOURCES     += $(precomp)/primetab.c
-PRECOMPS               += $(precomp)/primetab.h $(precomp)/primetab.c
+pkginclude_HEADERS     += $(precomp)/math/primetab.h
+nodist_libmath_la_SOURCES += ../precomp/math/primetab.c
+PRECOMPS               += $(precomp)/math/primetab.h \
+                          $(precomp)/math/primetab.c
 PRECOMP_PROGS          += genprimes
 genprimes_LDADD                 = $(mLib_LIBS)
 if !CROSS_COMPILING
-$(precomp)/primetab.h: $(precomp)/primetab.c
-$(precomp)/primetab.c:
-       $(AM_V_at)$(MKDIR_P) $(precomp)
-       $(AM_V_at)$(MAKE) genprimes$e
+$(precomp)/math/primetab.h: $(precomp)/math/primetab.c
+$(precomp)/math/primetab.c:
+       $(AM_V_at)$(MKDIR_P) $(precomp)/math
+       $(AM_V_at)$(MAKE) genprimes$(EXEEXT)
        $(AM_V_GEN)./genprimes -sCATACOMB_PRIMETAB_H \
-               -h$(precomp)/primetab.h -c$(precomp)/primetab.c \
+               -h$(precomp)/math/primetab.h -c$(precomp)/math/primetab.c \
                -n256 -t"unsigned short" -iprimetab
 endif
 
@@ -228,7 +229,7 @@ libmath_la_SOURCES  += pgen.c
 libmath_la_SOURCES     += pgen-gcd.c
 libmath_la_SOURCES     += pgen-simul.c
 libmath_la_SOURCES     += pgen-stdev.c
-TESTS                  += pgen.$t
+TESTS                  += pgen.t$(EXEEXT)
 EXTRA_DIST             += t/pgen
 
 ## Finding primitive elements in finite fields.
@@ -238,8 +239,8 @@ libmath_la_SOURCES  += prim.c
 ## Iterating over all prime numbers from a given starting point.
 pkginclude_HEADERS     += primeiter.h
 libmath_la_SOURCES     += primeiter.c
-TESTS                  += primeiter.$t
-primeiter.lo: $(precomp)/wheel.h
+TESTS                  += primeiter.t$(EXEEXT)
+primeiter.lo: $(precomp)/math/wheel.h
 
 ## The Miller--Rabin primality test.
 pkginclude_HEADERS     += rabin.h
@@ -251,18 +252,18 @@ pkginclude_HEADERS        += strongprime.h
 libmath_la_SOURCES     += strongprime.c
 
 ## A `wheel', used by the prime iteration machinery.
-pkginclude_HEADERS     += $(precomp)/wheel.h
-libmath_la_SOURCES     += $(precomp)/wheel.c
-PRECOMPS               += $(precomp)/wheel.h $(precomp)/wheel.c
+pkginclude_HEADERS     += $(precomp)/math/wheel.h
+nodist_libmath_la_SOURCES += ../precomp/math/wheel.c
+PRECOMPS               += $(precomp)/math/wheel.h $(precomp)/math/wheel.c
 PRECOMP_PROGS          += genwheel
 genwheel_LDADD          = $(mLib_LIBS)
 if !CROSS_COMPILING
-$(precomp)/wheel.h: $(precomp)/wheel.c
-$(precomp)/wheel.c:
-       $(AM_V_at)$(MKDIR_P) $(precomp)
-       $(AM_V_at)$(MAKE) genwheel$e
+$(precomp)/math/wheel.h: $(precomp)/math/wheel.c
+$(precomp)/math/wheel.c:
+       $(AM_V_at)$(MKDIR_P) $(precomp)/math
+       $(AM_V_at)$(MAKE) genwheel$(EXEEXT)
        $(AM_V_GEN)./genwheel -sCATACOMB_WHEEL_H \
-               -h$(precomp)/wheel.h -c$(precomp)/wheel.c \
+               -h$(precomp)/math/wheel.h -c$(precomp)/math/wheel.c \
                -n5 -t"unsigned char" -iwheel
 endif
 
@@ -272,42 +273,44 @@ endif
 ## User-visible binary polynomial arithmetic.
 pkginclude_HEADERS     += gf.h
 libmath_la_SOURCES     += gf-arith.c
-TESTS                  += gf-arith.$t
+TESTS                  += gf-arith.t$(EXEEXT)
 libmath_la_SOURCES     += gf-exp.c gf-exp.h
 libmath_la_SOURCES     += gf-gcd.c
-TESTS                  += gf-gcd.$t
+TESTS                  += gf-gcd.t$(EXEEXT)
 EXTRA_DIST             += t/gf
 
 ## Low-level binary polynomial arithmetic.
 pkginclude_HEADERS     += gfx.h
 libmath_la_SOURCES     += gfx.c
-TESTS                  += gfx.$t
+TESTS                  += gfx.t$(EXEEXT)
 libmath_la_SOURCES     += gfx-kmul.c
-TESTS                  += gfx-kmul.$t
-libmath_la_SOURCES     += gfx-sqr.c $(precomp)/gfx-sqrtab.c
-PRECOMPS               += $(precomp)/gfx-sqrtab.c
+TESTS                  += gfx-kmul.t$(EXEEXT)
+libmath_la_SOURCES     += gfx-sqr.c
+nodist_libmath_la_SOURCES += ../precomp/math/gfx-sqrtab.c
+PRECOMPS               += $(precomp)/math/gfx-sqrtab.c
 PRECOMP_PROGS          += gfx-sqr-mktab
 if !CROSS_COMPILING
-$(precomp)/gfx-sqrtab.c:
-       $(AM_V_at)$(MKDIR_P) $(precomp)
-       $(AM_V_at)$(MAKE) gfx-sqr-mktab$e
-       $(AM_V_GEN)./gfx-sqr-mktab >$(precomp)/gfx-sqrtab.c.new && \
-               mv $(precomp)/gfx-sqrtab.c.new $(precomp)/gfx-sqrtab.c
+$(precomp)/math/gfx-sqrtab.c:
+       $(AM_V_at)$(MKDIR_P) $(precomp)/math
+       $(AM_V_at)$(MAKE) gfx-sqr-mktab$(EXEEXT)
+       $(AM_V_GEN)./gfx-sqr-mktab >$(precomp)/math/gfx-sqrtab.c.new && \
+               mv $(precomp)/math/gfx-sqrtab.c.new \
+                       $(precomp)/math/gfx-sqrtab.c
 endif
-TESTS                  += gfx-sqr.$t
+TESTS                  += gfx-sqr.t$(EXEEXT)
 EXTRA_DIST             += t/gfx
 
 ## Conversions between normal and polynomial basis representations for binary
 ## fields.
 pkginclude_HEADERS     += gfn.h
 libmath_la_SOURCES     += gfn.c
-TESTS                  += gfn.$t
+TESTS                  += gfn.t$(EXEEXT)
 EXTRA_DIST             += t/gfn
 
 ## Efficient reduction modulo sparse polynomials.
 pkginclude_HEADERS     += gfreduce.h
 libmath_la_SOURCES     += gfreduce.c gfreduce-exp.h
-TESTS                  += gfreduce.$t
+TESTS                  += gfreduce.t$(EXEEXT)
 EXTRA_DIST             += t/gfreduce
 
 ###--------------------------------------------------------------------------
@@ -325,7 +328,7 @@ libmath_la_SOURCES  += g-bin.c
 libmath_la_SOURCES     += g-prime.c
 libmath_la_SOURCES     += g-ec.c
 EXTRA_DIST             += group-test.c
-TESTS                  += group-test.$t
+TESTS                  += group-test.t$(EXEEXT)
 EXTRA_DIST             += t/group
 
 ## Abstract finite fields.
@@ -363,11 +366,11 @@ pkginclude_HEADERS        += ec.h ec-guts.h
 libmath_la_SOURCES     += ec.c
 libmath_la_SOURCES     += ec-exp.c ec-exp.h
 libmath_la_SOURCES     += ec-info.c
-TESTS                  += ec-info.$t
+TESTS                  += ec-info.t$(EXEEXT)
 libmath_la_SOURCES     += ec-bin.c
-TESTS                  += ec-bin.$t
+TESTS                  += ec-bin.t$(EXEEXT)
 libmath_la_SOURCES     += ec-prime.c
-TESTS                  += ec-prime.$t
+TESTS                  += ec-prime.t$(EXEEXT)
 EXTRA_DIST             += t/ec
 
 ## The standard `raw' encoding (`EC2OSP') of elliptic curve points.
@@ -381,7 +384,7 @@ libmath_la_SOURCES  += ec-fetch.c
 ## Test infrastructure for elliptic curves.
 pkginclude_HEADERS     += ec-test.h
 libmath_la_SOURCES     += ec-test.c
-TESTS                  += ec-test.$t
+TESTS                  += ec-test.t$(EXEEXT)
 
 ## Table of built-in elliptic-curve groups.
 pkginclude_HEADERS     += ectab.h
index 9b37ebf..1db9b21 100644 (file)
@@ -37,7 +37,7 @@
  * %$F_{k-1} = F_{k+1} - F_k$%; in particular, %$F_{-1} = 1$% and
  * %$F_{-2} = -1$%.)  We say that %$F_k$% is the %$k$%th Fibonacci number.
  *
- * We work in the ring %$\ZZ[t]/(t^2 - t -1)$%.  Every residue class in this
+ * We work in the ring %$\ZZ[t]/(t^2 - t - 1)$%.  Every residue class in this
  * ring contains a unique representative with degree at most 1.  I claim that
  * %$t^k = F_k t + F_{k-1}$% for all %$k$%.  Certainly %$t = F_1 t + F_0$%.
  * Note that %$t (F_{-1} t + F_{-2}) = t (t - 1) = t^2 - t = 1$%, so the
index bb109b5..ad4309e 100644 (file)
--- a/math/mp.h
+++ b/math/mp.h
@@ -37,6 +37,7 @@
 #include <assert.h>
 #include <string.h>
 
+#include <mLib/macros.h>
 #include <mLib/sub.h>
 
 #ifndef CATACOMB_MPW_H
@@ -196,7 +197,8 @@ extern void mp_destroy(mp */*m*/);
 
 extern mp *mp_copy(mp */*m*/);
 
-#define MP_COPY(m) ((m)->ref++, (m))
+#define MP_COPY(m) MUFFLE_WARNINGS_EXPR(GCC_WARNING("-Wunused-value"), \
+                                       ((m)->ref++, (m)))
 
 /* --- @mp_drop@ --- *
  *
index 5d4640e..c902264 100644 (file)
@@ -60,7 +60,7 @@
 
 #define DEPTH (CHAR_BIT * sizeof(size_t) + 10)
 
-/*----- Main code ---------------------------------------------------------*/
+/*----- Input -------------------------------------------------------------*/
 
 /* --- @mp_read@ --- *
  *
  * bizarre syntax.
  */
 
-mp *mp_read(mp *m, int radix, const mptext_ops *ops, void *p)
+static int char_digit(int ch, int radix)
 {
-  int ch;                              /* Current char being considered */
-  unsigned f = 0;                      /* Flags about the current number */
-  int r;                               /* Radix to switch over to */
-  mpw rd;                              /* Radix as an @mp@ digit */
-  mp rr;                               /* The @mp@ for the radix */
-  unsigned nf = m ? m->f & MP_BURN : 0;        /* New @mp@ flags */
-
-  /* --- Stacks --- */
-
-  mp *pow[DEPTH];                      /* List of powers */
-  unsigned pows;                       /* Next index to fill */
-  struct { unsigned i; mp *m; } s[DEPTH]; /* Main stack */
-  unsigned sp;                         /* Current stack pointer */
-
-  /* --- Flags --- */
-
-#define f_neg 1u
-#define f_ok 2u
-#define f_start 4u
-
-  /* --- Initialize the stacks --- */
-
-  mp_build(&rr, &rd, &rd + 1);
-  pow[0] = &rr;
-  pows = 1;
-
-  sp = 0;
-
-  /* --- Initialize the destination number --- */
-
-  if (m)
-    MP_DROP(m);
-
-  /* --- Read an initial character --- */
-
-  ch = ops->get(p);
-  if (radix >= 0) {
-    while (isspace(ch))
-      ch = ops->get(p);
-  }
-
-  /* --- Handle an initial sign --- */
-
-  if (radix >= 0 && (ch == '-' || ch == '+')) {
-    if (ch == '-')
-      f |= f_neg;
-    do ch = ops->get(p); while isspace(ch);
-  }
-
-  /* --- If the radix is zero, look for leading zeros --- */
-
-  if (radix > 0) {
-    assert(((void)"ascii radix must be <= 62", radix <= 62));
-    rd = radix;
-    r = -1;
-  } else if (radix < 0) {
-    rd = -radix;
-    assert(((void)"binary radix must fit in a byte", rd <= UCHAR_MAX));
-    r = -1;
-  } else if (ch != '0') {
-    rd = 10;
-    r = 0;
-  } else {
-    ch = ops->get(p);
-    switch (ch) {
-      case 'x':
-       rd = 16;
-       goto prefix;
-      case 'o':
-       rd = 8;
-       goto prefix;
-      case 'b':
-       rd = 2;
-       goto prefix;
-      prefix:
-       ch = ops->get(p);
-       break;
-      default:
-       rd = 8;
-       f |= f_ok;
-    }
-    r = -1;
-  }
-
-  /* --- Use fast algorithm for binary radix --- *
-   *
-   * This is the restart point after having parsed a radix number from the
-   * input.  We check whether the radix is binary, and if so use a fast
-   * algorithm which just stacks the bits up in the right order.
-   */
+  int r = radix < 0 ? -radix : radix;
+  int d;
+
+  if (ch < 0) return (-1);
+  if (radix < 0) d = ch;
+  else if ('0' <= ch && ch <= '9') d = ch - '0';
+  else if ('a' <= ch && ch <= 'z') d = ch - 'a' + 10;
+  else if ('A' <= ch && ch <= 'Z') d = ch - 'A' + (radix > 36 ? 36 : 10);
+  else return (-1);
+  if (d >= r) return (-1);
+  return (d);
+}
 
-restart:
-  switch (rd) {
-    unsigned bit;
-
-    case   2: bit = 1; goto bin;
-    case   4: bit = 2; goto bin;
-    case   8: bit = 3; goto bin;
-    case  16: bit = 4; goto bin;
-    case  32: bit = 5; goto bin;
-    case  64: bit = 6; goto bin;
-    case 128: bit = 7; goto bin;
-    default:
-      break;
+static mp *read_binary(int radix, unsigned bit, unsigned nf,
+                      const mptext_ops *ops, void *p)
+{
+  mpw a = 0;
+  unsigned b = MPW_BITS;
+  int any = 0, nz = 0;
+  int ch, d;
+  size_t len, n;
+  mpw *v;
+  mp *m;
 
   /* --- The fast binary algorithm --- *
    *
@@ -212,250 +131,299 @@ restart:
    * bit-shift when we know where the end of the number is.
    */
 
-  bin: {
-    mpw a = 0;
-    unsigned b = MPW_BITS;
-    size_t len, n;
-    mpw *v;
-
-    m = mp_dest(MP_NEW, 1, nf);
-    len = n = m->sz;
-    n = len;
-    v = m->v + n;
-    for (;; ch = ops->get(p)) {
-      unsigned x;
+  m = mp_dest(MP_NEW, 1, nf);
+  len = n = m->sz;
+  n = len;
+  v = m->v + n;
 
-      if (ch < 0)
-       break;
+  for (;;) {
+    ch = ops->get(p);
+    if ((d = char_digit(ch, radix)) < 0) break;
 
-      /* --- Check that the character is a digit and in range --- */
+    /* --- Ignore leading zeroes, but notice that the number is valid --- */
 
-      if (radix < 0)
-       x = ch % rd;
-      else {
-       if (!isalnum(ch))
-         break;
-       if (ch >= '0' && ch <= '9')
-         x = ch - '0';
-       else {
-         if (rd <= 36)
-           ch = tolower(ch);
-         if (ch >= 'a' && ch <= 'z')   /* ASCII dependent! */
-           x = ch - 'a' + 10;
-         else if (ch >= 'A' && ch <= 'Z')
-           x = ch - 'A' + 36;
-         else
-           break;
-       }
-      }
-      if (x >= rd)
-       break;
-
-      /* --- Feed the digit into the accumulator --- */
-
-      f |= f_ok;
-      if (!x && !(f & f_start))
-       continue;
-      f |= f_start;
-      if (b > bit) {
-       b -= bit;
-       a |= MPW(x) << b;
-      } else {
-       a |= MPW(x) >> (bit - b);
-       b += MPW_BITS - bit;
-       *--v = MPW(a);
-       n--;
-       if (!n) {
-         n = len;
-         len <<= 1;
-         v = mpalloc(m->a, len);
-         memcpy(v + n, m->v, MPWS(n));
-         mpfree(m->a, m->v);
-         m->v = v;
-         v = m->v + n;
-       }
-       a = (b < MPW_BITS) ? MPW(x) << b : 0;
-      }
-    }
+    any = 1;
+    if (!d && !nz) continue;
+    nz = 1;
 
-    /* --- Finish up --- */
+    /* --- Feed the digit into the accumulator --- */
 
-    if (!(f & f_ok)) {
-      mp_drop(m);
-      m = 0;
+    if (b > bit) {
+      b -= bit;
+      a |= MPW(d) << b;
     } else {
-      *--v = MPW(a);
-      n--;
-      m->sz = len;
-      m->vl = m->v + len;
-      m->f &= ~MP_UNDEF;
-      m = mp_lsr(m, m, (unsigned long)n * MPW_BITS + b);
+      a |= MPW(d) >> (bit - b);
+      b += MPW_BITS - bit;
+      *--v = MPW(a); n--;
+      if (!n) {
+       n = len; len <<= 1;
+       v = mpalloc(m->a, len);
+       memcpy(v + n, m->v, MPWS(n));
+       mpfree(m->a, m->v);
+       m->v = v; v = m->v + n;
+      }
+      a = (b < MPW_BITS) ? MPW(d) << b : 0;
     }
-    ops->unget(ch, p);
-    goto done;
-  }}
+  }
 
-  /* --- Time to start --- */
+  /* --- Finish up --- */
 
-  for (;; ch = ops->get(p)) {
-    unsigned x;
+  ops->unget(ch, p);
+  if (!any) { mp_drop(m); return (0); }
 
-    if (ch < 0)
-      break;
+  *--v = MPW(a); n--;
+  m->sz = len;
+  m->vl = m->v + len;
+  m->f &= ~MP_UNDEF;
+  m = mp_lsr(m, m, (unsigned long)n * MPW_BITS + b);
 
-    /* --- An underscore indicates a numbered base --- */
+  return (m);
+}
 
-    if (ch == '_' && r > 0 && r <= 62) {
-      unsigned i;
+struct readstate {
 
-      /* --- Clear out the stacks --- */
+  /* --- State for the general-base reader --- *
+   *
+   * There are two arrays.  The @pow@ array is set so that @pow[i]@ contains
+   * %$R^{2^i}$% for @i < pows@.  The stack @s@ contains partial results:
+   * each entry contains a value @m@ corresponding to %$2^i$% digits.
+   * Inductively, an empty stack represents zero; if a stack represents %$x$%
+   * then pushing a new entry on the top causes the stack to represent
+   * %$R^{2^i} x + m$%.
+   *
+   * It is an invariant that each entry has a strictly smaller @i@ than the
+   * items beneath it.  This is achieved by coaslescing entries at the top if
+   * they have equal %$i$% values: if the top items are %$(m, i)$%, and
+   * %$(M', i)$%, and the rest of the stack represents the integer %$x$%,
+   * then %$R^{2^i} (R^{2^i} x + M) + m = R^{2^{i+1}} x + (R^{2^i} M + m)$%,
+   * so we replace the top two items by %$((R^{2^i} M + m), i + 1)$%, and
+   * repeat if necessary.
+   */
 
-      for (i = 1; i < pows; i++)
-       MP_DROP(pow[i]);
-      pows = 1;
-      for (i = 0; i < sp; i++)
-       MP_DROP(s[i].m);
-      sp = 0;
+  unsigned pows, sp;
+  struct { unsigned i; mp *m; } s[DEPTH];
+  mp *pow[DEPTH];
+};
 
-      /* --- Restart the search --- */
+static void ensure_power(struct readstate *rs)
+{
+  /* --- Make sure we have the necessary %$R^{2^i}$% computed --- */
 
-      rd = r;
-      r = -1;
-      f &= ~f_ok;
-      ch = ops->get(p);
-      goto restart;
-    }
+  if (rs->s[rs->sp].i >= rs->pows) {
+    assert(rs->pows < DEPTH);
+    rs->pow[rs->pows] = mp_sqr(MP_NEW, rs->pow[rs->pows - 1]);
+    rs->pows++;
+  }
+}
 
-    /* --- Check that the character is a digit and in range --- */
+static void read_digit(struct readstate *rs, unsigned nf, int d)
+{
+  mp *m = mp_new(1, nf);
+  m->v[0] = d;
 
-    if (radix < 0)
-      x = ch % rd;
-    else {
-      if (!isalnum(ch))
-       break;
-      if (ch >= '0' && ch <= '9')
-       x = ch - '0';
-      else {
-       if (rd <= 36)
-         ch = tolower(ch);
-       if (ch >= 'a' && ch <= 'z')     /* ASCII dependent! */
-         x = ch - 'a' + 10;
-       else if (ch >= 'A' && ch <= 'Z')
-         x = ch - 'A' + 36;
-       else
-         break;
-      }
-    }
+  /* --- Put the new digit on top --- */
 
-    /* --- Sort out what to do with the character --- */
+  assert(rs->sp < DEPTH);
+  rs->s[rs->sp].m = m;
+  rs->s[rs->sp].i = 0;
 
-    if (x >= 10 && r >= 0)
-      r = -1;
-    if (x >= rd)
-      break;
+  /* --- Restore the stack invariant --- */
 
-    if (r >= 0)
-      r = r * 10 + x;
+  while (rs->sp && rs->s[rs->sp - 1].i <= rs->s[rs->sp].i) {
+    assert(rs->sp > 0);
+    ensure_power(rs);
+    rs->sp--;
 
-    /* --- Stick the character on the end of my integer --- */
+    m = rs->s[rs->sp].m;
+    m = mp_mul(m, m, rs->pow[rs->s[rs->sp + 1].i]);
+    m = mp_add(m, m, rs->s[rs->sp + 1].m);
+    MP_DROP(rs->s[rs->sp + 1].m);
+    rs->s[rs->sp].m = m;
+    rs->s[rs->sp].i++;
+  }
 
-    assert(((void)"Number is too unimaginably huge", sp < DEPTH));
-    s[sp].m = m = mp_new(1, nf);
-    m->v[0] = x;
-    s[sp].i = 0;
+  /* --- Leave the stack pointer at an empty item --- */
 
-    /* --- Now grind through the stack --- */
+  rs->sp++;
+}
 
-    while (sp > 0 && s[sp - 1].i == s[sp].i) {
+static mp *read_general(int radix, unsigned t, unsigned nf,
+                       const mptext_ops *ops, void *p)
+{
+  struct readstate rs;
+  unsigned char v[4];
+  unsigned i;
+  mpw r;
+  int any = 0;
+  int ch, d;
+  mp rr;
+  mp *m, *z, *n;
+
+  /* --- Prepare the stack --- */
+
+  r = radix < 0 ? -radix : radix;
+  mp_build(&rr, &r, &r + 1);
+  rs.pow[0] = &rr;
+  rs.pows = 1;
+  rs.sp = 0;
+
+  /* --- If we've partially parsed some input then feed it in --- *
+   *
+   * Unfortunately, what we've got is backwards.  Fortunately there's a
+   * fairly tight upper bound on how many digits @t@ might be, since we
+   * aborted that loop once it got too large.
+   */
 
-      /* --- Combine the top two items --- */
+  if (t) {
+    i = 0;
+    while (t) { assert(i < sizeof(v)); v[i++] = t%r; t /= r; }
+    while (i) read_digit(&rs, nf, v[--i]);
+    any = 1;
+  }
 
-      sp--;
-      m = s[sp].m;
-      m = mp_mul(m, m, pow[s[sp].i]);
-      m = mp_add(m, m, s[sp + 1].m);
-      s[sp].m = m;
-      MP_DROP(s[sp + 1].m);
-      s[sp].i++;
+  /* --- Read more stuff --- */
 
-      /* --- Make a new radix power if necessary --- */
+  for (;;) {
+    ch = ops->get(p);
+    if ((d = char_digit(ch, radix)) < 0) break;
+    read_digit(&rs, nf, d); any = 1;
+  }
+  ops->unget(ch, p);
 
-      if (s[sp].i >= pows) {
-       assert(((void)"Number is too unimaginably huge", pows < DEPTH));
-       pow[pows] = mp_sqr(MP_NEW, pow[pows - 1]);
-       pows++;
-      }
-    }
-    f |= f_ok;
-    sp++;
+  /* --- Stitch all of the numbers together --- *
+   *
+   * This is not the same code as @read_digit@.  In particular, here we must
+   * cope with the partial result being some inconvenient power of %$R$%,
+   * rather than %$R^{2^i}$%.
+   */
+
+  if (!any) return (0);
+  m = MP_ZERO; z = MP_ONE;
+  while (rs.sp) {
+    rs.sp--;
+    ensure_power(&rs);
+    n = rs.s[rs.sp].m;
+    n = mp_mul(n, n, z);
+    m = mp_add(m, m, n);
+    z = mp_mul(z, z, rs.pow[rs.s[rs.sp].i]);
+    MP_DROP(n);
   }
+  for (i = 0; i < rs.pows; i++) MP_DROP(rs.pow[i]);
+  MP_DROP(z);
+  return (m);
+}
 
-  ops->unget(ch, p);
+mp *mp_read(mp *m, int radix, const mptext_ops *ops, void *p)
+{
+  unsigned t = 0;
+  unsigned nf = 0;
+  int ch, d, rd;
+
+  unsigned f = 0;
+#define f_neg 1u
+#define f_ok 2u
+
+  /* --- We don't actually need a destination so throw it away --- *
+   *
+   * But note the flags before we lose it entirely.
+   */
 
-  /* --- If we're done, compute the rest of the number --- */
+  if (m) {
+    nf = m->f & MP_BURN;
+    MP_DROP(m);
+  }
 
-  if (f & f_ok) {
-    if (!sp)
-      return (MP_ZERO);
-    else {
-      mp *z = MP_ONE;
-      sp--;
+  /* --- Maintain a lookahead character --- */
 
-      while (sp > 0) {
+  ch = ops->get(p);
 
-       /* --- Combine the top two items --- */
+  /* --- If we're reading text, skip leading space, and maybe a sign --- */
 
-       sp--;
-       m = s[sp].m;
-       z = mp_mul(z, z, pow[s[sp + 1].i]);
-       m = mp_mul(m, m, z);
-       m = mp_add(m, m, s[sp + 1].m);
-       s[sp].m = m;
-       MP_DROP(s[sp + 1].m);
+  if (radix >= 0) {
+    while (isspace(ch)) ch = ops->get(p);
+    switch (ch) {
+      case '-': f |= f_neg; /* and on */
+      case '+': do ch = ops->get(p); while (isspace(ch));
+    }
+  }
 
-       /* --- Make a new radix power if necessary --- */
+  /* --- If we don't have a fixed radix, then parse one from the input --- *
+   *
+   * This is moderately easy if the input starts with `0x' or similar.  If it
+   * starts with `0' and something else, then it might be octal, or just a
+   * plain old zero.  Finally, it might start with a leading `NN_', in which
+   * case we carefully collect the decimal number until we're sure it's
+   * either a radix prefix (in which case we accept it and start over) or it
+   * isn't (in which case it's actually the start of a large number we need
+   * to read).
+   */
 
-       if (s[sp].i >= pows) {
-         assert(((void)"Number is too unimaginably huge", pows < DEPTH));
-         pow[pows] = mp_sqr(MP_NEW, pow[pows - 1]);
-         pows++;
-       }
+  if (radix == 0) {
+    if (ch == '0') {
+      ch = ops->get(p);
+      switch (ch) {
+       case 'x': case 'X': radix = 16; goto fetch;
+       case 'o': case 'O': radix = 8; goto fetch;
+       case 'b': case 'B': radix = 2; goto fetch;
+       fetch: ch = ops->get(p); break;
+       default: radix = 8; f |= f_ok; break;
+      }
+    } else {
+      if ((d = char_digit(ch, 10)) < 0) { ops->unget(ch, p); return (0); }
+      for (;;) {
+       t = 10*t + d;
+       ch = ops->get(p);
+       if (t > 52) break;
+       if ((d = char_digit(ch, 10)) < 0) break;
+      }
+      if (ch != '_' || t > 52) radix = 10;
+      else {
+       radix = t; t = 0;
+       ch = ops->get(p);
       }
-      MP_DROP(z);
-      m = s[0].m;
     }
-  } else {
-    unsigned i;
-    for (i = 0; i < sp; i++)
-      MP_DROP(s[i].m);
   }
 
-  /* --- Clear the radix power list --- */
+  /* --- We're now ready to dispatch to the correct handler --- */
 
-  {
-    unsigned i;
-    for (i = 1; i < pows; i++)
-      MP_DROP(pow[i]);
+  rd = radix < 0 ? -radix : radix;
+  ops->unget(ch, p);
+  switch (rd) {
+    case   2: m = read_binary(radix,  1, nf, ops, p); break;
+    case   4: m = read_binary(radix,  2, nf, ops, p); break;
+    case   8: m = read_binary(radix,  3, nf, ops, p); break;
+    case  16: m = read_binary(radix,  4, nf, ops, p); break;
+    case  32: m = read_binary(radix,  5, nf, ops, p); break;
+    case  64: m = read_binary(radix,  6, nf, ops, p); break;
+    case 128: m = read_binary(radix,  7, nf, ops, p); break;
+    default:  m = read_general(radix, t, nf, ops, p); break;
   }
 
-  /* --- Bail out if the number was bad --- */
+  /* --- That didn't work --- *
+   *
+   * If we've already read something then return that.  Otherwise it's an
+   * error.
+   */
 
-done:
-  if (!(f & f_ok))
-    return (0);
+  if (!m) {
+    if (f & f_ok) return (MP_ZERO);
+    else return (0);
+  }
 
-  /* --- Set the sign and return --- */
+  /* --- Negate the result if we should do that --- */
+
+  if (f & f_neg) m = mp_neg(m, m);
+
+  /* --- And we're all done --- */
 
-  if (f & f_neg)
-    m->f |= MP_NEG;
-  MP_SHRINK(m);
   return (m);
 
-#undef f_start
 #undef f_neg
 #undef f_ok
 }
 
+/*----- Output ------------------------------------------------------------*/
+
 /* --- @mp_write@ --- *
  *
  * Arguments:  @mp *m@ = pointer to a multi-precision integer
@@ -468,6 +436,14 @@ done:
  * Use:                Writes a large integer in textual form.
  */
 
+static int digit_char(int d, int radix)
+{
+  if (radix < 0) return (d);
+  else if (d < 10) return (d + '0');
+  else if (d < 26) return (d - 10 + 'a');
+  else return (d - 36 + 'A');
+}
+
 /* --- Simple case --- *
  *
  * Use a fixed-sized buffer and single-precision arithmetic to pick off
@@ -477,35 +453,23 @@ done:
  * enough real digits.
  */
 
-static int simple(mpw n, int radix, unsigned z,
-                 const mptext_ops *ops, void *p)
+static int write_simple(mpw n, int radix, unsigned z,
+                       const mptext_ops *ops, void *p)
 {
   int rc = 0;
   char buf[64];
   unsigned i = sizeof(buf);
   int rd = radix > 0 ? radix : -radix;
+  mpw x;
 
   do {
-    int ch;
-    mpw x;
-
-    x = n % rd;
-    n /= rd;
-    if (radix < 0)
-      ch = x;
-    else if (x < 10)
-      ch = '0' + x;
-    else if (x < 36)                   /* Ascii specific */
-      ch = 'a' + x - 10;
-    else
-      ch = 'A' + x - 36;
-    buf[--i] = ch;
-    if (z)
-      z--;
+    x = n % rd; n /= rd;
+    buf[--i] = digit_char(x, radix);
+    if (z) z--;
   } while (i && n);
 
   if (n)
-    rc = simple(n, radix, z, ops, p);
+    rc = write_simple(n, radix, z, ops, p);
   else {
     char zbuf[32];
     memset(zbuf, (radix < 0) ? 0 : '0', sizeof(zbuf));
@@ -513,11 +477,9 @@ static int simple(mpw n, int radix, unsigned z,
       rc = ops->put(zbuf, sizeof(zbuf), p);
       z -= sizeof(zbuf);
     }
-    if (!rc && z)
-      rc = ops->put(zbuf, z, p);
+    if (!rc && z) rc = ops->put(zbuf, z, p);
   }
-  if (!rc)
-    rc = ops->put(buf + i, sizeof(buf) - i, p);
+  if (!rc) rc = ops->put(buf + i, sizeof(buf) - i, p);
   BURN(buf);
   return (rc);
 }
@@ -530,29 +492,26 @@ static int simple(mpw n, int radix, unsigned z,
  * leading zeroes on the remainder part, because they're deeply significant.
  */
 
-static int complicated(mp *m, int radix, mp **pr, unsigned i, unsigned z,
-                      const mptext_ops *ops, void *p)
+static int write_complicated(mp *m, int radix, mp **pr,
+                            unsigned i, unsigned z,
+                            const mptext_ops *ops, void *p)
 {
   int rc = 0;
   mp *q = MP_NEW;
   unsigned d = 1 << i;
 
   if (MP_LEN(m) < 2)
-    return (simple(MP_LEN(m) ? m->v[0] : 0, radix, z, ops, p));
+    return (write_simple(MP_LEN(m) ? m->v[0] : 0, radix, z, ops, p));
 
   assert(i);
   mp_div(&q, &m, m, pr[i]);
-  if (MP_ZEROP(q))
-    d = z;
+  if (MP_ZEROP(q)) d = z;
   else {
-    if (z > d)
-      z -= d;
-    else
-      z = 0;
-    rc = complicated(q, radix, pr, i - 1, z, ops, p);
+    if (z > d) z -= d;
+    else z = 0;
+    rc = write_complicated(q, radix, pr, i - 1, z, ops, p);
   }
-  if (!rc)
-    rc = complicated(m, radix, pr, i - 1, d, ops, p);
+  if (!rc) rc = write_complicated(m, radix, pr, i - 1, d, ops, p);
   mp_drop(q);
   return (rc);
 }
@@ -562,7 +521,8 @@ static int complicated(mp *m, int radix, mp **pr, unsigned i, unsigned z,
  * Special case for binary output.  Goes much faster.
  */
 
-static int binary(mp *m, int bit, int radix, const mptext_ops *ops, void *p)
+static int write_binary(mp *m, int bit, int radix,
+                       const mptext_ops *ops, void *p)
 {
   mpw *v;
   mpw a;
@@ -573,15 +533,13 @@ static int binary(mp *m, int bit, int radix, const mptext_ops *ops, void *p)
   unsigned f = 0;
   char buf[8], *q;
   unsigned x;
-  int ch;
 
 #define f_out 1u
 
   /* --- Work out where to start --- */
 
   n = mp_bits(m);
-  if (n % bit)
-    n += bit - (n % bit);
+  if (n % bit) n += bit - (n % bit);
   b = n % MPW_BITS;
   n /= MPW_BITS;
 
@@ -604,43 +562,23 @@ static int binary(mp *m, int bit, int radix, const mptext_ops *ops, void *p)
     } else {
       x = a << (bit - b);
       b += MPW_BITS - bit;
-      if (v == m->v)
-       break;
+      if (v == m->v) break;
       a = *--v;
-      if (b < MPW_BITS)
-       x |= a >> b;
+      if (b < MPW_BITS) x |= a >> b;
     }
     x &= mask;
-    if (!x && !(f & f_out))
-      continue;
-
-    if (radix < 0)
-      ch = x;
-    else if (x < 10)
-      ch = '0' + x;
-    else if (x < 36)
-      ch = 'a' + x - 10;               /* Ascii specific */
-    else
-      ch = 'A' + x - 36;
-    *q++ = ch;
+    if (!x && !(f & f_out)) continue;
+
+    *q++ = digit_char(x, radix);
     if (q >= buf + sizeof(buf)) {
-      if ((rc = ops->put(buf, sizeof(buf), p)) != 0)
-       goto done;
+      if ((rc = ops->put(buf, sizeof(buf), p)) != 0) goto done;
       q = buf;
     }
     f |= f_out;
   }
 
   x &= mask;
-  if (radix < 0)
-    ch = x;
-  else if (x < 10)
-    ch = '0' + x;
-  else if (x < 36)
-    ch = 'a' + x - 10;                 /* Ascii specific */
-  else
-    ch = 'A' + x - 36;
-  *q++ = ch;
+  *q++ = digit_char(x, radix);
   rc = ops->put(buf, q - buf, p);
 
 done:
@@ -655,6 +593,10 @@ done:
 int mp_write(mp *m, int radix, const mptext_ops *ops, void *p)
 {
   int rc;
+  mp *pr[DEPTH];
+  size_t target;
+  unsigned i = 0;
+  mp *z;
 
   if (MP_EQ(m, MP_ZERO))
     return (ops->put(radix > 0 ? "0" : "\0", 1, p));
@@ -677,27 +619,26 @@ int mp_write(mp *m, int radix, const mptext_ops *ops, void *p)
 
   if (MP_NEGP(m)) {
     assert(radix > 0);
-    if (ops->put("-", 1, p))
-      return (EOF);
+    if (ops->put("-", 1, p)) return (EOF);
     m->f &= ~MP_NEG;
   }
 
   /* --- Handle binary radix --- */
 
   switch (radix) {
-    case   2: case   -2: return (binary(m, 1, radix, ops, p));
-    case   4: case   -4: return (binary(m, 2, radix, ops, p));
-    case   8: case   -8: return (binary(m, 3, radix, ops, p));
-    case  16: case  -16: return (binary(m, 4, radix, ops, p));
-    case  32: case  -32: return (binary(m, 5, radix, ops, p));
-             case  -64: return (binary(m, 6, radix, ops, p));
-             case -128: return (binary(m, 7, radix, ops, p));
+    case   2: case   -2: return (write_binary(m, 1, radix, ops, p));
+    case   4: case   -4: return (write_binary(m, 2, radix, ops, p));
+    case   8: case   -8: return (write_binary(m, 3, radix, ops, p));
+    case  16: case  -16: return (write_binary(m, 4, radix, ops, p));
+    case  32: case  -32: return (write_binary(m, 5, radix, ops, p));
+             case  -64: return (write_binary(m, 6, radix, ops, p));
+             case -128: return (write_binary(m, 7, radix, ops, p));
   }
 
   /* --- If the number is small, do it the easy way --- */
 
   if (MP_LEN(m) < 2)
-    rc = simple(MP_LEN(m) ? m->v[0] : 0, radix, 0, ops, p);
+    rc = write_simple(MP_LEN(m) ? m->v[0] : 0, radix, 0, ops, p);
 
   /* --- Use a clever algorithm --- *
    *
@@ -709,10 +650,8 @@ int mp_write(mp *m, int radix, const mptext_ops *ops, void *p)
    */
 
   else {
-    mp *pr[DEPTH];
-    size_t target = (MP_LEN(m) + 1) / 2;
-    unsigned i = 0;
-    mp *z = mp_new(1, 0);
+    target = (MP_LEN(m) + 1) / 2;
+    z = mp_new(1, 0);
 
     /* --- Set up the exponent table --- */
 
@@ -721,19 +660,17 @@ int mp_write(mp *m, int radix, const mptext_ops *ops, void *p)
     for (;;) {
       assert(((void)"Number is too unimaginably huge", i < DEPTH));
       pr[i++] = z;
-      if (MP_LEN(z) > target)
-       break;
+      if (MP_LEN(z) > target) break;
       z = mp_sqr(MP_NEW, z);
     }
 
     /* --- Write out the answer --- */
 
-    rc = complicated(m, radix, pr, i - 1, 0, ops, p);
+    rc = write_complicated(m, radix, pr, i - 1, 0, ops, p);
 
     /* --- Tidy away the array --- */
 
-    while (i > 0)
-      mp_drop(pr[--i]);
+    while (i > 0) mp_drop(pr[--i]);
   }
 
   /* --- Tidying up code --- */
diff --git a/math/mptypes.c b/math/mptypes.c
deleted file mode 100644 (file)
index 807ffee..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-/* -*-c-*-
- *
- * Generate `mptypes.h' header file for current architecture
- *
- * (c) 1999 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.
- */
-
-/*----- Header files ------------------------------------------------------*/
-
-#define _GNU_SOURCE
-#include "config.h"
-
-#include <stdio.h>
-#include <limits.h>
-#if __STDC_VERSION__ >= 199900l
-#  include <stdint.h>
-#  include <inttypes.h>
-#endif
-
-/*----- Data types --------------------------------------------------------*/
-
-/* --- Hack for GCC --- *
- *
- * WG14 in their infinite wisdom decided not to use the GCC constant name.
- */
-
-#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 91)
-#  define EXT __extension__
-#else
-#  define EXT
-#endif
-
-#if defined(ULONG_LONG_MAX) && !defined(ULLONG_MAX)
-#  define ULLONG_MAX ULONG_LONG_MAX
-#endif
-
-/* --- Choose the largest integer type --- */
-
-#if defined(UINTMAX_MAX) && defined(PRIuMAX)
-  typedef uintmax_t umax;
-# define P_UMAX PRIuMAX
-#elif defined(ULLONG_MAX)
-  EXT typedef unsigned long long umax;
-# define P_UMAX "llu"
-#else
-  typedef unsigned long umax;
-# define P_UMAX "lu"
-#endif
-
-/* --- Table of interesting types --- *
- *
- * These are in preference order.
- */
-
-enum {
-  f_stdint = 1u,
-  f_ext = 2u
-};
-
-struct itype {
-  const char *name;
-  const char *suff;
-  umax max;
-  unsigned flags;
-  unsigned bits;
-} tytab[] = {
-  { "unsigned int",            "u",    UINT_MAX,               0 },
-  { "unsigned short",          "u",    USHRT_MAX,              0 },
-  { "unsigned long",           "ul",   ULONG_MAX,              0 },
-#ifdef ULLONG_MAX
-  { "unsigned long long",      "ull",  EXT ULLONG_MAX,         f_ext },
-#endif
-#ifdef UINTMAX_MAX
-  { "uintmax_t",               "u",    UINTMAX_MAX,            f_stdint },
-#endif
-  { 0,                         0 },
-};
-
-typedef struct itype itype;
-
-/*----- Main code ---------------------------------------------------------*/
-
-int main(int argc, char *argv[])
-{
-  itype *i;
-  itype *largest, *mpw, *mpd;
-  const static char *extstr = "CATACOMB_MPTYPES_EXTENSION ";
-  unsigned p2;
-
-  /* --- Find the bitcounts --- */
-
-  for (i = tytab; i->name; i++) {
-    unsigned bits;
-    umax u = i->max;
-    for (bits = 0; u; bits++)
-      u >>= 1;
-    i->bits = bits;
-  }
-
-  /* --- Now try to find the interesting types --- *
-   *
-   * The first thing to do is to find the largest type.  Then I find the
-   * `best' type which is less than half that size, and then the `best' type
-   * which is twice as big as that one.
-   */
-
-#if defined(FORCE_MPW_CUSSID)
-  largest = mpd = &tytab[3];
-  mpw = &tytab[2];
-  mpw->bits = 19; mpw->max = 0x7ffff;
-  mpd->bits = 38; mpd->max = 0x3fffffffffll;
-#elif defined(FORCE_MPW_SHORT)
-  largest = mpd = &tytab[2];
-  mpw = &tytab[1];
-  mpw->bits = 16; mpw->max = 0xffff;
-  mpd->bits = 32; mpd->max = 0xffffffff;
-#else
-  largest = tytab;
-  for (i = tytab; i->name; i++) {
-    if (i->bits > largest->bits)
-      largest = i;
-  }
-  for (mpw = 0, i = tytab; i->name; i++) {
-    if (i->bits * 2 <= largest->bits && (!mpw || i->bits > mpw->bits))
-      mpw = i;
-  }
-  if (!mpw)
-    mpw = tytab;
-  for (mpd = 0, i = tytab; i->name; i++) {
-    if (i->bits >= mpw->bits * 2 && (!mpd || i->bits < mpd->bits))
-      mpd = i;
-  }
-  if (!mpd) {
-    static itype w, d;
-    d = w = *mpw;
-    w.bits /= 2; w.max = ~(~((umax)0) << w.bits);
-    d.bits = w.bits * 2; d.max = ~(~((umax)0) << d.bits);
-    mpw = &w; mpd = &d;
-  }
-#endif
-  for (p2 = 1; (p2 << 1) < mpw->bits; p2 <<= 1);
-
-  /* --- Output time --- */
-
-  puts("\
-/* -*-c-*-\n\
- *\n\
- * mptypes.h [generated]\n\
- */\n\
-\n\
-#ifndef CATACOMB_MPTYPES_H\n\
-#define CATACOMB_MPTYPES_H\n\
-");
-  if ((mpd->flags | mpw->flags) & f_stdint) {
-    puts("\
-#if __STDC_VERSION__ >= 199900l\n\
-#  include <stdint.h>\n\
-#endif\n\
-");
-  }
-  if ((mpd->flags | mpw->flags) & f_ext) {
-    printf("\
-#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 91)\n\
-#  define %s __extension__\n\
-#else\n\
-#  define %s\n\
-#endif\n\
-", extstr, extstr);
-  }
-  printf("\
-%stypedef %s mpw;\n\
-#define MPW_BITS %u\n\
-#define MPW_P2 %u\n\
-#define MPW_MAX %s%" P_UMAX "%s\n\
-\n\
-%stypedef %s mpd;\n\
-#define MPD_BITS %u\n\
-#define MPD_MAX %s%" P_UMAX "%s\n\
-\n\
-#endif\n\
-",
-  mpw->flags & f_ext ? extstr : "", mpw->name,
-  mpw->bits, p2,
-  mpw->flags & f_ext ? extstr : "", mpw->max, mpw->suff,
-  mpd->flags & f_ext ? extstr : "", mpd->name,
-  mpd->bits,
-  mpd->flags & f_ext ? extstr : "", mpd->max, mpd->suff);
-
-  return (0);
-}
-
-/*----- That's all, folks -------------------------------------------------*/
index 54be12a..7fb4c7b 100644 (file)
@@ -28,6 +28,7 @@ include $(top_srcdir)/vars.am
 
 noinst_LTLIBRARIES      = libmisc.la
 libmisc_la_SOURCES      =
+nodist_libmisc_la_SOURCES =
 
 TEST_LIBS               = libmisc.la
 
@@ -37,21 +38,22 @@ TEST_LIBS            = libmisc.la
 ## Efficient sharing over GF(2^8).
 pkginclude_HEADERS     += gfshare.h
 libmisc_la_SOURCES     += gfshare.c
-libmisc_la_SOURCES     += $(precomp)/gfshare-tab.c
-PRECOMPS               += $(precomp)/gfshare-tab.c
+nodist_libmisc_la_SOURCES += ../precomp/misc/gfshare-tab.c
+PRECOMPS               += $(precomp)/misc/gfshare-tab.c
 PRECOMP_PROGS          += gfshare-mktab
 if !CROSS_COMPILING
-$(precomp)/gfshare-tab.c:
-       $(AM_V_at)$(MKDIR_P) $(precomp)
-       $(AM_V_at)$(MAKE) gfshare-mktab$e
-       $(AM_V_GEN)./gfshare-mktab >$(precomp)/gfshare-tab.c.new && \
-               mv $(precomp)/gfshare-tab.c.new $(precomp)/gfshare-tab.c
+$(precomp)/misc/gfshare-tab.c:
+       $(AM_V_at)$(MKDIR_P) $(precomp)/misc
+       $(AM_V_at)$(MAKE) gfshare-mktab$(EXEEXT)
+       $(AM_V_GEN)./gfshare-mktab >$(precomp)/misc/gfshare-tab.c.new && \
+               mv $(precomp)/misc/gfshare-tab.c.new \
+                       $(precomp)/misc/gfshare-tab.c
 endif
-TESTS                  += gfshare.$t
+TESTS                  += gfshare.t$(EXEEXT)
 
 ## Number-theoretic sharing over GF(p).
 pkginclude_HEADERS     += share.h
 libmisc_la_SOURCES     += share.c
-TESTS                  += share.$t
+TESTS                  += share.t$(EXEEXT)
 
 ###----- That's all, folks --------------------------------------------------
index d919edf..b21d6af 100644 (file)
@@ -39,9 +39,9 @@ pkginclude_HEADERS    += bbs.h
 libpub_la_SOURCES      += bbs-fetch.c
 libpub_la_SOURCES      += bbs-gen.c
 libpub_la_SOURCES      += bbs-jump.c
-TESTS                  += bbs-jump.$t
+TESTS                  += bbs-jump.t$(EXEEXT)
 libpub_la_SOURCES      += bbs-rand.c
-TESTS                  += bbs-rand.$t
+TESTS                  += bbs-rand.t$(EXEEXT)
 EXTRA_DIST             += t/bbs
 
 ## Plain Diffie--Hellman, in Schorr groups.
@@ -52,30 +52,30 @@ libpub_la_SOURCES   += dh-gen.c
 libpub_la_SOURCES      += dh-kcdsa.c
 libpub_la_SOURCES      += dh-limlee.c
 libpub_la_SOURCES      += dh-param.c
-TESTS                  += dh-param.$t
+TESTS                  += dh-param.t$(EXEEXT)
 
 ## The National Security Agency's Digital Signature Algorithm.
 pkginclude_HEADERS     += dsa.h
 libpub_la_SOURCES      += dsa-gen.c
-TESTS                  += dsa-gen.$t
+TESTS                  += dsa-gen.t$(EXEEXT)
 libpub_la_SOURCES      += dsa-misc.c
 libpub_la_SOURCES      += dsa-sign.c
-TESTS                  += dsa-sign.$t
+TESTS                  += dsa-sign.t$(EXEEXT)
 libpub_la_SOURCES      += dsa-verify.c
-TESTS                  += dsa-verify.$t
+TESTS                  += dsa-verify.t$(EXEEXT)
 libpub_la_SOURCES      += dsa-check.c
 EXTRA_DIST             += t/dsa
 
 ## Generalization of DSA to arbitrary cyclic groups.
 pkginclude_HEADERS     += gdsa.h
 libpub_la_SOURCES      += gdsa.c
-TESTS                  += gdsa.$t
+TESTS                  += gdsa.t$(EXEEXT)
 EXTRA_DIST             += t/gdsa
 
 ## KISA `KCDSA', generalized to arbitrary cyclic groups.
 pkginclude_HEADERS     += gkcdsa.h
 libpub_la_SOURCES      += gkcdsa.c
-TESTS                  += gkcdsa.$t
+TESTS                  += gkcdsa.t$(EXEEXT)
 EXTRA_DIST             += t/gkcdsa
 
 ## General key validity checking machinery.
@@ -95,7 +95,7 @@ libpub_la_SOURCES     += oaep.c
 libpub_la_SOURCES      += pkcs1.c
 libpub_la_SOURCES      += pss.c
 EXTRA_DIST             += rsa-test.c
-TESTS                  += rsa-test.$t
+TESTS                  += rsa-test.t$(EXEEXT)
 EXTRA_DIST             += t/rsa
 
 ###----- That's all, folks --------------------------------------------------
index 58b62b1..c7dc86e 100644 (file)
@@ -348,7 +348,7 @@ static const grand_ops gops = {
   "bbs",
   GRAND_CRYPTO, 0,
   gmisc, gdestroy,
-  gword, gbyte, gword, grand_range, grand_fill
+  gword, gbyte, gword, grand_defaultrange, grand_defaultfill
 };
 
 /* --- @bbs_rand@ --- *
index 3934131..a60125b 100644 (file)
@@ -53,7 +53,7 @@ librand_la_SOURCES    += grand.c
 ## A simple linear-congruential generator.
 pkginclude_HEADERS     += lcrand.h
 librand_la_SOURCES     += lcrand.c
-TESTS                  += lcrand.$t
+TESTS                  += lcrand.t$(EXEEXT)
 EXTRA_DIST             += t/lcrand
 
 ## Maurer's universal statistical test.
@@ -71,13 +71,13 @@ librand_la_SOURCES  += rand.c
 ## The SSL v3 pseudorandom function.
 pkginclude_HEADERS     += sslprf.h
 librand_la_SOURCES     += sslprf.c
-TESTS                  += sslprf.$t
+TESTS                  += sslprf.t$(EXEEXT)
 EXTRA_DIST             += t/sslprf
 
 ## The TLS v1 pseudorandom function.
 pkginclude_HEADERS     += tlsprf.h
 librand_la_SOURCES     += tlsprf.c
-TESTS                  += tlsprf.$t
+TESTS                  += tlsprf.t$(EXEEXT)
 EXTRA_DIST             += t/tlsprf
 
 ###----- That's all, folks --------------------------------------------------
index 9b18ab0..70ffaf8 100644 (file)
@@ -310,7 +310,8 @@ static const grand_ops gops = {
   "dsarand",
   0, 0,
   gmisc, gdestroy,
-  grand_word, grand_byte, grand_word, grand_range, gfill
+  grand_defaultword, grand_defaultbyte, grand_defaultword,
+  grand_defaultrange, gfill
 };
 
 /* --- @dsarand_create@ --- *
index 17d248b..e445191 100644 (file)
 
 #include "grand.h"
 
+/*----- Default operations ------------------------------------------------*/
+
+/* --- @grand_defaultbyte@ --- *
+ *
+ * Arguments:  @grand *r@ = pointet to generic generator
+ *
+ * Returns:    A uniformly-distributed pseudorandom integer in the interval
+ *             %$[0, 256)$%.
+ *
+ * Use:                Default @byte@ output method.  This calls the @range@ method
+ *             to return a uniform random value between 0 and 255.
+ */
+
+octet grand_defaultbyte(grand *r)
+  { return (r->ops->range(r, 256)); }
+
+/* --- @grand_defaultword@ --- *
+ *
+ * Arguments:  @grand *r@ = pointet to generic generator
+ *
+ * Returns:    A uniformly-distributed pseudorandom integer in the interval
+ *             %$[0, 2^{32})$%.
+ *
+ * Use:                Default @word@ output method.  This calls the @fill@ method
+ *             to fill a 4-octet buffer with uniform random bytes, and then
+ *             converts them to an integer.
+ */
+
+uint32 grand_defaultword(grand *r)
+  { octet buf[4]; r->ops->fill(r, buf, sizeof(buf)); return (LOAD32(buf)); }
+
+/* --- @grand_defaultrange@ --- *
+ *
+ * Arguments:  @grand *r@ = pointet to generic generator
+ *             @uint32 l@ = limit for acceptable results
+ *
+ * Returns:    A uniformly-distributed pseudorandom integer in the interval
+ *             %$[0, l)$%.
+ *
+ * Use:                Default @range@ output method.  This falls back to either
+ *             @word@ (if the generator's @max@ is zero, or if @max < l@) or
+ *             @raw@ (otherwise).  This might recurse via @fill@ and @byte@,
+ *             but this is safe because of the constraint on the @raw@
+ *             method.
+ */
+
+uint32 grand_defaultrange(grand *r, uint32 l)
+{
+  uint32 m, z;
+  uint32 (*w)(grand */*r*/);
+  uint32 x;
+
+  /* --- Decide where to get data from --- *
+   *
+   * The choice of %$2^{32} - 1$% as a limit when using @grand_word@ isn't
+   * wonderful, but working with %$2^{32}$% is awkward and the loss of a few
+   * return values isn't significant.  The algorithm below still successfully
+   * returns uniformly distributed results.
+   *
+   * If there's a raw generator, and it can cope with the limit, then use it;
+   * otherwise use the @word@ generator, which may recurse via @fill@ and
+   * @byte@, but by that point it must be able to satisfy us.
+   */
+
+  if (r->ops->max && r->ops->max >= l) {
+    w = r->ops->raw;
+    m = r->ops->max;
+  } else {
+    assert(!r->ops->max || r->ops->max >= 256);
+    w = grand_word;
+    m = 0xffffffff;
+  }
+
+  /* --- Work out maximum acceptable return value --- *
+   *
+   * This will be the highest multiple of @l@ less than @m@.
+   */
+
+  z = m - m%l;
+
+  /* --- Generate numbers until something acceptable is found --- *
+   *
+   * This will require an expected number of attempts less than 2.
+   */
+
+  do x = w(r); while (x >= z);
+  return (x%l);
+}
+
+/* --- @grand_defaultfill@ --- *
+ *
+ * Arguments:  @grand *r@ = pointet to generic generator
+ *             @void *p@ = pointer to a buffer
+ *             @size_t sz@ = size of the buffer
+ *
+ * Returns:    ---
+ *
+ * Use:                Fills a buffer with uniformly distributed pseudorandom bytes.
+ *             This calls the @byte@ method repeatedly to fill in the output
+ *             buffer.
+ */
+
+void grand_defaultfill(grand *r, void *p, size_t sz)
+  { octet *q = p; while (sz--) *q++ = r->ops->byte(r); }
+
 /*----- Main code ---------------------------------------------------------*/
 
 /* --- @grand_byte@ --- *
 
 octet grand_byte(grand *r)
 {
-  if (r->ops->byte != grand_byte)
-    return (r->ops->byte(r));
-  else if (r->ops->word != grand_word)
-    return (r->ops->word(r) & 0xff);
-  else if (r->ops->fill != grand_fill) {
-    octet o;
-    r->ops->fill(r, &o, 1);
-    return (o);
-  } else
-    return (grand_range(r, 256));
+  if (r->ops->byte == grand_byte) return (grand_defaultbyte(r));
+  else return (r->ops->byte(r));
 }
 
 /* --- @grand_word@ --- *
@@ -67,13 +164,8 @@ octet grand_byte(grand *r)
 
 uint32 grand_word(grand *r)
 {
-  if (r->ops->word != grand_word)
-    return (r->ops->word(r));
-  else {
-    octet b[4];
-    grand_fill(r, b, sizeof(b));
-    return (LOAD32(b));
-  }
+  if (r->ops->word == grand_word) return (grand_defaultword(r));
+  else return (r->ops->word(r));
 }
 
 /* --- @grand_range@ --- *
@@ -87,44 +179,8 @@ uint32 grand_word(grand *r)
 
 uint32 grand_range(grand *r, uint32 l)
 {
-  if (r->ops->range != grand_range)
-    return (r->ops->range(r, l));
-  else {
-    uint32 m, z;
-    uint32 (*w)(grand */*r*/);
-    uint32 x;
-
-    /* --- Decide where to get data from --- *
-     *
-     * The choice of %$2^{32} - 1$% as a limit when using @grand_word@ isn't
-     * wonderful, but working with %$2^{32}$% is awkward and the loss of a
-     * few return values isn't significant.  The algorithm below still
-     * successfully returns uniformly distributed results.
-     */
-
-    if (r->ops->max) {
-      w = r->ops->raw;
-      m = r->ops->max;
-    } else {
-      w = grand_word;
-      m = 0xffffffff;
-    }
-
-    /* --- Work out maximum acceptable return value --- *
-     *
-     * This will be the highest multiple of @l@ less than @m@.
-     */
-
-    z = m - (m % l);
-
-    /* --- Generate numbers until something acceptable is found --- *
-     *
-     * This will require an expected number of attempts less than 2.
-     */
-
-    do x = w(r); while (x >= z);
-    return (x % l);
-  }
+  if (r->ops->range == grand_range) return (grand_defaultrange(r, l));
+  else return (r->ops->range(r, l));
 }
 
 /* --- @grand_fill@ --- *
@@ -141,15 +197,8 @@ uint32 grand_range(grand *r, uint32 l)
 
 void grand_fill(grand *r, void *p, size_t sz)
 {
-  if (r->ops->fill != grand_fill)
-    r->ops->fill(r, p, sz);
-  else {
-    octet *q = p;
-    while (sz) {
-      *q++ = r->ops->byte(r);
-      sz--;
-    }
-  }
+  if (r->ops->fill == grand_fill) grand_defaultfill(r, p, sz);
+  else r->ops->fill(r, p, sz);
 }
 
 /*----- That's all, folks -------------------------------------------------*/
index ec11404..b45f045 100644 (file)
@@ -51,7 +51,10 @@ typedef struct grand_ops {
 
   const char *name;                    /* Generator's name */
   unsigned f;                          /* Various flags */
-  uint32 max;                          /* Maximum raw output */
+  uint32 max;                          /* Maximum raw output, if nonzero;
+                                        * must be either zero or at least
+                                        * 256
+                                        */
 
   /* --- Maintenance methods --- */
 
@@ -60,9 +63,10 @@ typedef struct grand_ops {
 
   /* --- Output methods --- *
    *
-   * Only one of these operations need actually be implemented.  All the
-   * other operations may be synthesized.  Of course, performance is improved
-   * if more are provided.
+   * Of these, only @raw@ need be implemented directly by the generator: the
+   * others can point to provided @grand_default...@ functions, which will
+   * synthesize the necessary behaviour.  Of course, this comes at an
+   * efficiency penalty.
    */
 
   uint32 (*raw)(grand */*r*/);         /* Uniform over %$[0, max)$% */
@@ -105,6 +109,67 @@ enum {
 
 #define GRAND_BADOP assert(((void)"bad grand_misc op", 0))
 
+/*----- Default operations ------------------------------------------------*/
+
+/* --- @grand_defaultbyte@ --- *
+ *
+ * Arguments:  @grand *r@ = pointet to generic generator
+ *
+ * Returns:    A uniformly-distributed pseudorandom integer in the interval
+ *             %$[0, 256)$%.
+ *
+ * Use:                Default @byte@ output method.  This calls the @range@ method
+ *             to return a uniform random value between 0 and 255.
+ */
+
+extern octet grand_defaultbyte(grand */*r*/);
+
+/* --- @grand_defaultword@ --- *
+ *
+ * Arguments:  @grand *r@ = pointet to generic generator
+ *
+ * Returns:    A uniformly-distributed pseudorandom integer in the interval
+ *             %$[0, 2^{32})$%.
+ *
+ * Use:                Default @word@ output method.  This calls the @fill@ method
+ *             to fill a 4-octet buffer with uniform random bytes, and then
+ *             converts them to an integer.
+ */
+
+extern uint32 grand_defaultword(grand */*r*/);
+
+/* --- @grand_defaultrange@ --- *
+ *
+ * Arguments:  @grand *r@ = pointet to generic generator
+ *             @uint32 l@ = limit for acceptable results
+ *
+ * Returns:    A uniformly-distributed pseudorandom integer in the interval
+ *             %$[0, l)$%.
+ *
+ * Use:                Default @range@ output method.  This falls back to either
+ *             @word@ (if the generator's @max@ is zero, or if @max < l@) or
+ *             @raw@ (otherwise).  This might recurse via @fill@ and @byte@,
+ *             but this is safe because of the constraint on the @raw@
+ *             method.
+ */
+
+extern uint32 grand_defaultrange(grand */*r*/, uint32 /*l*/);
+
+/* --- @grand_defaultfill@ --- *
+ *
+ * Arguments:  @grand *r@ = pointet to generic generator
+ *             @void *p@ = pointer to a buffer
+ *             @size_t sz@ = size of the buffer
+ *
+ * Returns:    ---
+ *
+ * Use:                Fills a buffer with uniformly distributed pseudorandom bytes.
+ *             This calls the @byte@ method repeatedly to fill in the output
+ *             buffer.
+ */
+
+extern void grand_defaultfill(grand */*r*/, void */*p*/, size_t /*sz*/);
+
 /*----- Functions provided ------------------------------------------------*/
 
 /* --- @grand_byte@ --- *
index 6944a71..d8c4a37 100644 (file)
@@ -246,7 +246,7 @@ static const grand_ops gops = {
   "lcrand",
   LCRAND_P, 0,
   gmisc, gdestroy,
-  graw, gbyte, grand_word, grange, grand_fill
+  graw, gbyte, grand_defaultword, grange, grand_defaultfill
 };
 
 /* --- @lcrand_create@ --- *
index 3bece70..3969b4e 100644 (file)
@@ -365,7 +365,7 @@ int noise_filter(rand_pool *r, int good, const char *c)
 
 #ifdef USE_FREEWHEEL
 
-static jmp_buf fwjmp;
+static sigjmp_buf fwjmp;
 
 static void fwalarm(int sig)
 {
index e0bebbf..6fcdf43 100644 (file)
@@ -560,7 +560,7 @@ static const grand_ops gops = {
   "rand",
   GRAND_CRYPTO, 0,
   gmisc, gdestroy,
-  gword, gbyte, gword, grand_range, gfill
+  gword, gbyte, gword, grand_defaultrange, gfill
 };
 
 /* --- @rand_create@ --- *
index 83a4c84..06187b3 100644 (file)
@@ -270,7 +270,7 @@ static const grand_ops grops = {
   "<sslprf-dummy>",
   GRAND_CRYPTO, 0,
   grmisc, grdestroy,
-  grword, grbyte, grword, grand_range, grfill
+  grword, grbyte, grword, grand_defaultrange, grfill
 };
 
 /* ---@sslprf_rand@ --- *
index 3f055b0..fa28faf 100644 (file)
@@ -249,7 +249,7 @@ static const grand_ops dx_grops = {
   "<tlsdx-dummy>",
   GRAND_CRYPTO, 0,
   dx_grmisc, dx_grdestroy,
-  dx_grword, dx_grbyte, dx_grword, grand_range, dx_grfill
+  dx_grword, dx_grbyte, dx_grword, grand_defaultrange, dx_grfill
 };
 
 /* ---@tlsdx_rand@ --- *
@@ -454,7 +454,7 @@ static const grand_ops prf_grops = {
   "<tlsprf-dummy>",
   GRAND_CRYPTO, 0,
   prf_grmisc, prf_grdestroy,
-  prf_grword, prf_grbyte, prf_grword, grand_range, prf_grfill
+  prf_grword, prf_grbyte, prf_grword, grand_defaultrange, prf_grfill
 };
 
 /* ---@tlsprf_rand@ --- *
index e78277b..1d3374f 100644 (file)
@@ -102,22 +102,23 @@ pkginclude_HEADERS        += $(BLKC_H)
 
 ## Schneier's `Blowfish' block cipher.
 BLKCS                  += blowfish
-libsymm_la_SOURCES     += $(precomp)/blowfish-tab.c
-PRECOMPS               += $(precomp)/blowfish-tab.c
+nodist_libsymm_la_SOURCES += ../precomp/symm/blowfish-tab.c
+PRECOMPS               += $(precomp)/symm/blowfish-tab.c
 PRECOMP_PROGS          += blowfish-mktab
 blowfish_mktab_CPPFLAGS         = $(AM_CPPFLAGS) -DQUIET
 if !CROSS_COMPILING
-$(precomp)/blowfish-tab.c:
-       $(AM_V_at)$(MKDIR_P) $(precomp)
-       $(AM_V_at)$(MAKE) blowfish-mktab$e
-       $(AM_V_GEN)./blowfish-mktab >$(precomp)/blowfish-tab.c.new && \
-               mv $(precomp)/blowfish-tab.c.new $(precomp)/blowfish-tab.c
+$(precomp)/symm/blowfish-tab.c:
+       $(AM_V_at)$(MKDIR_P) $(precomp)/symm
+       $(AM_V_at)$(MAKE) blowfish-mktab$(EXEEXT)
+       $(AM_V_GEN)./blowfish-mktab >$(precomp)/symm/blowfish-tab.c.new && \
+               mv $(precomp)/symm/blowfish-tab.c.new \
+                       $(precomp)/symm/blowfish-tab.c
 endif
 
 ## Adams and Tavares' `CAST' block ciphers.
 BLKCS                  += cast128 cast256
 libsymm_la_SOURCES     += cast-s.c cast-sk.c cast-base.h
-cast256.$t: t/cast256
+cast256.t$(EXEEXT): t/cast256
 EXTRA_DIST             += t/cast256.aes
 MAINTAINERCLEANFILES   += $(srcdir)/t/cast256
 t/cast256: t/cast256.aes
@@ -128,15 +129,16 @@ t/cast256: t/cast256.aes
 
 ## IBM's `DES' block cipher, by Feistel, Coppersmith, and others.
 BLKCS                  += des des3
-libsymm_la_SOURCES     += des-base.h $(precomp)/des-tab.c
-PRECOMPS               += $(precomp)/des-tab.c
+libsymm_la_SOURCES     += des-base.h
+nodist_libsymm_la_SOURCES += ../precomp/symm/des-tab.c
+PRECOMPS               += $(precomp)/symm/des-tab.c
 PRECOMP_PROGS          += des-mktab
 if !CROSS_COMPILING
-$(precomp)/des-tab.c:
-       $(AM_V_at)$(MKDIR_P) $(precomp)
-       $(AM_V_at)$(MAKE) des-mktab$e
-       $(AM_V_GEN)./des-mktab >$(precomp)/des-tab.c.new && \
-               mv $(precomp)/des-tab.c.new $(precomp)/des-tab.c
+$(precomp)/symm/des-tab.c:
+       $(AM_V_at)$(MKDIR_P) $(precomp)/symm
+       $(AM_V_at)$(MAKE) des-mktab$(EXEEXT)
+       $(AM_V_GEN)./des-mktab >$(precomp)/symm/des-tab.c.new && \
+               mv $(precomp)/symm/des-tab.c.new $(precomp)/symm/des-tab.c
 endif
 
 ## Rivest's `DESX' variant, with pre- and post-whitening.
@@ -148,17 +150,17 @@ BLKCS                     += idea
 
 ## IBM's `MARS' block cipher.
 BLKCS                  += mars
-libsymm_la_SOURCES     += $(precomp)/mars-tab.c
-PRECOMPS               += $(precomp)/mars-tab.c
+nodist_libsymm_la_SOURCES += ../precomp/symm/mars-tab.c
+PRECOMPS               += $(precomp)/symm/mars-tab.c
 PRECOMP_PROGS          += mars-mktab
 if !CROSS_COMPILING
-$(precomp)/mars-tab.c:
-       $(AM_V_at)$(MKDIR_P) $(precomp)
-       $(AM_V_at)$(MAKE) mars-mktab$e
-       $(AM_V_GEN)./mars-mktab >$(precomp)/mars-tab.c.new && \
-               mv $(precomp)/mars-tab.c.new $(precomp)/mars-tab.c
+$(precomp)/symm/mars-tab.c:
+       $(AM_V_at)$(MKDIR_P) $(precomp)/symm
+       $(AM_V_at)$(MAKE) mars-mktab$(EXEEXT)
+       $(AM_V_GEN)./mars-mktab >$(precomp)/symm/mars-tab.c.new && \
+               mv $(precomp)/symm/mars-tab.c.new $(precomp)/symm/mars-tab.c
 endif
-mars.$t: t/mars
+mars.t$(EXEEXT): t/mars
 EXTRA_DIST             += t/mars.aes
 MAINTAINERCLEANFILES   += $(srcdir)/t/mars
 t/mars: t/mars.aes
@@ -186,17 +188,18 @@ endif
 if CPUFAM_AMD64
 libsymm_la_SOURCES     += rijndael-x86ish-aesni.S
 endif
-libsymm_la_SOURCES     += $(precomp)/rijndael-tab.c
-PRECOMPS               += $(precomp)/rijndael-tab.c
+nodist_libsymm_la_SOURCES += ../precomp/symm/rijndael-tab.c
+PRECOMPS               += $(precomp)/symm/rijndael-tab.c
 PRECOMP_PROGS          += rijndael-mktab
 if !CROSS_COMPILING
-$(precomp)/rijndael-tab.c:
-       $(AM_V_at)$(MKDIR_P) $(precomp)
-       $(AM_V_at)$(MAKE) rijndael-mktab$e
-       $(AM_V_GEN)./rijndael-mktab >$(precomp)/rijndael-tab.c.new && \
-               mv $(precomp)/rijndael-tab.c.new $(precomp)/rijndael-tab.c
+$(precomp)/symm/rijndael-tab.c:
+       $(AM_V_at)$(MKDIR_P) $(precomp)/symm
+       $(AM_V_at)$(MAKE) rijndael-mktab$(EXEEXT)
+       $(AM_V_GEN)./rijndael-mktab >$(precomp)/symm/rijndael-tab.c.new && \
+               mv $(precomp)/symm/rijndael-tab.c.new \
+                       $(precomp)/symm/rijndael-tab.c
 endif
-rijndael.$t: t/rijndael
+rijndael.t$(EXEEXT): t/rijndael
 EXTRA_DIST             += t/rijndael.aes
 MAINTAINERCLEANFILES   += $(srcdir)/t/rijndael
 t/rijndael: t/rijndael.aes
@@ -207,16 +210,17 @@ t/rijndael: t/rijndael.aes
 
 ## Massey's `SAFER' block ciphers.
 BLKCS                  += safer safersk
-libsymm_la_SOURCES     += $(precomp)/safer-tab.c
-PRECOMPS               += $(precomp)/safer-tab.c
+nodist_libsymm_la_SOURCES += ../precomp/symm/safer-tab.c
+PRECOMPS               += $(precomp)/symm/safer-tab.c
 PRECOMP_PROGS          += safer-mktab
 STUBS_HDR              += SAFER-SK,safersk,safer
 if !CROSS_COMPILING
-$(precomp)/safer-tab.c:
-       $(AM_V_at)$(MKDIR_P) $(precomp)
-       $(AM_V_at)$(MAKE) safer-mktab$e
-       $(AM_V_GEN)./safer-mktab >$(precomp)/safer-tab.c.new && \
-               mv $(precomp)/safer-tab.c.new $(precomp)/safer-tab.c
+$(precomp)/symm/safer-tab.c:
+       $(AM_V_at)$(MKDIR_P) $(precomp)/symm
+       $(AM_V_at)$(MAKE) safer-mktab$(EXEEXT)
+       $(AM_V_GEN)./safer-mktab >$(precomp)/symm/safer-tab.c.new && \
+               mv $(precomp)/symm/safer-tab.c.new \
+                       $(precomp)/symm/safer-tab.c
 endif
 
 ## Anderson, Biham and Knudsen's `Serpent' block cipher.
@@ -224,7 +228,7 @@ BLKCS                       += serpent
 libsymm_la_SOURCES     += serpent-sbox.h
 check_PROGRAMS         += serpent-check
 TESTS                  += serpent-check
-serpent.$t: t/serpent
+serpent.t$(EXEEXT): t/serpent
 EXTRA_DIST             += t/serpent.aes
 MAINTAINERCLEANFILES   += $(srcdir)/t/serpent
 t/serpent: t/serpent.aes
@@ -240,15 +244,16 @@ libsymm_la_SOURCES        += skipjack-tab.c
 
 ## Daemen and Rijmen's `Square' block cipher.
 BLKCS                  += square
-libsymm_la_SOURCES     += $(precomp)/square-tab.c
-PRECOMPS               += $(precomp)/square-tab.c
+nodist_libsymm_la_SOURCES += ../precomp/symm/square-tab.c
+PRECOMPS               += $(precomp)/symm/square-tab.c
 PRECOMP_PROGS          += square-mktab
 if !CROSS_COMPILING
-$(precomp)/square-tab.c:
-       $(AM_V_at)$(MKDIR_P) $(precomp)
-       $(AM_V_at)$(MAKE) square-mktab$e
-       $(AM_V_GEN)./square-mktab >$(precomp)/square-tab.c.new && \
-               mv $(precomp)/square-tab.c.new $(precomp)/square-tab.c
+$(precomp)/symm/square-tab.c:
+       $(AM_V_at)$(MKDIR_P) $(precomp)/symm
+       $(AM_V_at)$(MAKE) square-mktab$(EXEEXT)
+       $(AM_V_GEN)./square-mktab >$(precomp)/symm/square-tab.c.new && \
+               mv $(precomp)/symm/square-tab.c.new \
+                       $(precomp)/symm/square-tab.c
 endif
 
 ## Wheeler and Needham's `TEA' and `XTEA' block ciphers.
@@ -257,17 +262,18 @@ BLKCS                     += tea xtea
 ## Schneier, Kelsey, Whiting, Wagner, Hall and Ferguson's `Twofish' block
 ## cipher.
 BLKCS                  += twofish
-libsymm_la_SOURCES     += $(precomp)/twofish-tab.c
-PRECOMPS               += $(precomp)/twofish-tab.c
+nodist_libsymm_la_SOURCES += ../precomp/symm/twofish-tab.c
+PRECOMPS               += $(precomp)/symm/twofish-tab.c
 PRECOMP_PROGS          += twofish-mktab
 if !CROSS_COMPILING
-$(precomp)/twofish-tab.c:
-       $(AM_V_at)$(MKDIR_P) $(precomp)
-       $(AM_V_at)$(MAKE) twofish-mktab$e
-       $(AM_V_GEN)./twofish-mktab >$(precomp)/twofish-tab.c.new && \
-               mv $(precomp)/twofish-tab.c.new $(precomp)/twofish-tab.c
+$(precomp)/symm/twofish-tab.c:
+       $(AM_V_at)$(MKDIR_P) $(precomp)/symm
+       $(AM_V_at)$(MAKE) twofish-mktab$(EXEEXT)
+       $(AM_V_GEN)./twofish-mktab >$(precomp)/symm/twofish-tab.c.new && \
+               mv $(precomp)/symm/twofish-tab.c.new \
+                       $(precomp)/symm/twofish-tab.c
 endif
-twofish.$t: t/twofish
+twofish.t$(EXEEXT): t/twofish
 EXTRA_DIST             += t/twofish.aes
 MAINTAINERCLEANFILES   += $(srcdir)/t/twofish
 t/twofish: t/twofish.aes
@@ -322,29 +328,33 @@ STUBS_HDR         += SHA-384,sha384,sha512
 
 ## Anderson and Biham's `Tiger' hash function.
 HASHES                 += tiger
-libsymm_la_SOURCES     += tiger-base.h $(precomp)/tiger-tab.c
-PRECOMPS               += $(precomp)/tiger-tab.c
+libsymm_la_SOURCES     += tiger-base.h
+nodist_libsymm_la_SOURCES += ../precomp/symm/tiger-tab.c
+PRECOMPS               += $(precomp)/symm/tiger-tab.c
 PRECOMP_PROGS          += tiger-mktab
 if !CROSS_COMPILING
-$(precomp)/tiger-tab.c:
-       $(AM_V_at)$(MKDIR_P) $(precomp)
-       $(AM_V_at)$(MAKE) tiger-mktab$e
-       $(AM_V_GEN)./tiger-mktab >$(precomp)/tiger-tab.c.new && \
-               mv $(precomp)/tiger-tab.c.new $(precomp)/tiger-tab.c
+$(precomp)/symm/tiger-tab.c:
+       $(AM_V_at)$(MKDIR_P) $(precomp)/symm
+       $(AM_V_at)$(MAKE) tiger-mktab$(EXEEXT)
+       $(AM_V_GEN)./tiger-mktab >$(precomp)/symm/tiger-tab.c.new && \
+               mv $(precomp)/symm/tiger-tab.c.new \
+                       $(precomp)/symm/tiger-tab.c
 endif
 
 ## Barreto and Rijmen's `Whirlpool' hash function.
 HASHES                 += whirlpool whirlpool256
-libsymm_la_SOURCES     += $(precomp)/whirlpool-tab.c
-PRECOMPS               += $(precomp)/whirlpool-tab.c
+nodist_libsymm_la_SOURCES += ../precomp/symm/whirlpool-tab.c
+PRECOMPS               += $(precomp)/symm/whirlpool-tab.c
 PRECOMP_PROGS          += whirlpool-mktab
 STUBS_HDR              += Whirlpool-256,whirlpool256,whirlpool
 if !CROSS_COMPILING
-$(precomp)/whirlpool-tab.c:
-       $(AM_V_at)$(MKDIR_P) $(precomp)
-       $(AM_V_at)$(MAKE) whirlpool-mktab$e
-       $(AM_V_GEN)./whirlpool-mktab >$(precomp)/whirlpool-tab.c.new && \
-               mv $(precomp)/whirlpool-tab.c.new $(precomp)/whirlpool-tab.c
+$(precomp)/symm/whirlpool-tab.c:
+       $(AM_V_at)$(MKDIR_P) $(precomp)/symm
+       $(AM_V_at)$(MAKE) whirlpool-mktab$(EXEEXT)
+       $(AM_V_GEN)./whirlpool-mktab \
+                       >$(precomp)/symm/whirlpool-tab.c.new && \
+               mv $(precomp)/symm/whirlpool-tab.c.new \
+                       $(precomp)/symm/whirlpool-tab.c
 endif
 
 ## Bellare, Canetti and Krawczyk's `HMAC' mode for message authentication.
@@ -364,14 +374,14 @@ ALL_HASHES                += crc32=gcrc32
 ## Rivest's `RC4' stream cipher.
 pkginclude_HEADERS     += rc4.h
 libsymm_la_SOURCES     += rc4.c
-TESTS                  += rc4.$t
+TESTS                  += rc4.t$(EXEEXT)
 EXTRA_DIST             += t/rc4
 ALL_CIPHERS            += rc4
 
 ## Coppersmith and Rogaway's `SEAL' pseudorandom function.
 pkginclude_HEADERS     += seal.h
 libsymm_la_SOURCES     += seal.c
-TESTS                  += seal.$t
+TESTS                  += seal.t$(EXEEXT)
 EXTRA_DIST             += t/seal
 ALL_CIPHERS            += seal
 
@@ -390,7 +400,7 @@ endif
 if CPUFAM_AMD64
 libsymm_la_SOURCES     += salsa20-x86ish-sse2.S
 endif
-TESTS                  += salsa20.$t
+TESTS                  += salsa20.t$(EXEEXT)
 ALL_CIPHERS            += salsa20 salsa2012 salsa208
 ALL_CIPHERS            += xsalsa20 xsalsa2012 xsalsa208
 STUBS_HDR              += Salsa20/12,salsa2012,salsa20
@@ -400,7 +410,7 @@ STUBS_HDR           += XSalsa20/12,xsalsa2012,salsa20
 STUBS_HDR              += XSalsa20/8,xsalsa208,salsa20
 EXTRA_DIST             += t/salsa20
 MAINTAINERCLEANFILES   += t/salsa20
-salsa20.$t: t/salsa20
+salsa20.t$(EXEEXT): t/salsa20
 SALSA20_ESTREAM_TV      = t/salsa20.estream
 SALSA20_ESTREAM_TV     += t/salsa2012.estream
 SALSA20_ESTREAM_TV     += t/salsa208.estream
@@ -422,7 +432,7 @@ endif
 if CPUFAM_AMD64
 libsymm_la_SOURCES     += chacha-x86ish-sse2.S
 endif
-TESTS                  += chacha.$t
+TESTS                  += chacha.t$(EXEEXT)
 EXTRA_DIST             += t/chacha
 ALL_CIPHERS            += chacha20 chacha12 chacha8
 ALL_CIPHERS            += xchacha20 xchacha12 xchacha8
@@ -533,6 +543,6 @@ EXTRA_DIST          += $(SYMM_TEST_FILES)
 EXTRA_DIST             += daftstory.h
 
 ## Clean the debris from the `modes' subdirectory.
-CLEANFILES             += modes/*.to modes/*.$t
+CLEANFILES             += modes/*.to modes/*.t$(EXEEXT)
 
 ###----- That's all, folks --------------------------------------------------
index f48ee46..56c8f05 100644 (file)
@@ -467,12 +467,12 @@ static const octet iv[] = IV;                                             \
 static octet ct[sizeof(text)];                                         \
 static octet pt[sizeof(text)];                                         \
                                                                        \
-static void hexdump(const octet *p, size_t sz)                         \
+static void hexdump(const octet *p, size_t sz, size_t off)             \
 {                                                                      \
   const octet *q = p + sz;                                             \
   for (sz = 0; p < q; p++, sz++) {                                     \
     printf("%02x", *p);                                                        \
-    if ((sz + 1) % PRE##_BLKSZ == 0)                                   \
+    if ((off + sz + 1) % PRE##_BLKSZ == 0)                             \
       putchar(':');                                                    \
   }                                                                    \
 }                                                                      \
@@ -513,14 +513,14 @@ int main(void)                                                            \
     } else {                                                           \
       printf("\nError (sz = %lu)\n", (unsigned long)sz);               \
       status = 1;                                                      \
-      printf("\tplaintext      = "); hexdump(text, sz);                        \
-       printf(", "); hexdump(text + sz, rest);                         \
+      printf("\tplaintext      = "); hexdump(text, sz, 0);             \
+       printf(", "); hexdump(text + sz, rest, sz);                     \
        fputc('\n', stdout);                                            \
-      printf("\tciphertext     = "); hexdump(ct, sz);                  \
-       printf(", "); hexdump(ct + sz, rest);                           \
+      printf("\tciphertext     = "); hexdump(ct, sz, 0);               \
+       printf(", "); hexdump(ct + sz, rest, sz);                       \
        fputc('\n', stdout);                                            \
-      printf("\trecovered text = "); hexdump(pt, sz);                  \
-       printf(", "); hexdump(pt + sz, rest);                           \
+      printf("\trecovered text = "); hexdump(pt, sz, 0);               \
+       printf(", "); hexdump(pt + sz, rest, sz);                       \
        fputc('\n', stdout);                                            \
       fputc('\n', stdout);                                             \
     }                                                                  \
index 767f4c4..4f0f38f 100644 (file)
@@ -426,12 +426,12 @@ static const octet iv[] = IV;                                             \
 static octet ct[sizeof(text)];                                         \
 static octet pt[sizeof(text)];                                         \
                                                                        \
-static void hexdump(const octet *p, size_t sz)                         \
+static void hexdump(const octet *p, size_t sz, size_t off)             \
 {                                                                      \
   const octet *q = p + sz;                                             \
   for (sz = 0; p < q; p++, sz++) {                                     \
     printf("%02x", *p);                                                        \
-    if ((sz + 1) % PRE##_BLKSZ == 0)                                   \
+    if ((off + sz + 1) % PRE##_BLKSZ == 0)                             \
       putchar(':');                                                    \
   }                                                                    \
 }                                                                      \
@@ -472,14 +472,14 @@ int main(void)                                                            \
     } else {                                                           \
       printf("\nError (sz = %lu)\n", (unsigned long)sz);               \
       status = 1;                                                      \
-      printf("\tplaintext      = "); hexdump(text, sz);                        \
-       printf(", "); hexdump(text + sz, rest);                         \
+      printf("\tplaintext      = "); hexdump(text, sz, 0);             \
+       printf(", "); hexdump(text + sz, rest, sz);                     \
        fputc('\n', stdout);                                            \
-      printf("\tciphertext     = "); hexdump(ct, sz);                  \
-       printf(", "); hexdump(ct + sz, rest);                           \
+      printf("\tciphertext     = "); hexdump(ct, sz, 0);               \
+       printf(", "); hexdump(ct + sz, rest, sz);                       \
        fputc('\n', stdout);                                            \
-      printf("\trecovered text = "); hexdump(pt, sz);                  \
-       printf(", "); hexdump(pt + sz, rest);                           \
+      printf("\trecovered text = "); hexdump(pt, sz, 0);               \
+       printf(", "); hexdump(pt + sz, rest, sz);                       \
        fputc('\n', stdout);                                            \
       fputc('\n', stdout);                                             \
     }                                                                  \
index 80a84c1..0c8aa00 100644 (file)
@@ -695,7 +695,7 @@ static void grdestroy(grand *r)
   static const grand_ops grops_rand_##rr = {                           \
     "chacha" #rr, GRAND_CRYPTO, 0,                                     \
     grmisc, grdestroy, grword,                                         \
-    grbyte, grword, grand_range, grfill                                        \
+    grbyte, grword, grand_defaultrange, grfill                         \
   };                                                                   \
                                                                        \
   grand *chacha##rr##_rand(const void *k, size_t ksz, const void *n)   \
@@ -737,7 +737,7 @@ CHACHA_VARS(DEFGRAND)
   static const grand_ops grxops_rand_##rr = {                          \
     "xchacha" #rr, GRAND_CRYPTO, 0,                                    \
     grmisc, grxdestroy_##rr, grword,                                   \
-    grbyte, grword, grand_range, grfill                                        \
+    grbyte, grword, grand_defaultrange, grfill                         \
   };                                                                   \
                                                                        \
   grand *xchacha##rr##_rand(const void *k, size_t ksz, const void *n)  \
index 2f35323..4553679 100644 (file)
@@ -398,7 +398,7 @@ static const grand_ops grops = {                                    \
   #pre "-counter",                                                     \
   GRAND_CRYPTO, 0,                                                     \
   grmisc, grdestroy,                                                   \
-  grword, grbyte, grword, grand_range, grfill                          \
+  grword, grbyte, grword, grand_defaultrange, grfill                   \
 };                                                                     \
                                                                        \
 /* --- @pre_counterrand@ --- *                                         \
@@ -453,12 +453,12 @@ static const octet iv[] = IV;                                             \
 static octet ct[sizeof(text)];                                         \
 static octet pt[sizeof(text)];                                         \
                                                                        \
-static void hexdump(const octet *p, size_t sz)                         \
+static void hexdump(const octet *p, size_t sz, size_t off)             \
 {                                                                      \
   const octet *q = p + sz;                                             \
   for (sz = 0; p < q; p++, sz++) {                                     \
     printf("%02x", *p);                                                        \
-    if ((sz + 1) % PRE##_BLKSZ == 0)                                   \
+    if ((off + sz + 1) % PRE##_BLKSZ == 0)                             \
       putchar(':');                                                    \
   }                                                                    \
 }                                                                      \
@@ -499,14 +499,14 @@ int main(void)                                                            \
     } else {                                                           \
       printf("\nError (sz = %lu)\n", (unsigned long)sz);               \
       status = 1;                                                      \
-      printf("\tplaintext      = "); hexdump(text, sz);                        \
-       printf(", "); hexdump(text + sz, rest);                         \
+      printf("\tplaintext      = "); hexdump(text, sz, 0);             \
+       printf(", "); hexdump(text + sz, rest, sz);                     \
        fputc('\n', stdout);                                            \
-      printf("\tciphertext     = "); hexdump(ct, sz);                  \
-       printf(", "); hexdump(ct + sz, rest);                           \
+      printf("\tciphertext     = "); hexdump(ct, sz, 0);               \
+       printf(", "); hexdump(ct + sz, rest, sz);                       \
        fputc('\n', stdout);                                            \
-      printf("\trecovered text = "); hexdump(pt, sz);                  \
-       printf(", "); hexdump(pt + sz, rest);                           \
+      printf("\trecovered text = "); hexdump(pt, sz, 0);               \
+       printf(", "); hexdump(pt + sz, rest, sz);                       \
        fputc('\n', stdout);                                            \
       fputc('\n', stdout);                                             \
     }                                                                  \
index ea153a2..9f50292 100644 (file)
@@ -391,12 +391,12 @@ static const octet iv[] = IV;                                             \
 static octet ct[sizeof(text)];                                         \
 static octet pt[sizeof(text)];                                         \
                                                                        \
-static void hexdump(const octet *p, size_t sz)                         \
+static void hexdump(const octet *p, size_t sz, size_t off)             \
 {                                                                      \
   const octet *q = p + sz;                                             \
   for (sz = 0; p < q; p++, sz++) {                                     \
     printf("%02x", *p);                                                        \
-    if ((sz + 1) % PRE##_BLKSZ == 0)                                   \
+    if ((off + sz + 1) % PRE##_BLKSZ == 0)                             \
       putchar(':');                                                    \
   }                                                                    \
 }                                                                      \
@@ -436,14 +436,14 @@ int main(void)                                                            \
     } else {                                                           \
       printf("\nError (sz = %lu)\n", (unsigned long)sz);               \
       status = 1;                                                      \
-      printf("\tplaintext      = "); hexdump(text, sz);                        \
-       printf(", "); hexdump(text + sz, rest);                         \
+      printf("\tplaintext      = "); hexdump(text, sz, 0);             \
+       printf(", "); hexdump(text + sz, rest, sz);                     \
        fputc('\n', stdout);                                            \
-      printf("\tciphertext     = "); hexdump(ct, sz);                  \
-       printf(", "); hexdump(ct + sz, rest);                           \
+      printf("\tciphertext     = "); hexdump(ct, sz, 0);               \
+       printf(", "); hexdump(ct + sz, rest, sz);                       \
        fputc('\n', stdout);                                            \
-      printf("\trecovered text = "); hexdump(pt, sz);                  \
-       printf(", "); hexdump(pt + sz, rest);                           \
+      printf("\trecovered text = "); hexdump(pt, sz, 0);               \
+       printf(", "); hexdump(pt + sz, rest, sz);                       \
        fputc('\n', stdout);                                            \
       fputc('\n', stdout);                                             \
     }                                                                  \
index b5105ed..529428f 100644 (file)
@@ -327,7 +327,7 @@ static const grand_ops grops = {                                    \
   #pre "-mgf",                                                         \
   GRAND_CRYPTO, 0,                                                     \
   grmisc, grdestroy,                                                   \
-  grword, grbyte, grword, grand_range, grfill                          \
+  grword, grbyte, grword, grand_defaultrange, grfill                   \
 };                                                                     \
                                                                        \
 /* --- @pre_mgfrand@ --- *                                             \
index e9e52a7..73fb6db 100644 (file)
@@ -15,14 +15,14 @@ GENMODES_H =
 %repeat
 GENMODES_C += modes/@blkc-@blkcmode.c
 GENMODES_H += modes/@blkc-@blkcmode.h
-SYMM_TESTS += @blkc-@blkcmode.$t
+SYMM_TESTS += modes/@blkc-@blkcmode.t$(EXEEXT)
 %end
 
 ## Hash function modes.
 %repeat
 GENMODES_C += modes/@hash-@hashmode.c
 GENMODES_H += modes/@hash-@hashmode.h
-SYMM_TESTS += @hash-@hashmode.$t
+SYMM_TESTS += modes/@hash-@hashmode.t$(EXEEXT)
 %end
 
 ## Interface and implementation headers for the various modes.
@@ -40,7 +40,7 @@ BLKC_H =
 %repeat
 BLKC_C += @blkc.c
 BLKC_H += @blkc.h
-SYMM_TESTS += @blkc.$t
+SYMM_TESTS += @blkc.t$(EXEEXT)
 %end
 
 ## Hash function interfaces and implementations.
@@ -49,7 +49,7 @@ HASH_H =
 %repeat
 HASH_C += @hash.c
 HASH_H += @hash.h
-SYMM_TESTS += @hash.$t
+SYMM_TESTS += @hash.t$(EXEEXT)
 %end
 
 ## Modes for symmetric encryption.
index 6b1357d..358ee54 100644 (file)
@@ -410,7 +410,7 @@ static const grand_ops grops = {                                    \
   #pre "-ofb",                                                         \
   GRAND_CRYPTO, 0,                                                     \
   grmisc, grdestroy,                                                   \
-  grword, grbyte, grword, grand_range, grfill                          \
+  grword, grbyte, grword, grand_defaultrange, grfill                   \
 };                                                                     \
                                                                        \
 /* --- @pre_ofbrand@ --- *                                             \
@@ -465,12 +465,12 @@ static const octet iv[] = IV;                                             \
 static octet ct[sizeof(text)];                                         \
 static octet pt[sizeof(text)];                                         \
                                                                        \
-static void hexdump(const octet *p, size_t sz)                         \
+static void hexdump(const octet *p, size_t sz, size_t off)             \
 {                                                                      \
   const octet *q = p + sz;                                             \
   for (sz = 0; p < q; p++, sz++) {                                     \
     printf("%02x", *p);                                                        \
-    if ((sz + 1) % PRE##_BLKSZ == 0)                                   \
+    if ((off + sz + 1) % PRE##_BLKSZ == 0)                             \
       putchar(':');                                                    \
   }                                                                    \
 }                                                                      \
@@ -511,14 +511,14 @@ int main(void)                                                            \
     } else {                                                           \
       printf("\nError (sz = %lu)\n", (unsigned long)sz);               \
       status = 1;                                                      \
-      printf("\tplaintext      = "); hexdump(text, sz);                        \
-       printf(", "); hexdump(text + sz, rest);                         \
+      printf("\tplaintext      = "); hexdump(text, sz, 0);             \
+       printf(", "); hexdump(text + sz, rest, sz);                     \
        fputc('\n', stdout);                                            \
-      printf("\tciphertext     = "); hexdump(ct, sz);                  \
-       printf(", "); hexdump(ct + sz, rest);                           \
+      printf("\tciphertext     = "); hexdump(ct, sz, 0);               \
+       printf(", "); hexdump(ct + sz, rest, sz);                       \
        fputc('\n', stdout);                                            \
-      printf("\trecovered text = "); hexdump(pt, sz);                  \
-       printf(", "); hexdump(pt + sz, rest);                           \
+      printf("\trecovered text = "); hexdump(pt, sz, 0);               \
+       printf(", "); hexdump(pt + sz, rest, sz);                       \
        fputc('\n', stdout);                                            \
       fputc('\n', stdout);                                             \
     }                                                                  \
index 38f0097..214dbc1 100644 (file)
@@ -267,7 +267,7 @@ static const grand_ops grops = {
   "rc4",
   GRAND_CRYPTO, 0,
   grmisc, grdestroy,
-  grword, grbyte, grword, grand_range, grfill
+  grword, grbyte, grword, grand_defaultrange, grfill
 };
 
 /* --- @rc4_rand@ --- *
index eb4e67a..40f28fc 100644 (file)
@@ -695,7 +695,7 @@ static void grdestroy(grand *r)
   static const grand_ops grops_rand_##rr = {                           \
     SALSA20_NAME_##rr, GRAND_CRYPTO, 0,                                        \
     grmisc, grdestroy, grword,                                         \
-    grbyte, grword, grand_range, grfill                                        \
+    grbyte, grword, grand_defaultrange, grfill                         \
   };                                                                   \
                                                                        \
   grand *SALSA20_DECOR(salsa20, rr, _rand)                             \
@@ -738,7 +738,7 @@ SALSA20_VARS(DEFGRAND)
   static const grand_ops grxops_rand_##rr = {                          \
     "x" SALSA20_NAME_##rr, GRAND_CRYPTO, 0,                            \
     grmisc, grxdestroy_##rr, grword,                                   \
-    grbyte, grword, grand_range, grfill                                        \
+    grbyte, grword, grand_defaultrange, grfill                         \
   };                                                                   \
                                                                        \
   grand *SALSA20_DECOR(xsalsa20, rr, _rand)                            \
index 57cfc10..0ba56c0 100644 (file)
@@ -529,7 +529,7 @@ static const grand_ops grops = {
   "seal",
   GRAND_CRYPTO, 0,
   grmisc, grdestroy,
-  grword, grbyte, grword, grand_range, grfill
+  grword, grbyte, grword, grand_defaultrange, grfill
 };
 
 /* --- @seal_rand@ --- *
diff --git a/vars.am b/vars.am
index b0cd53c..ea5cbc0 100644 (file)
--- a/vars.am
+++ b/vars.am
 ###--------------------------------------------------------------------------
 ### Miscellaneous useful definitions.
 
-## Some convenient abbreviations for file suffixes.
-e                       = $(EXEEXT)
-o                       = $(OBJEXT)
-t                       = t$e
-
 ## Installation directories.
 archincludedir          = $(pkglibdir)/include
 
@@ -95,7 +90,9 @@ SUBST = $(V_SUBST)$(confsubst)
 
 CATACOMB_INCLUDES       = \
        -I$(top_srcdir) \
-       -I$(precomp) \
+       -I$(precomp)/math \
+       -I$(precomp)/misc \
+       -I$(precomp)/symm \
        -I$(top_srcdir)/base \
        -I$(top_srcdir)/key \
        -I$(top_srcdir)/math \
@@ -111,13 +108,13 @@ AM_CPPFLAGS                = $(CATACOMB_INCLUDES)
 ###--------------------------------------------------------------------------
 ### Testing.
 
-SUFFIXES               += .c .$t .to
+SUFFIXES               += .c .t$(EXEEXT) .to
 .c.to:
        $(AM_V_CC)$(COMPILE) -c -DTEST_RIG -DSRCDIR=\"$(srcdir)\" $< -o $@
-.to.$t:
+.to.t$(EXEEXT):
        $(AM_V_CCLD)$(LINK) $< $(TEST_LIBS) $(top_builddir)/libcatacomb.la \
                $(mLib_LIBS) $(CATACOMB_LIBS) $(LIBS)
 .PRECIOUS: %.to
-CLEANFILES             += *.to *.$t
+CLEANFILES             += *.to *.t$(EXEEXT)
 
 ###----- That's all, folks --------------------------------------------------