]> pd.if.org Git - zpackage/commitdiff
add package signing code
authorNathan Wagner <nw@hydaspes.if.org>
Mon, 11 Feb 2019 13:55:17 +0000 (13:55 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Mon, 11 Feb 2019 13:55:17 +0000 (13:55 +0000)
22 files changed:
Makefile
crypto/libeddsa/lib/bitness.h [new file with mode: 0644]
crypto/libeddsa/lib/burn.c [new file with mode: 0644]
crypto/libeddsa/lib/burn.h [new file with mode: 0644]
crypto/libeddsa/lib/burnstack.c [new file with mode: 0644]
crypto/libeddsa/lib/burnstack.h [new file with mode: 0644]
crypto/libeddsa/lib/compat.h [new file with mode: 0644]
crypto/libeddsa/lib/ed.c [new file with mode: 0644]
crypto/libeddsa/lib/ed.h [new file with mode: 0644]
crypto/libeddsa/lib/ed25519-sha512.c [new file with mode: 0644]
crypto/libeddsa/lib/ed_lookup32.h [new file with mode: 0644]
crypto/libeddsa/lib/ed_lookup64.h [new file with mode: 0644]
crypto/libeddsa/lib/eddsa.h [new file with mode: 0644]
crypto/libeddsa/lib/fld.c [new file with mode: 0644]
crypto/libeddsa/lib/fld.h [new file with mode: 0644]
crypto/libeddsa/lib/limb.h [new file with mode: 0644]
crypto/libeddsa/lib/sc.c [new file with mode: 0644]
crypto/libeddsa/lib/sc.h [new file with mode: 0644]
crypto/libeddsa/lib/sha512.c [new file with mode: 0644]
crypto/libeddsa/lib/sha512.h [new file with mode: 0644]
crypto/libeddsa/lib/x25519.c [new file with mode: 0644]
crypto/libeddsa/sign.c [new file with mode: 0644]

index 5b677ca0356baa9eb73860836f9a30ccc6f70867..f4143d5d949205e1e356ff689356e8a105a9f461 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -769,6 +769,24 @@ testddg: zpm-fetchurl
 testgra: zpm-fetchurl
        ./zpm-fetchurl granicus.if.org 443 /
 
+SIGNSRC= \
+crypto/libeddsa/lib/burn.c \
+crypto/libeddsa/lib/burnstack.c \
+crypto/libeddsa/lib/ed.c \
+crypto/libeddsa/lib/ed25519-sha512.c \
+crypto/libeddsa/lib/fld.c \
+crypto/libeddsa/lib/sc.c \
+crypto/libeddsa/lib/sha512.c \
+crypto/libeddsa/lib/x25519.c \
+crypto/libeddsa/sign.c
+
+SIGNOBJ=$(SIGNSRC:.c=.o)
+
+$(SIGNOBJ): CFLAGS+=-Icrypto/libeddsa/lib
+
+zpm-sign: $(SIGNOBJ)
+       $(CC) $(CFLAGS) -o $@ $+
+
 clean:
        rm -f *.o sqlite/*.o lib/*.o $(LZMAOBJ) liblzma.a \
                libelf.a libzpm.a zpm-addfile soname \
diff --git a/crypto/libeddsa/lib/bitness.h b/crypto/libeddsa/lib/bitness.h
new file mode 100644 (file)
index 0000000..5850c7f
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef BITNESS_H
+#define BITNESS_H
+
+#ifndef NO_AUTO_BITNESS
+  #ifdef __LP64__
+    #define USE_64BIT  1
+  #else
+    #undef USE_64BIT
+  #endif
+#endif
+
+#endif
diff --git a/crypto/libeddsa/lib/burn.c b/crypto/libeddsa/lib/burn.c
new file mode 100644 (file)
index 0000000..1b6c3b6
--- /dev/null
@@ -0,0 +1,14 @@
+#include <stdint.h>
+#include <stddef.h>
+
+/*
+ * burn - simple function to zero a buffer, used to cover our tracks
+ */
+void
+burn(void *dest, size_t len)
+{
+       volatile uint8_t *p = (uint8_t *)dest;
+       const uint8_t *end = (uint8_t *)dest+len;
+
+       while (p < end) *p++ = 0;
+}
diff --git a/crypto/libeddsa/lib/burn.h b/crypto/libeddsa/lib/burn.h
new file mode 100644 (file)
index 0000000..27d7044
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef BURN_H
+#define BURN_H
+
+#include <stddef.h>
+
+#include "compat.h"
+
+
+#if defined(HAVE_MEMSET_S)
+
+#include <string.h>
+static INLINE void burn(void *dest, size_t len) { memset_s(dest, len, 0, len); }
+
+#elif defined(HAVE_EXPLICIT_BZERO)
+
+#include <string.h>
+static INLINE void burn(void *dest, size_t len) { explicit_bzero(dest, len); }
+
+#else
+
+void   burn(void *dest, size_t len);
+
+#endif
+
+
+#endif
diff --git a/crypto/libeddsa/lib/burnstack.c b/crypto/libeddsa/lib/burnstack.c
new file mode 100644 (file)
index 0000000..acc140e
--- /dev/null
@@ -0,0 +1,21 @@
+#include <stdint.h>
+
+#include "burn.h"
+#include "burnstack.h"
+
+
+#ifdef USE_STACKCLEAN
+
+/*
+ * burnstack - cleanup our stack
+ */
+void
+burnstack(int len)
+{
+       uint8_t stack[1024];
+       burn(stack, 1024);
+       if (len > 0)
+               burnstack(len-1024);
+}
+
+#endif
diff --git a/crypto/libeddsa/lib/burnstack.h b/crypto/libeddsa/lib/burnstack.h
new file mode 100644 (file)
index 0000000..fbc63f7
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef BURNSTACK_H
+#define BURNSTACK_H
+
+#include "compat.h"
+
+#ifdef USE_STACKCLEAN
+
+void burnstack(int len);
+
+#else
+
+static INLINE void burnstack(int len) { (void)len; }
+
+#endif
+
+#endif
diff --git a/crypto/libeddsa/lib/compat.h b/crypto/libeddsa/lib/compat.h
new file mode 100644 (file)
index 0000000..7c62b1d
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef COMPAT_H
+#define COMPAT_H
+
+/*
+ * macro for inline-functions to make visual c happy :-\
+ */
+
+#ifdef _MSC_VER
+#define INLINE __inline
+#else
+#define INLINE inline
+#endif
+
+#endif
diff --git a/crypto/libeddsa/lib/ed.c b/crypto/libeddsa/lib/ed.c
new file mode 100644 (file)
index 0000000..9a1e5ee
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+ * Implementing twisted edwards curve
+ *     E : -x^2 + y^2 = 1 - (121665/121666) x^2 y^2
+ * over GF(2^255-19) according to [1].
+ *
+ * This code is public domain.
+ *
+ * Philipp Lay <philipp.lay@illunis.net>.
+ *
+ * References:
+ * [1] High-speed high-security signatures, 2011/09/26,
+ *     Bernstein, Duif, Lange, Schwabe, Yang
+ * [2] Twisted Edwards Curves Revisited, 2008,
+ *     Hisil, Wong, Carter, Dawson
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "bitness.h"
+#include "fld.h"
+#include "sc.h"
+#include "ed.h"
+
+
+/*
+ * special pre-computed form of a point on the curve, used
+ * for the lookup table and some optimizations.
+ */
+struct pced {
+       fld_t           diff;           /* y - x */
+       fld_t           sum;            /* y + x */
+       fld_t           prod;           /* 2*d*t */
+};
+
+
+
+#ifdef USE_64BIT
+
+/* lookup-table for ed_scale_base - 64bit version */
+static const struct pced ed_lookup[][8] = {
+  #include "ed_lookup64.h"
+};
+
+/* base point B of our group in pre-computed form */
+const struct pced pced_B = {
+       {62697248952638, 204681361388450, 631292143396476,
+        338455783676468, 1213667448819585},
+       {1288382639258501, 245678601348599, 269427782077623,
+        1462984067271730, 137412439391563},
+       {301289933810280, 1259582250014073, 1422107436869536,
+        796239922652654, 1953934009299142} };
+
+#else
+
+/* lookup-table for ed_scale_base - 32bit version */
+static const struct pced ed_lookup[][8] = {
+  #include "ed_lookup32.h"
+};
+
+/* base point B of our group in pre-computed form */
+const struct pced pced_B = {
+       {54563134, 934261, 64385954, 3049989, 66381436,
+        9406985, 12720692, 5043384, 19500929, 18085054},
+       {25967493, 19198397, 29566455, 3660896, 54414519,
+        4014786, 27544626, 21800161, 61029707, 2047604},
+       {58370664, 4489569, 9688441, 18769238, 10184608,
+        21191052, 29287918, 11864899, 42594502, 29115885} };
+
+#endif
+
+const struct ed ed_zero = { { 0 }, { 1 }, { 0 }, { 1 } };
+const struct pced pced_zero = { { 1 }, { 1 }, { 0 } };
+
+
+/*
+ * memselect - helper function to select one of two buffers in a
+ * time-constant way.
+ */
+static void
+memselect(void *out, const void *pa, const void *pb, size_t max, int flag)
+{
+       uint8_t *a = (uint8_t*)pa;
+       uint8_t *b = (uint8_t*)pb;
+       uint8_t *p = (uint8_t*)out;
+       uint8_t *endp = p+max;
+
+       uint8_t mB = (flag & 1) - 1;
+       uint8_t mA = ~mB;
+
+       while (p < endp)
+               *p++ = (mA & *a++) ^ (mB & *b++);
+}
+
+
+/*
+ * ed_import - import a point P on the curve from packet 256bit encoding.
+ *
+ */
+void
+ed_import(struct ed *P, const uint8_t in[32])
+{
+       fld_t U, V, A, B;
+       uint8_t tmp[32];
+       int flag;
+
+       /* import y */
+       memcpy(tmp, in, 32);
+       tmp[31] &= 0x7f;
+       
+       fld_import(P->y, tmp);
+
+       
+       /* U <- y^2 - 1,  V <- d*y^2 + 1 */
+       fld_sq(U, P->y);
+       fld_mul(V, con_d, U);
+       U[0]--;
+       V[0]++;
+
+       /* A <- v^2 */
+       fld_sq(A, V);
+       /* B <- v^4 */
+       fld_sq(B, A);
+       /* A <- uv^3 */
+       fld_mul(A, A, U);
+       fld_mul(A, A, V);
+       /* B <- (uv^7)^((q-5)/8) */
+       fld_mul(B, B, A);
+       fld_pow2523(B, B);
+       /* B <- uv^3 * (uv^7)^((q-5)/8) */
+       fld_mul(B, B, A);
+
+       /* A <- v * B^2 */
+       fld_sq(A, B);
+       fld_mul(A, A, V);
+       /* flag <- v*B^2 == u */
+       flag = fld_eq(A, U);
+
+       /* A <- j * B */
+       fld_mul(A, con_j, B);
+
+       memselect(P->x, B, A, sizeof(fld_t), flag);
+       fld_reduce(P->x, P->x);
+       fld_tinyscale(P->x, P->x, 1 - 2*((in[31] >> 7) ^ (P->x[0] & 1)));
+
+       /* compute t and z */
+       fld_mul(P->t, P->x, P->y);
+       fld_set0(P->z, 1);
+}
+
+
+/*
+ * ed_export - export point P to packed 256bit format.
+ */
+void
+ed_export(uint8_t out[32], const struct ed *P)
+{
+       fld_t x, y, zinv;
+
+       /* divide x and y by z to get affine coordinates */
+       fld_inv(zinv, P->z);
+       fld_mul(x, P->x, zinv);
+       fld_mul(y, P->y, zinv);
+       fld_export(out, y);
+
+       /* lsb decides the sign of x */
+       fld_reduce(x, x);
+       out[31] |= (x[0] & 1) << 7;
+}
+
+
+/*
+ * ed_add - add points P and Q
+ */
+static void
+ed_add(struct ed *out, const struct ed *P, const struct ed *Q)
+{
+       fld_t a, b, c, d, e, f, g, h, t;
+       
+       fld_sub(a, P->y, P->x);
+       fld_sub(t, Q->y, Q->x);
+       fld_mul(a, a, t);
+
+       fld_add(b, P->y, P->x);
+       fld_add(t, Q->y, Q->x);
+       fld_mul(b, b, t);
+
+       fld_mul(c, P->t, Q->t);
+       fld_mul(c, c, con_2d);
+
+       fld_mul(d, P->z, Q->z);
+       fld_scale2(d, d);
+
+       fld_sub(e, b, a);
+       fld_sub(f, d, c);
+       fld_add(g, d, c);
+       fld_add(h, b, a);
+       
+       fld_mul(out->x, e, f);
+       fld_mul(out->y, g, h);
+       fld_mul(out->t, e, h);
+       fld_mul(out->z, f, g);
+}
+
+
+/*
+ * ed_double - special case of ed_add for P=Q.
+ *
+ * little bit faster, since 4 multiplications are turned into squares.
+ */
+static void
+ed_double(struct ed *out, const struct ed *P)
+{
+       fld_t a, b, c, d, e, f, g, h;
+       
+       fld_sub(a, P->y, P->x);
+       fld_sq(a, a);
+
+       fld_add(b, P->y, P->x);
+       fld_sq(b, b);
+
+       fld_sq(c, P->t);
+       fld_mul(c, c, con_2d);
+
+       fld_sq(d, P->z);
+       fld_scale2(d, d);
+
+       fld_sub(e, b, a);
+       fld_sub(f, d, c);
+       fld_add(g, d, c);
+       fld_add(h, b, a);
+       
+       fld_mul(out->x, e, f);
+       fld_mul(out->y, g, h);
+       fld_mul(out->t, e, h);
+       fld_mul(out->z, f, g);
+}
+
+/*
+ * ed_sub - subtract two points P and Q.
+ *
+ * alternatively we could negate a point (which is cheap) and use
+ * ed_add, but this is a little bit faster.
+ */
+static void
+ed_sub(struct ed *out, const struct ed *P, const struct ed *Q)
+{
+       fld_t a, b, c, d, e, f, g, h, t;
+       
+       fld_sub(a, P->y, P->x);
+       fld_add(t, Q->y, Q->x);
+       fld_mul(a, a, t);
+
+       fld_add(b, P->y, P->x);
+       fld_sub(t, Q->y, Q->x);
+       fld_mul(b, b, t);
+
+       fld_mul(c, P->t, Q->t);
+       fld_mul(c, c, con_m2d);
+
+       fld_mul(d, P->z, Q->z);
+       fld_scale2(d, d);
+
+       fld_sub(e, b, a);
+       fld_sub(f, d, c);
+       fld_add(g, d, c);
+       fld_add(h, b, a);
+       
+       fld_mul(out->x, e, f);
+       fld_mul(out->y, g, h);
+       fld_mul(out->t, e, h);
+       fld_mul(out->z, f, g);
+}
+
+
+/*
+ * ed_add_pc - add points P and Q where Q is in precomputed form
+ *
+ * the precomputed form is used for the lookup table and as an
+ * optimization in ed_double_scale.
+ */
+static void
+ed_add_pc(struct ed *out, const struct ed *P, const struct pced *Q)
+{
+       fld_t a, b, c, d, e, f, g, h;
+
+       fld_sub(a, P->y, P->x);
+       fld_mul(a, a, Q->diff);
+
+       fld_add(b, P->y, P->x);
+       fld_mul(b, b, Q->sum);
+
+       fld_mul(c, P->t, Q->prod);
+       fld_scale2(d, P->z);
+
+       fld_sub(e, b, a);
+       fld_sub(f, d, c);
+       fld_add(g, d, c);
+       fld_add(h, b, a);
+       
+       fld_mul(out->x, e, f);
+       fld_mul(out->y, g, h);
+       fld_mul(out->t, e, h);
+       fld_mul(out->z, f, g);
+}
+
+/*
+ * ed_sub_pc - subtract P and Q where Q is in precomputed form.
+ */
+static void
+ed_sub_pc(struct ed *out, const struct ed *P, const struct pced *Q)
+{
+       fld_t a, b, c, d, e, f, g, h;
+
+       fld_sub(a, P->y, P->x);
+       fld_mul(a, a, Q->sum);
+
+       fld_add(b, P->y, P->x);
+       fld_mul(b, b, Q->diff);
+
+       fld_mul(c, P->t, Q->prod);
+       fld_neg(c, c);
+
+       fld_scale2(d, P->z);
+
+       fld_sub(e, b, a);
+       fld_sub(f, d, c);
+       fld_add(g, d, c);
+       fld_add(h, b, a);
+       
+       fld_mul(out->x, e, f);
+       fld_mul(out->y, g, h);
+       fld_mul(out->t, e, h);
+       fld_mul(out->z, f, g);
+}
+
+
+/*
+ * scale16 - helper function for ed_scale_base, returns x * 16^pow * base
+ *
+ * assumes:
+ *  -8 <= x <= 7
+ *   0 <= pow <= 62
+ *   2 | pow
+ */
+static void
+scale16(struct pced *out, int pow, int x)
+{
+       struct pced R = { { 0 }, { 0 }, { 0 } };
+       limb_t mA, mB, mask;
+       int neg, sgnx, absx;
+       int i, k;
+       
+       neg = (x >> 3) & 1;
+       sgnx = 1 - 2*neg;
+       absx = sgnx * x;
+       pow >>= 1;
+
+       /* handle abs(x) == 0 */
+       mask = absx | (absx >> 2);
+       mask |= mask >> 1;
+       mask = (mask & 1) - 1;
+       for (i = 0; i < FLD_LIMB_NUM; i++) {
+               R.diff[i] ^= pced_zero.diff[i] & mask;
+               R.sum[i] ^= pced_zero.sum[i] & mask;
+               R.prod[i] ^= pced_zero.prod[i] & mask;
+       }
+
+
+       /* go through our table and look for abs(x) */
+       for (k = 0; k < 8; k++) {
+               absx--;
+               mask = absx | (absx >> 2);
+               mask |= mask >> 1;
+               mask = (mask & 1) - 1;
+               for (i = 0; i < FLD_LIMB_NUM; i++) {
+                       R.diff[i] ^= ed_lookup[pow][k].diff[i] & mask;
+                       R.sum[i] ^= ed_lookup[pow][k].sum[i] & mask;
+                       R.prod[i] ^= ed_lookup[pow][k].prod[i] & mask;
+               }
+       }
+
+       /* conditionally negate R and write to out */
+       mA = neg-1;
+       mB = ~mA;
+       for (i = 0; i < FLD_LIMB_NUM; i++) {
+               out->diff[i] = (mA & R.diff[i]) ^ (mB & R.sum[i]);
+               out->sum[i]  = (mB & R.diff[i]) ^ (mA & R.sum[i]);
+               out->prod[i] = sgnx * R.prod[i];
+       }
+}
+
+
+/*
+ * ed_scale_base - calculates x * base
+ */
+void
+ed_scale_base(struct ed *out, const sc_t x)
+{
+       struct ed R0, R1;
+       struct pced P;
+       sc_t tmp;
+       uint8_t pack[32];
+       int r[64];
+       int i;
+       
+       /* s <- x + 8 * (16^64 - 1) / 15 */
+       sc_add(tmp, x, con_off);
+       sc_export(pack, tmp);
+       for (i = 0; i < 32; i++) {
+               r[2*i] = (pack[i] & 0x0f) - 8;
+               r[2*i+1] = (pack[i] >> 4) - 8;
+       }
+       
+       /*
+        * R0 <- r0*B + r2*16^2*B + ... + r62*16^62*B 
+        * R1 <- r1*B + r3*16^2*B + ... + r63*16^62*B
+        */
+       memcpy(&R0, &ed_zero, sizeof(struct ed));
+       memcpy(&R1, &ed_zero, sizeof(struct ed));
+       for (i = 0; i < 63; i += 2) {
+               scale16(&P, i, r[i]);
+               ed_add_pc(&R0, &R0, &P);
+
+               scale16(&P, i, r[i+1]);
+               ed_add_pc(&R1, &R1, &P);
+       }
+       
+       /* R1 <- 16 * R1 */
+       for (i = 0; i < 4; i++)
+               ed_add(&R1, &R1, &R1);
+
+       /* out <- R0 + R1 */
+       ed_add(out, &R0, &R1);
+}
+
+
+/*
+ * helper function to speed up ed_double_scale
+ */
+static void
+ed_precompute(struct pced *R, const struct ed *P)
+{
+       fld_sub(R->diff, P->y, P->x);
+       fld_add(R->sum, P->y, P->x);
+       fld_mul(R->prod, P->t, con_2d);
+}
+
+
+/*
+ * ed_dual_scale - calculates R = x*base + y*Q.  (vartime)
+ *
+ * Note: This algorithms does NOT run in constant time! Please use this
+ * only for public information like in ed25519_verify().
+ *
+ * assumes:
+ *   Q is affine, ie has z = 1
+ *   x and y must be reduced
+ */
+void
+ed_dual_scale(struct ed *R,
+             const sc_t x,
+             const sc_t y, const struct ed *Q)
+{
+       struct ed QpB, QmB;
+       struct pced pcQ;
+
+       int ux[SC_BITS+1], uy[SC_BITS+1];
+       int n, i;
+
+       memcpy(R, &ed_zero, sizeof(struct ed));
+
+       /* calculate joint sparse form of x and y */
+       n = sc_jsf(ux, uy, x, y);
+       if (n == -1)
+               return;
+
+       /* precompute Q, Q+B and Q-B */
+       ed_add_pc(&QpB, Q, &pced_B);
+       ed_sub_pc(&QmB, Q, &pced_B);
+       ed_precompute(&pcQ, Q);
+       
+       /* now we calculate R = x * base_point + y * Q using fast shamir method */
+       for (i = n; ; i--) {
+               if (ux[i] == 1) {
+                       if (uy[i] == 1)
+                               ed_add(R, R, &QpB);
+                       else if (uy[i] == -1)
+                               ed_sub(R, R, &QmB);
+                       else
+                               ed_add_pc(R, R, &pced_B);
+                       
+               } else if (ux[i] == -1) {
+                       if (uy[i] == 1)
+                               ed_add(R, R, &QmB);
+                       else if (uy[i] == -1)
+                               ed_sub(R, R, &QpB);
+                       else
+                               ed_sub_pc(R, R, &pced_B);
+
+               } else {
+                       if (uy[i] == 1)
+                               ed_add_pc(R, R, &pcQ);
+                       else if (uy[i] == -1)
+                               ed_sub_pc(R, R, &pcQ);
+               }
+
+               if (i == 0) break;
+
+               ed_double(R, R);
+       }
+}
diff --git a/crypto/libeddsa/lib/ed.h b/crypto/libeddsa/lib/ed.h
new file mode 100644 (file)
index 0000000..285040a
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef ED_H
+#define ED_H
+
+#include <stdint.h>
+
+#include "fld.h"
+#include "sc.h"
+
+
+/* (x,y,z) are the projective points on our curve E and t = x*y is an
+ * auxiliary coordinate (see [2], ch. 3).
+ */
+struct ed {
+       fld_t           x;
+       fld_t           y;
+       fld_t           t;
+       fld_t           z;
+};
+
+
+void   ed_export(uint8_t out[32], const struct ed *P);
+void   ed_import(struct ed *P, const uint8_t in[32]);
+
+void   ed_scale_base(struct ed *res, const sc_t x);
+
+void   ed_dual_scale(struct ed *R, const sc_t x,
+                     const sc_t y, const struct ed *Q);
+
+#endif
diff --git a/crypto/libeddsa/lib/ed25519-sha512.c b/crypto/libeddsa/lib/ed25519-sha512.c
new file mode 100644 (file)
index 0000000..c4c37fb
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * implementing ed25519-sha512 from [1].
+ *
+ * This code is public domain.
+ *
+ * Philipp Lay <philipp.lay@illunis.net>
+ *
+ *
+ * References:
+ * [1] High-speed high-security signatures, 2011/09/26,
+ *     Bernstein, Duif, Lange, Schwabe, Yang
+ *
+ * TODO:
+ *   - batch verify
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "eddsa.h"
+
+#include "sha512.h"
+#include "sc.h"
+#include "fld.h"
+#include "ed.h"
+#include "burnstack.h"
+
+
+static void
+ed25519_key_setup(uint8_t out[SHA512_HASH_LENGTH],
+                 const uint8_t sk[ED25519_KEY_LEN])
+{
+       struct sha512 hash;
+
+       /* hash secret-key */
+       sha512_init(&hash);
+       sha512_add(&hash, sk, ED25519_KEY_LEN);
+       sha512_final(&hash, out);
+
+       /* delete bit 255 and set bit 254 */
+       out[31] &= 0x7f;
+       out[31] |= 0x40;
+       /* delete 3 lowest bits */
+       out[0] &= 0xf8;
+}
+
+
+/*
+ * genpub - derive public key from secret key
+ */
+static void
+genpub(uint8_t pub[ED25519_KEY_LEN], const uint8_t sec[ED25519_KEY_LEN])
+{
+       uint8_t h[SHA512_HASH_LENGTH];
+       struct ed A;
+       sc_t a;
+
+       /* derive secret and import it */
+       ed25519_key_setup(h, sec);
+       sc_import(a, h, 32);
+
+       /* multiply with base point to calculate public key */
+       ed_scale_base(&A, a);
+       ed_export(pub, &A);
+}
+
+
+/*
+ * ed25519_genpub - stack-clearing wrapper for genpub
+ */
+void
+ed25519_genpub(uint8_t pub[ED25519_KEY_LEN], const uint8_t sec[ED25519_KEY_LEN])
+{
+       genpub(pub, sec);
+       burnstack(2048);
+}
+
+
+/*
+ * sign - create ed25519 signature of data using secret key sec
+ */
+static void
+sign(uint8_t sig[ED25519_SIG_LEN],
+     const uint8_t sec[ED25519_KEY_LEN],
+     const uint8_t pub[ED25519_KEY_LEN],
+     const uint8_t *data, size_t len)
+{
+       struct sha512 hash;
+       uint8_t h[SHA512_HASH_LENGTH];
+       
+       sc_t a, r, t, S;
+       struct ed R;
+
+       /* derive secret scalar a */
+       ed25519_key_setup(h, sec);
+       sc_import(a, h, 32);
+
+       /* hash next 32 bytes together with data to form r */
+       sha512_init(&hash);
+       sha512_add(&hash, h+32, 32);
+       sha512_add(&hash, data, len);
+       sha512_final(&hash, h);
+       sc_import(r, h, sizeof(h));
+
+       /* calculate R = r * B which form the first 256bit of the signature */
+       ed_scale_base(&R, r);
+       ed_export(sig, &R);
+       
+       /* calculate t := Hash(export(R), export(A), data) mod m */
+       sha512_init(&hash);
+       sha512_add(&hash, sig, 32);
+       sha512_add(&hash, pub, 32);
+       sha512_add(&hash, data, len);
+       sha512_final(&hash, h);
+       sc_import(t, h, sizeof(h));
+       
+       /* calculate S := r + t*a mod m and finish the signature */
+       sc_mul(S, t, a);
+       sc_add(S, r, S);
+       sc_export(sig+32, S);
+}
+
+
+/*
+ * ed25519_sign - stack-cleaning wrapper for sign
+ */
+void
+ed25519_sign(uint8_t sig[ED25519_SIG_LEN],
+          const uint8_t sec[ED25519_KEY_LEN],
+          const uint8_t pub[ED25519_KEY_LEN],
+          const uint8_t *data, size_t len)
+{
+       sign(sig, sec, pub, data, len);
+       burnstack(4096);
+}
+
+
+/*
+ * ed25519_verify - verifies an ed25519-signature of given data.
+ *
+ * note: this functions runs in vartime and does no stack cleanup, since
+ * all information are considered public.
+ *
+ * returns true if signature is ok and false otherwise.
+ */
+bool
+ed25519_verify(const uint8_t sig[ED25519_SIG_LEN],
+              const uint8_t pub[ED25519_KEY_LEN],
+              const uint8_t *data, size_t len)
+{
+       struct sha512 hash;
+       uint8_t h[SHA512_HASH_LENGTH];
+       struct ed A, C;
+       sc_t t, S;
+       uint8_t check[32];
+
+       /* import public key */
+       ed_import(&A, pub);
+
+       /* import S from second half of the signature */
+       sc_import(S, sig+32, 32);
+
+       /* calculate t := Hash(export(R), export(A), data) mod m */
+       sha512_init(&hash);
+       sha512_add(&hash, sig, 32);
+       sha512_add(&hash, pub, 32);
+       sha512_add(&hash, data, len);
+       sha512_final(&hash, h);
+       sc_import(t, h, 64);
+
+       /* verify signature (vartime!) */
+       fld_neg(A.x, A.x);
+       fld_neg(A.t, A.t);
+       ed_dual_scale(&C, S, t, &A);
+       ed_export(check, &C);
+       
+       /* is export(C) == export(R) (vartime!) */
+       return (memcmp(check, sig, 32) == 0);
+}
+
+
+/*
+ * pk_ed25519_to_x25519 - convert a ed25519 public key to x25519
+ */
+void
+pk_ed25519_to_x25519(uint8_t out[X25519_KEY_LEN], const uint8_t in[ED25519_KEY_LEN])
+{
+       struct ed P;
+       fld_t u, t;
+
+       /* import ed25519 public key */
+       ed_import(&P, in);
+
+       /*
+        * We now have the point P = (x,y) on the curve
+        *
+        *      x^2 + y^2 = 1 + (121665/121666)x^2y^2
+        *
+        * and want the u-component of the corresponding point
+        * on the birationally equivalent montgomery curve
+        *
+        *      v^2 = u^3 + 486662 u^2 + u.
+        *
+        *
+        * From the paper [1] we get
+        *
+        *      y = (u - 1) / (u + 1),
+        *
+        * which immediately yields
+        *
+        *      u = (1 + y) / (1 - y)
+        *
+        * or, by using projective coordinantes,
+        *
+        *      u = (z + y) / (z - y).
+        */
+
+       /* u <- z + y */
+       fld_add(u, P.z, P.y);
+
+       /* t <- (z - y)^-1 */
+       fld_sub(t, P.z, P.y);
+       fld_inv(t, t);
+
+       /* u <- u * t = (z+y) / (z-y) */
+       fld_mul(u, u, t);
+
+       /* export curve25519 public key */
+       fld_export(out, u);
+}
+
+
+
+/*
+ * conv_sk_ed25519_to_x25519 - convert a ed25519 secret key to x25519 secret.
+ */
+static void
+conv_sk_ed25519_to_x25519(uint8_t out[X25519_KEY_LEN], const uint8_t in[ED25519_KEY_LEN])
+{
+       uint8_t h[SHA512_HASH_LENGTH];
+       ed25519_key_setup(h, in);
+       memcpy(out, h, X25519_KEY_LEN);
+}
+
+
+/*
+ * sk_ed25519_to_x25519 - stack-clearing wrapper for conv_sk_ed25519_to_x25519.
+ */
+void
+sk_ed25519_to_x25519(uint8_t out[X25519_KEY_LEN], const uint8_t in[ED25519_KEY_LEN])
+{
+       conv_sk_ed25519_to_x25519(out, in);
+       burnstack(1024);
+}
+
+
+
+
+
+/*
+ * Obsolete Interface, this will be removed in the future.
+ */
+
+
+/*
+ * eddsa_genpub - stack-clearing wrapper for genpub (obsolete interface!)
+ */
+void
+eddsa_genpub(uint8_t pub[32], const uint8_t sec[32])
+{
+       genpub(pub, sec);
+       burnstack(2048);
+}
+
+
+/*
+ * eddsa_sign - stack-cleaning wrapper for sign (obsolete interface!)
+ */
+void
+eddsa_sign(uint8_t sig[ED25519_SIG_LEN],
+          const uint8_t sec[ED25519_KEY_LEN],
+          const uint8_t pub[ED25519_KEY_LEN],
+          const uint8_t *data, size_t len)
+{
+       sign(sig, sec, pub, data, len);
+       burnstack(4096);
+}
+
+/*
+ * eddsa_verify - verifies an ed25519 signature of given data.
+ * (obsolete interface!)
+ *
+ */
+bool
+eddsa_verify(const uint8_t sig[ED25519_SIG_LEN],
+            const uint8_t pub[ED25519_KEY_LEN],
+            const uint8_t *data, size_t len)
+{
+       return ed25519_verify(sig, pub, data, len);
+}
+
+/*
+ * eddsa_pk_eddsa_to_dh - convert a ed25519 public key to x25519.
+ * (obsolete interface!)
+ */
+void
+eddsa_pk_eddsa_to_dh(uint8_t out[X25519_KEY_LEN], const uint8_t in[ED25519_KEY_LEN])
+{
+       pk_ed25519_to_x25519(out, in);
+}
+
+
+/*
+ * eddsa_sk_eddsa_to_dh - convert a ed25519 secret key to x25519 secret.
+ * (obsolete interface!)
+ */
+void
+eddsa_sk_eddsa_to_dh(uint8_t out[X25519_KEY_LEN], const uint8_t in[ED25519_KEY_LEN])
+{
+       conv_sk_ed25519_to_x25519(out, in);
+       burnstack(1024);
+}
diff --git a/crypto/libeddsa/lib/ed_lookup32.h b/crypto/libeddsa/lib/ed_lookup32.h
new file mode 100644 (file)
index 0000000..d7fe3da
--- /dev/null
@@ -0,0 +1,1603 @@
+/*
+ * this file is auto generated! see gentable32.gp
+ */
+{ /* 16^0 */
+       {       { 54563134, 934261, 64385954, 3049989, 66381436,
+               9406985, 12720692, 5043384, 19500929, 18085054 },       /* 1 * 16^0 */
+               { 25967493, 19198397, 29566455, 3660896, 54414519,
+               4014786, 27544626, 21800161, 61029707, 2047604 },
+               { 58370664, 4489569, 9688441, 18769238, 10184608,
+               21191052, 29287918, 11864899, 42594502, 29115885 } },
+       {       { 45405608, 6903824, 27185491, 6451973, 37531140,
+               24000426, 51492312, 11189267, 40279186, 28235350 },     /* 2 * 16^0 */
+               { 54292951, 20578084, 45527620, 11784319, 41753206,
+               30803714, 55390960, 29739860, 66750418, 23343128 },
+               { 26966623, 11152617, 32442495, 15396054, 14353839,
+               20802097, 63980037, 24013313, 51636816, 29387734 } },
+       {       { 16568933, 4717097, 55552716, 32452109, 15682895,
+               21747389, 16354576, 21778470, 7689661, 11199574 },      /* 3 * 16^0 */
+               { 15636272, 23865875, 24204772, 25642034, 616976,
+               16869170, 27787599, 18782243, 28944399, 32004408 },
+               { 30464137, 27578307, 55329429, 17883566, 23220364,
+               15915852, 7512774, 10017326, 49359771, 23634074 } },
+       {       { 23599295, 25248385, 55915199, 25867015, 13236773,
+               10506355, 7464579, 9656445, 13059162, 10374397 },       /* 4 * 16^0 */
+               { 50071967, 13921891, 10945806, 27521001, 27105051,
+               17470053, 38182653, 15006022, 3284568, 27277892 },
+               { 7798537, 16710257, 3033922, 2874086, 28997861,
+               2835604, 32406664, 29715387, 66467155, 33453106 } },
+       {       { 4708026, 6336745, 20377586, 9066809, 55836755,
+               6594695, 41455196, 12483687, 54440373, 5581305 },       /* 5 * 16^0 */
+               { 10861363, 11473154, 27284546, 1981175, 37044515,
+               12577860, 32867885, 14515107, 51670560, 10819379 },
+               { 19563141, 16186464, 37722007, 4097518, 10237984,
+               29206317, 28542349, 13850243, 43430843, 17738489 } },
+       {       { 58559652, 109982, 15149363, 2178705, 22900618,
+               4543417, 3044240, 17864545, 1762327, 14866737 },        /* 6 * 16^0 */
+               { 51736881, 20691677, 32573249, 4720197, 40672342,
+               5875510, 47920237, 18329612, 57289923, 21468654 },
+               { 48909169, 17603008, 56635573, 1707277, 49922944,
+               3916100, 38872452, 3959420, 27914454, 4383652 } },
+       {       { 36839857, 30090922, 7665485, 10083793, 28475525,
+               1649722, 20654025, 16520125, 30598449, 7715701 },       /* 7 * 16^0 */
+               { 5153727, 9909285, 1723747, 30776558, 30523604,
+               5516873, 19480852, 5230134, 43156425, 18378665 },
+               { 28881826, 14381568, 9657904, 3680757, 46927229,
+               7843315, 35708204, 1370707, 29794553, 32145132 } },
+       {       { 59913433, 30899068, 52378708, 462250, 39384538,
+               3941371, 60872247, 3696004, 34808032, 15351954 },       /* 8 * 16^0 */
+               { 14499471, 30824833, 33917750, 29299779, 28494861,
+               14271267, 30290735, 10876454, 33954766, 2381725 },
+               { 27431194, 8222322, 16448760, 29646437, 48401861,
+               11938354, 34147463, 30583916, 29551812, 10109425 } },
+},
+{ /* 16^2 */
+       {       { 27939166, 14210322, 4677035, 16277044, 44144402,
+               21156292, 34600109, 12005537, 49298737, 12803509 },     /* 1 * 16^2 */
+               { 53451805, 20399000, 35825113, 11777097, 21447386,
+               6519384, 64730580, 31926875, 10092782, 28790261 },
+               { 17228999, 17892808, 65875336, 300139, 65883994,
+               21839654, 30364212, 24516238, 18016356, 4397660 } },
+       {       { 29253598, 15796703, 64244882, 23645547, 10057022,
+               3163536, 7332899, 29434304, 46061167, 9934962 },        /* 2 * 16^2 */
+               { 56150021, 25864224, 4776340, 18600194, 27850027,
+               17952220, 40489757, 14544524, 49631360, 982638 },
+               { 5793284, 16271923, 42977250, 23438027, 29188559,
+               1206517, 52360934, 4559894, 36984942, 22656481 } },
+       {       { 12650548, 32057319, 9052870, 11355358, 49428827,
+               25154267, 49678271, 12264342, 10874051, 13524335 },     /* 3 * 16^2 */
+               { 39464912, 22061425, 16282656, 22517939, 28414020,
+               18542168, 24191033, 4541697, 53770555, 5500567 },
+               { 25556948, 30508442, 714650, 2510400, 23394682,
+               23139102, 33119037, 5080568, 44580805, 5376627 } },
+       {       { 64853442, 14606629, 45416424, 25514613, 28430648,
+               8775819, 36614302, 3044289, 31848280, 12543772 },       /* 4 * 16^2 */
+               { 41020600, 29543379, 50095164, 30016803, 60382070,
+               1920896, 44787559, 24106988, 4535767, 1569007 },
+               { 45080285, 2943892, 35251351, 6777305, 13784462,
+               29262229, 39731668, 31491700, 7718481, 14474653 } },
+       {       { 13741529, 10911568, 33875447, 24950694, 46931033,
+               32521134, 33040650, 20129900, 46379407, 8321685 },      /* 5 * 16^2 */
+               { 2385296, 2454213, 44477544, 46602, 62670929,
+               17874016, 656964, 26317767, 24316167, 28300865 },
+               { 21060490, 31341688, 15712756, 29218333, 1639039,
+               10656336, 23845965, 21679594, 57124405, 608371 } },
+       {       { 43864724, 33260226, 55364135, 14712570, 37643165,
+               31524814, 12797023, 27114124, 65475458, 16678953 },     /* 6 * 16^2 */
+               { 53436132, 18466845, 56219170, 25997372, 61071954,
+               11305546, 1123968, 26773855, 27229398, 23887 },
+               { 37608244, 4770661, 51054477, 14001337, 7830047,
+               9564805, 65600720, 28759386, 49939598, 4904952 } },
+       {       { 50127693, 4124965, 58568254, 22900634, 30336521,
+               19449185, 37302527, 916032, 60226322, 30567899 },       /* 7 * 16^2 */
+               { 24059538, 14617003, 19037157, 18514524, 19766092,
+               18648003, 5169210, 16191880, 2128236, 29227599 },
+               { 44477957, 12419371, 59974635, 26081060, 50629959,
+               16739174, 285431, 2763829, 15736322, 4143876 } },
+       {       { 33431108, 22423954, 49269897, 17927531, 8909498,
+               8376530, 34483524, 4087880, 51919953, 19138217 },       /* 8 * 16^2 */
+               { 2379333, 11839345, 62998462, 27565766, 11274297,
+               794957, 212801, 18959769, 23527083, 17096164 },
+               { 1767664, 7197987, 53903638, 31531796, 54017513,
+               448825, 5799055, 4357868, 62334673, 17231393 } },
+},
+{ /* 16^4 */
+       {       { 4409022, 2052381, 23373853, 10530217, 7676779,
+               20668478, 21302352, 29290375, 1244379, 20634787 },      /* 1 * 16^4 */
+               { 6721966, 13833823, 43585476, 32003117, 26354292,
+               21691111, 23365146, 29604700, 7390889, 2759800 },
+               { 62687625, 7169618, 4982368, 30596842, 30256824,
+               30776892, 14086412, 9208236, 15886429, 16489664 } },
+       {       { 41801399, 9795879, 64331450, 14878808, 33577029,
+               14780362, 13348553, 12076947, 36272402, 5113181 },      /* 2 * 16^4 */
+               { 1996056, 10375649, 14346367, 13311202, 60234729,
+               17116020, 53415665, 398368, 36502409, 32841498 },
+               { 49338080, 11797795, 31950843, 13929123, 41220562,
+               12288343, 36767763, 26218045, 13847710, 5387222 } },
+       {       { 20246567, 19185054, 22358228, 33010720, 18507282,
+               23140436, 14554436, 24808340, 32232923, 16763880 },     /* 3 * 16^4 */
+               { 48526701, 30138214, 17824842, 31213466, 22744342,
+               23111821, 8763060, 3617786, 47508202, 10370990 },
+               { 9648486, 10094563, 26416693, 14745928, 36734546,
+               27081810, 11094160, 15689506, 3140038, 17044340 } },
+       {       { 19153450, 11523972, 56012374, 27051289, 42461232,
+               5420646, 28344573, 8041113, 719605, 11671788 }, /* 4 * 16^4 */
+               { 50948792, 5472694, 31895588, 4744994, 8823515,
+               10365685, 39884064, 9448612, 38334410, 366294 },
+               { 8678006, 2694440, 60300850, 2517371, 4964326,
+               11152271, 51675948, 18287915, 27000812, 23358879 } },
+       {       { 11836410, 29574944, 26297893, 16080799, 23455045,
+               15735944, 1695823, 24735310, 8169719, 16220347 },       /* 5 * 16^4 */
+               { 51950941, 7134311, 8639287, 30739555, 59873175,
+               10421741, 564065, 5336097, 6750977, 19033406 },
+               { 48993007, 8653646, 17578566, 27461813, 59083086,
+               17541668, 55964556, 30926767, 61118155, 19388398 } },
+       {       { 39571412, 19301410, 41772562, 25551651, 57738101,
+               8129820, 21651608, 30315096, 48021414, 22549153 },      /* 6 * 16^4 */
+               { 43800366, 22586119, 15213227, 23473218, 36255258,
+               22504427, 27884328, 2847284, 2655861, 1738395 },
+               { 1533110, 3437855, 23735889, 459276, 29970501,
+               11335377, 26030092, 5821408, 10478196, 8544890 } },
+       {       { 36555903, 31326030, 51530034, 23407230, 13243888,
+               517024, 15479401, 29701199, 30460519, 1052596 },        /* 7 * 16^4 */
+               { 32173102, 17425121, 24896206, 3921497, 22579056,
+               30143578, 19270448, 12217473, 17789017, 30158437 },
+               { 55493970, 13323617, 32618793, 8175907, 51878691,
+               12596686, 27491595, 28942073, 3179267, 24075541 } },
+       {       { 11685058, 11822410, 3158003, 19601838, 33402193,
+               29389366, 5977895, 28339415, 473098, 5040608 }, /* 8 * 16^4 */
+               { 31947050, 19187781, 62468280, 18214510, 51982886,
+               27514722, 52352086, 17142691, 19072639, 24043372 },
+               { 46817982, 8198641, 39698732, 11602122, 1290375,
+               30754672, 28326861, 1721092, 47550222, 30422825 } },
+},
+{ /* 16^6 */
+       {       { 47173198, 3899860, 18283497, 26752864, 51380203,
+               22305220, 8754524, 7446702, 61432810, 5797015 },        /* 1 * 16^6 */
+               { 7881532, 10687937, 7578723, 7738378, 48157852,
+               31000479, 21820785, 8076149, 39240368, 11538388 },
+               { 55813245, 29760862, 51326753, 25589858, 12708868,
+               25098233, 2014098, 24503858, 64739691, 27677090 } },
+       {       { 14352079, 30134717, 48166819, 10822654, 32750596,
+               4699007, 67038501, 15776355, 38222085, 21579878 },      /* 2 * 16^6 */
+               { 44636488, 21985690, 39426843, 1146374, 18956691,
+               16640559, 1192730, 29840233, 15123618, 10811505 },
+               { 38867681, 25481956, 62129901, 28239114, 29416930,
+               1847569, 46454691, 17069576, 4714546, 23953777 } },
+       {       { 12876937, 23074376, 33134380, 6590940, 60801088,
+               14872439, 9613953, 8241152, 15370987, 9608631 },        /* 3 * 16^6 */
+               { 15200332, 8368572, 19679101, 15970074, 35236190,
+               1959450, 24611599, 29010600, 55362987, 12340219 },
+               { 62965568, 21540023, 8446280, 33162829, 4407737,
+               13629032, 59383996, 15866073, 38898243, 24740332 } },
+       {       { 14620696, 13067227, 51661590, 8264466, 14106269,
+               15080814, 33531827, 12516406, 45534429, 21077682 },     /* 4 * 16^6 */
+               { 26660628, 17876777, 8393733, 358047, 59707573,
+               992987, 43204631, 858696, 20571223, 8420556 },
+               { 236881, 10476226, 57258, 18877408, 6472997,
+               2466984, 17258519, 7256740, 8791136, 15069930 } },
+       {       { 5855666, 4990204, 53397016, 7294283, 59304582,
+               1924646, 65685689, 25642053, 34039526, 9234252 },       /* 5 * 16^6 */
+               { 1276391, 24182514, 22949634, 17231625, 43615824,
+               27852245, 14711874, 4874229, 36445724, 31223040 },
+               { 20590503, 24535444, 31529743, 26201766, 64402029,
+               10650547, 31559055, 21944845, 18979185, 13396066 } },
+       {       { 55541958, 26988926, 45743778, 15928891, 40950559,
+               4315420, 41160136, 29637754, 45628383, 12868081 },      /* 6 * 16^6 */
+               { 24474287, 4968103, 22267082, 4407354, 24063882,
+               25229252, 48291976, 13594781, 33514650, 7021958 },
+               { 38473832, 13504660, 19988037, 31421671, 21078224,
+               6443208, 45662757, 2244499, 54653067, 25465048 } },
+       {       { 55478669, 22050529, 58989363, 25911358, 2620055,
+               1022908, 43398120, 31985447, 50980335, 18591624 },      /* 7 * 16^6 */
+               { 36513336, 13793478, 61256044, 319135, 41385692,
+               27290532, 33086545, 8957937, 51875216, 5540520 },
+               { 23152952, 775386, 27395463, 14006635, 57407746,
+               4649511, 1689819, 892185, 55595587, 18348483 } },
+       {       { 34343820, 1927589, 31726409, 28801137, 23962433,
+               17534932, 27846558, 5931263, 37359161, 17445976 },      /* 8 * 16^6 */
+               { 9770129, 9586738, 26496094, 4324120, 1556511,
+               30004408, 27453818, 4763127, 47929250, 5867133 },
+               { 27461885, 30576896, 22380809, 1815854, 44075111,
+               30522493, 7283489, 18406359, 47582163, 7734628 } },
+},
+{ /* 16^8 */
+       {       { 34450527, 27383209, 59436070, 22502750, 6258877,
+               13504381, 10458790, 27135971, 58236621, 8424745 },      /* 1 * 16^8 */
+               { 59098600, 23963614, 55988460, 6196037, 29344158,
+               20123547, 7585294, 30377806, 18549496, 15302069 },
+               { 24687186, 8613276, 36441818, 30320886, 1863891,
+               31723888, 19206233, 7134917, 55824382, 32725512 } },
+       {       { 8911542, 6887158, 57524604, 26595841, 11145640,
+               24010752, 17303924, 19430194, 6536640, 10543906 },      /* 2 * 16^8 */
+               { 11334899, 24336410, 8025292, 12707519, 17523892,
+               23078361, 10243737, 18868971, 62042829, 16498836 },
+               { 38162480, 15479762, 49642029, 568875, 65611181,
+               11223453, 64439674, 16928857, 39873154, 8876770 } },
+       {       { 10330056, 70051, 7957388, 24551765, 9764901,
+               15609756, 27698697, 28664395, 1657393, 3084098 },       /* 3 * 16^8 */
+               { 41365946, 20987567, 51458897, 32707824, 34082177,
+               32758143, 33627041, 15824473, 66504438, 24514614 },
+               { 10477963, 26084172, 12119565, 20303627, 29016246,
+               28188843, 31280318, 14396151, 36875289, 15272408 } },
+       {       { 40928506, 9489186, 11053416, 18808271, 36055143,
+               5825629, 58724558, 24786899, 15341278, 8373727 },       /* 4 * 16^8 */
+               { 54820555, 3169462, 28813183, 16658753, 25116432,
+               27923966, 41934906, 20918293, 42094106, 1950503 },
+               { 28685821, 7759505, 52730348, 21551571, 35137043,
+               4079241, 298136, 23321830, 64230656, 15190419 } },
+       {       { 65528476, 21825014, 41129205, 22109408, 49696989,
+               22641577, 9291593, 17306653, 54954121, 6048604 },       /* 5 * 16^8 */
+               { 34175969, 13806335, 52771379, 17760000, 43104243,
+               10940927, 8669718, 2742393, 41075551, 26679428 },
+               { 36803549, 14843443, 1539301, 11864366, 20201677,
+               1900163, 13934231, 5128323, 11213262, 9168384 } },
+       {       { 43972811, 9282191, 14855179, 18164354, 59746048,
+               19145871, 44324911, 14461607, 14042978, 5230683 },      /* 6 * 16^8 */
+               { 40828332, 11007846, 19408960, 32613674, 48515898,
+               29225851, 62020803, 22449281, 20470156, 17155731 },
+               { 29969548, 30812838, 50396996, 25001989, 9175485,
+               31085458, 21556950, 3506042, 61174973, 21104723 } },
+       {       { 47644235, 10110287, 49846336, 30050539, 43608476,
+               1355668, 51585814, 15300987, 46594746, 9168259 },       /* 7 * 16^8 */
+               { 63964118, 8744660, 19704003, 4581278, 46678178,
+               6830682, 45824694, 8971512, 38569675, 15326562 },
+               { 61755510, 4488612, 43305616, 16314346, 7780487,
+               17915493, 38160505, 9601604, 33087103, 24543045 } },
+       {       { 23294591, 16921819, 44458082, 25083453, 27844203,
+               11461195, 13099750, 31094076, 18151675, 13417686 },     /* 8 * 16^8 */
+               { 47665694, 18041531, 46311396, 21109108, 37284416,
+               10229460, 39664535, 18553900, 61111993, 15664671 },
+               { 42385932, 29377914, 35958184, 5988918, 40250079,
+               6685064, 1661597, 21002991, 15271675, 18101767 } },
+},
+{ /* 16^10 */
+       {       { 35672693, 15575145, 30436815, 12192228, 44645511,
+               9395378, 57191156, 24915434, 12215109, 12028277 },      /* 1 * 16^10 */
+               { 11433023, 20325767, 8239630, 28274915, 65123427,
+               32828713, 48410099, 2167543, 60187563, 20114249 },
+               { 14098381, 6555944, 23007258, 5757252, 51681032,
+               20603929, 30123439, 4617780, 50208775, 32898803 } },
+       {       { 40577025, 29858441, 65199965, 2534300, 35238307,
+               17004076, 18341389, 22134481, 32013173, 23450893 },     /* 2 * 16^10 */
+               { 63082644, 18313596, 11893167, 13718664, 52299402,
+               1847384, 51288865, 10154008, 23973261, 20869958 },
+               { 41629544, 10876442, 55337778, 18929291, 54739296,
+               1838103, 21911214, 6354752, 4425632, 32716610 } },
+       {       { 19268631, 26250011, 1555348, 8692754, 45634805,
+               23643767, 6347389, 32142648, 47586572, 17444675 },      /* 3 * 16^10 */
+               { 56675475, 18941465, 22229857, 30463385, 53917697,
+               776728, 49693489, 21533969, 4725004, 14044970 },
+               { 42244775, 12986007, 56209986, 27995847, 55796492,
+               33405905, 19541417, 8180106, 9282262, 10282508 } },
+       {       { 56546323, 14895632, 26814552, 16880582, 49628109,
+               31065071, 64326972, 6993760, 49014979, 10114654 },      /* 4 * 16^10 */
+               { 40903763, 4428546, 58447668, 20360168, 4098401,
+               19389175, 15522534, 8372215, 5542595, 22851749 },
+               { 47001790, 32625013, 31422703, 10427861, 59998115,
+               6150668, 38017109, 22025285, 25953724, 33448274 } },
+       {       { 51110167, 7578151, 5310217, 14408357, 33560244,
+               33329692, 31575953, 6326196, 7381791, 31132593 },       /* 5 * 16^10 */
+               { 62874467, 25515139, 57989738, 3045999, 2101609,
+               20947138, 19390019, 6094296, 63793585, 12831124 },
+               { 46206085, 3296810, 24736065, 17226043, 18374253,
+               7318640, 6295303, 8082724, 51746375, 12339663 } },
+       {       { 48242193, 8331042, 24373479, 8541013, 66406866,
+               24284974, 12927299, 20858939, 44926390, 24541532 },     /* 6 * 16^10 */
+               { 27724736, 2291157, 6088201, 19369634, 1792726,
+               5857634, 13848414, 15768922, 25091167, 14856294 },
+               { 55685435, 28132841, 11632844, 3405020, 30536730,
+               21880393, 39848098, 13866389, 30146206, 9142070 } },
+       {       { 51186905, 16037936, 6713787, 16606682, 45496729,
+               2790943, 26396185, 3731949, 345228, 28091483 }, /* 7 * 16^10 */
+               { 3924129, 18246916, 53291741, 23499471, 12291819,
+               32886066, 39406089, 9326383, 58871006, 4171293 },
+               { 45781307, 13448258, 25284571, 1143661, 20614966,
+               24705045, 2031538, 21163201, 50855680, 19972348 } },
+       {       { 62033029, 9368965, 58546785, 28953529, 51858910,
+               6970559, 57918991, 16292056, 58241707, 3507939 },       /* 8 * 16^10 */
+               { 31016192, 16832003, 26371391, 19103199, 62081514,
+               14854136, 17477601, 3842657, 28012650, 17149012 },
+               { 29439664, 3537914, 23333589, 6997794, 49553303,
+               22536363, 51899661, 18503164, 57943934, 6580395 } },
+},
+{ /* 16^12 */
+       {       { 20714545, 29217521, 29088194, 7406487, 11426967,
+               28458727, 14792666, 18945815, 5289420, 33077305 },      /* 1 * 16^12 */
+               { 54923003, 25874643, 16438268, 10826160, 58412047,
+               27318820, 17860443, 24280586, 65013061, 9304566 },
+               { 50443312, 22903641, 60948518, 20248671, 9192019,
+               31751970, 17271489, 12349094, 26939669, 29802138 } },
+       {       { 22263325, 26994382, 3984569, 22379786, 51994855,
+               32987646, 28311252, 5358056, 43789084, 541963 },        /* 2 * 16^12 */
+               { 54218966, 9373457, 31595848, 16374215, 21471720,
+               13221525, 39825369, 21205872, 63410057, 117886 },
+               { 16259200, 3261970, 2309254, 18019958, 50223152,
+               28972515, 24134069, 16848603, 53771797, 20002236 } },
+       {       { 24977353, 33240048, 58884894, 20089345, 28432342,
+               32378079, 54040059, 21257083, 44727879, 6618998 },      /* 3 * 16^12 */
+               { 9378160, 20414246, 44262881, 20809167, 28198280,
+               26310334, 64709179, 32837080, 690425, 14876244 },
+               { 65570671, 11685645, 12944378, 13682314, 42719353,
+               19141238, 8044828, 19737104, 32239828, 27901670 } },
+       {       { 34100715, 28339925, 34843976, 29869215, 9460460,
+               24227009, 42507207, 14506723, 21639561, 30924196 },     /* 4 * 16^12 */
+               { 48505798, 4762989, 66182614, 8885303, 38696384,
+               30367116, 9781646, 23204373, 32779358, 5095274 },
+               { 50707921, 20442216, 25239337, 15531969, 3987758,
+               29055114, 65819361, 26690896, 17874573, 558605 } },
+       {       { 44903700, 31034903, 50727262, 414690, 42089314,
+               2170429, 30634760, 25190818, 35108870, 27794547 },      /* 5 * 16^12 */
+               { 53508735, 10240080, 9171883, 16131053, 46239610,
+               9599699, 33499487, 5080151, 2085892, 5119761 },
+               { 60263160, 15791201, 8550074, 32241778, 29928808,
+               21462176, 27534429, 26362287, 44757485, 12961481 } },
+       {       { 55987368, 30172197, 2307365, 6362031, 66973409,
+               8868176, 50273234, 7031274, 7589640, 8945490 }, /* 6 * 16^12 */
+               { 42616785, 23983660, 10368193, 11582341, 43711571,
+               31309144, 16533929, 8206996, 36914212, 28394793 },
+               { 34956097, 8917966, 6661220, 21876816, 65916803,
+               17761038, 7251488, 22372252, 24099108, 19098262 } },
+       {       { 10853575, 10721687, 26480089, 5861829, 44113045,
+               1972174, 65242217, 22996533, 63745412, 27113307 },      /* 7 * 16^12 */
+               { 5019539, 25646962, 4244126, 18840076, 40175591,
+               6453164, 47990682, 20265406, 60876967, 23273695 },
+               { 50106456, 5906789, 221599, 26991285, 7828207,
+               20305514, 24362660, 31546264, 53242455, 7421391 } },
+       {       { 6267067, 9695052, 7709135, 16950835, 34239795,
+               31668296, 14795159, 25714308, 13746020, 31812384 },     /* 8 * 16^12 */
+               { 8139908, 27007935, 32257645, 27663886, 30375718,
+               1886181, 45933756, 15441251, 28826358, 29431403 },
+               { 28584883, 7787108, 60375922, 18503702, 22846040,
+               25983196, 63926927, 33190907, 4771361, 25134474 } },
+},
+{ /* 16^14 */
+       {       { 26514970, 4740088, 27912651, 3697550, 19331575,
+               22082093, 6809885, 4608608, 7325975, 18753361 },        /* 1 * 16^14 */
+               { 24949256, 6376279, 39642383, 25379823, 48462709,
+               23623825, 33543568, 21412737, 3569626, 11342593 },
+               { 55490446, 19000001, 42787651, 7655127, 65739590,
+               5214311, 39708324, 10258389, 49462170, 25367739 } },
+       {       { 66948081, 23228174, 44253547, 29249434, 46247496,
+               19933429, 34297962, 22372809, 51563772, 4387440 },      /* 2 * 16^14 */
+               { 11431185, 15823007, 26570245, 14329124, 18029990,
+               4796082, 35662685, 15580663, 9280358, 29580745 },
+               { 46309467, 12194511, 3937617, 27748540, 39954043,
+               9340369, 42594872, 8548136, 20617071, 26072431 } },
+       {       { 47253587, 31985546, 44906155, 8714033, 14007766,
+               6928528, 16318175, 32543743, 4766742, 3552007 },        /* 3 * 16^14 */
+               { 66170039, 29623845, 58394552, 16124717, 24603125,
+               27329039, 53333511, 21678609, 24345682, 10325460 },
+               { 45357481, 16823515, 1351762, 32751011, 63099193,
+               3950934, 3217514, 14481909, 10988822, 29559670 } },
+       {       { 57666574, 6624295, 36809900, 21640754, 62437882,
+               31497052, 31521203, 9614054, 37108040, 12074673 },      /* 4 * 16^14 */
+               { 15564307, 19242862, 3101242, 5684148, 30446780,
+               25503076, 12677126, 27049089, 58813011, 13296004 },
+               { 4771172, 33419193, 14290748, 20464580, 27992297,
+               14998318, 65694928, 31997715, 29832612, 17163397 } },
+       {       { 64810282, 2439669, 59642254, 1719964, 39841323,
+               17225986, 32512468, 28236839, 36752793, 29363474 },     /* 5 * 16^14 */
+               { 7064884, 26013258, 47946901, 28486894, 48217594,
+               30641695, 25825241, 5293297, 39986204, 13101589 },
+               { 37102324, 10162315, 33928688, 3981722, 50626726,
+               20484387, 14413973, 9515896, 19568978, 9628812 } },
+       {       { 48129987, 3884492, 19469877, 12726490, 15913552,
+               13614290, 44147131, 70103, 7463304, 4176122 },  /* 6 * 16^14 */
+               { 33053803, 199357, 15894591, 1583059, 27380243,
+               28973997, 49269969, 27447592, 60817077, 3437739 },
+               { 39984863, 10659916, 11482427, 17484051, 12771466,
+               26919315, 34389459, 28231680, 24216881, 5944158 } },
+       {       { 26942781, 31239115, 9129563, 28647825, 26024104,
+               11769399, 55590027, 6367193, 57381634, 4782139 },       /* 7 * 16^14 */
+               { 8894125, 7450974, 64444715, 23788679, 39028346,
+               21165316, 19345745, 14680796, 11632993, 5847885 },
+               { 19916442, 28726022, 44198159, 22140040, 25606323,
+               27581991, 33253852, 8220911, 6358847, 31680575 } },
+       {       { 19646058, 5720633, 55692158, 12814208, 11607948,
+               12749789, 14147075, 15156355, 45242033, 11835259 },     /* 8 * 16^14 */
+               { 801428, 31472730, 16569427, 11065167, 29875704,
+               96627, 7908388, 29073952, 53570360, 1387154 },
+               { 19299512, 1155910, 28703737, 14890794, 2925026,
+               7269399, 26121523, 15467869, 40548314, 5052482 } },
+},
+{ /* 16^16 */
+       {       { 32944382, 14922211, 44263970, 5188527, 21913450,
+               24834489, 4001464, 13238564, 60994061, 8653814 },       /* 1 * 16^16 */
+               { 64091413, 10058205, 1980837, 3964243, 22160966,
+               12322533, 60677741, 20936246, 12228556, 26550755 },
+               { 22865569, 28901697, 27603667, 21009037, 14348957,
+               8234005, 24808405, 5719875, 28483275, 2841751 } },
+       {       { 55452759, 10087520, 58243976, 28018288, 47830290,
+               30498519, 3999227, 13239134, 62331395, 19644223 },      /* 2 * 16^16 */
+               { 50687877, 32441126, 66781144, 21446575, 21886281,
+               18001658, 65220897, 33238773, 19932057, 20815229 },
+               { 1382174, 21859713, 17266789, 9194690, 53784508,
+               9720080, 20403944, 11284705, 53095046, 3093229 } },
+       {       { 45197768, 27626490, 62497547, 27994275, 35364760,
+               22769138, 24123613, 15193618, 45456747, 16815042 },     /* 3 * 16^16 */
+               { 16650902, 22516500, 66044685, 1570628, 58779118,
+               7352752, 66806440, 16271224, 43059443, 26862581 },
+               { 57172930, 29264984, 41829040, 4372841, 2087473,
+               10399484, 31870908, 14690798, 17361620, 11864968 } },
+       {       { 14668443, 21284197, 26039038, 15305210, 25515617,
+               4542480, 10453892, 6577524, 9145645, 27110552 },        /* 4 * 16^16 */
+               { 55801235, 6210371, 13206574, 5806320, 38091172,
+               19587231, 54777658, 26067830, 41530403, 17313742 },
+               { 5974855, 3053895, 57675815, 23169240, 35243739,
+               3225008, 59136222, 3936127, 61456591, 30504127 } },
+       {       { 63555773, 9865098, 61880298, 4272700, 61435032,
+               16864731, 14911343, 12196514, 45703375, 7047411 },      /* 5 * 16^16 */
+               { 30625386, 28825032, 41552902, 20761565, 46624288,
+               7695098, 17097188, 17250936, 39109084, 1803631 },
+               { 20093258, 9920966, 55970670, 28210574, 13161586,
+               12044805, 34252013, 4124600, 34765036, 23296865 } },
+       {       { 40289628, 30270716, 29965058, 3039786, 52635099,
+               2540456, 29457502, 14625692, 42289247, 12570231 },      /* 6 * 16^16 */
+               { 46320040, 14084653, 53577151, 7842146, 19119038,
+               19731827, 4752376, 24839792, 45429205, 2288037 },
+               { 66045306, 22002608, 16920317, 12494842, 1278292,
+               27685323, 45948920, 30055751, 55134159, 4724942 } },
+       {       { 23134274, 19275300, 56426866, 31942495, 20684484,
+               15770816, 54119114, 3190295, 26955097, 14109738 },      /* 7 * 16^16 */
+               { 17960970, 21778898, 62967895, 23851901, 58232301,
+               32143814, 54201480, 24894499, 37532563, 1903855 },
+               { 15308788, 5320727, 36995055, 19235554, 22902007,
+               7767164, 29425325, 22276870, 31960941, 11934971 } },
+       {       { 53949449, 9197840, 3875503, 24618324, 65725151,
+               27674630, 33518458, 16176658, 21432314, 12180697 },     /* 8 * 16^16 */
+               { 39713153, 8435795, 4109644, 12222639, 42480996,
+               14818668, 20638173, 4875028, 10491392, 1379718 },
+               { 55321537, 11500837, 13787581, 19721842, 44678184,
+               10140204, 1465425, 12689540, 56807545, 19681548 } },
+},
+{ /* 16^18 */
+       {       { 40771450, 19788269, 32496024, 19900513, 17847800,
+               20885276, 3604024, 8316894, 41233830, 23117073 },       /* 1 * 16^18 */
+               { 5414091, 18168391, 46101199, 9643569, 12834970,
+               1186149, 64485948, 32212200, 26128230, 6032912 },
+               { 3296484, 6223048, 24680646, 21307972, 44056843,
+               5903204, 58246567, 28915267, 12376616, 3188849 } },
+       {       { 52364359, 24245275, 735817, 32955454, 46701176,
+               28496527, 25246077, 17758763, 18640740, 32593455 },     /* 2 * 16^18 */
+               { 29190469, 18895386, 27549112, 32370916, 3520065,
+               22857131, 32049514, 26245319, 50999629, 23702124 },
+               { 60180029, 17123636, 10361373, 5642961, 4910474,
+               12345252, 35470478, 33060001, 10530746, 1053335 } },
+       {       { 44516310, 30409154, 64819587, 5953842, 53668675,
+               9425630, 25310643, 13003497, 64794073, 18408815 },      /* 3 * 16^18 */
+               { 37842897, 19367626, 53570647, 21437058, 47651804,
+               22899047, 35646494, 30605446, 24018830, 15026644 },
+               { 39688860, 32951110, 59064879, 31885314, 41016598,
+               13987818, 39811242, 187898, 43942445, 31022696 } },
+       {       { 29370903, 27500434, 7334070, 18212173, 9385286,
+               2247707, 53446902, 28714970, 30007387, 17731091 },      /* 4 * 16^18 */
+               { 45364466, 19743956, 1844839, 5021428, 56674465,
+               17642958, 9716666, 16266922, 62038647, 726098 },
+               { 66172485, 16086690, 23751945, 33011114, 65941325,
+               28365395, 9137108, 730663, 9835848, 4555336 } },
+       {       { 31117226, 21338698, 53606025, 6561946, 57231997,
+               20796761, 61990178, 29457725, 29120152, 13924425 },     /* 5 * 16^18 */
+               { 43732429, 1410445, 44855111, 20654817, 30867634,
+               15826977, 17693930, 544696, 55123566, 12422645 },
+               { 49707966, 19321222, 19675798, 30819676, 56101901,
+               27695611, 57724924, 22236731, 7240930, 33317044 } },
+       {       { 50424044, 19110186, 11038543, 11054958, 53307689,
+               30215898, 42789283, 7733546, 12796905, 27218610 },      /* 6 * 16^18 */
+               { 35747106, 22207651, 52101416, 27698213, 44655523,
+               21401660, 1222335, 4389483, 3293637, 18002689 },
+               { 58349431, 22736595, 41689999, 10783768, 36493307,
+               23807620, 38855524, 3647835, 3222231, 22393970 } },
+       {       { 9255298, 30423235, 54952701, 32550175, 13098012,
+               24339566, 16377219, 31451620, 47306788, 30519729 },     /* 7 * 16^18 */
+               { 18606113, 1693100, 41660478, 18384159, 4112352,
+               10045021, 23603893, 31506198, 59558087, 2484984 },
+               { 44379556, 7496159, 61366665, 11329248, 19991973,
+               30206930, 35390715, 9936965, 37011176, 22935634 } },
+       {       { 27736842, 10103576, 12500508, 8502413, 63695848,
+               23920873, 10436917, 32004156, 43449720, 25422331 },     /* 8 * 16^18 */
+               { 21878571, 28553135, 4338335, 13643897, 64071999,
+               13160959, 19708896, 5415497, 59748361, 29445138 },
+               { 19492550, 21450067, 37426887, 32701801, 63900692,
+               12403436, 30066266, 8367329, 13243957, 8709688 } },
+},
+{ /* 16^20 */
+       {       { 2831347, 21062286, 1478974, 6122054, 23825128,
+               20820846, 31097298, 6083058, 31021603, 23760822 },      /* 1 * 16^20 */
+               { 12015105, 2801261, 28198131, 10151021, 24818120,
+               28811299, 55914672, 27908697, 5150967, 7274186 },
+               { 64578913, 31324785, 445612, 10720828, 53259337,
+               22048494, 43601132, 16354464, 15067285, 19406725 } },
+       {       { 915865, 17085158, 15608284, 24765302, 42751837,
+               6060029, 49737545, 8410996, 59888403, 16527024 },       /* 2 * 16^20 */
+               { 7840923, 14037873, 33744001, 15934015, 66380651,
+               29911725, 21403987, 1057586, 47729402, 21151211 },
+               { 32922597, 32997445, 20336073, 17369864, 10903704,
+               28169945, 16957573, 52992, 23834301, 6588044 } },
+       {       { 62419196, 9166775, 41398568, 22707125, 11576751,
+               12733943, 7924251, 30802151, 1976122, 26305405 },       /* 3 * 16^20 */
+               { 32752011, 11232950, 3381995, 24839566, 22652987,
+               22810329, 17159698, 16689107, 46794284, 32248439 },
+               { 21251203, 16309901, 64125849, 26771309, 30810596,
+               12967303, 156041, 30183180, 12331344, 25317235 } },
+       {       { 31486061, 15114593, 52847614, 12951353, 14369431,
+               26166587, 16347320, 19892343, 8684154, 23021480 },      /* 4 * 16^20 */
+               { 8651595, 29077400, 51023227, 28557437, 13002506,
+               2950805, 29054427, 28447462, 10008135, 28886531 },
+               { 19443825, 11385320, 24468943, 23895364, 43189605,
+               2187568, 40845657, 27467510, 31316347, 14219878 } },
+       {       { 32382916, 1110093, 18477781, 11028262, 39697101,
+               26006320, 62128346, 10843781, 59151264, 19118701 },     /* 5 * 16^20 */
+               { 38514374, 1193784, 32245219, 11392485, 31092169,
+               15722801, 27146014, 6992409, 29126555, 9207390 },
+               { 2814918, 7836403, 27519878, 25686276, 46214848,
+               22000742, 45614304, 8550129, 28346258, 1994730 } },
+       {       { 36703732, 955510, 55975026, 18476362, 34661776,
+               20276352, 41457285, 3317159, 57165847, 930271 },        /* 6 * 16^20 */
+               { 47530565, 8085544, 53108345, 29605809, 2785837,
+               17323125, 47591912, 7174893, 22628102, 8115180 },
+               { 51805164, 26720662, 28856489, 1357446, 23421993,
+               1057177, 24091212, 32165462, 44343487, 22903716 } },
+       {       { 35139535, 2106402, 62372504, 1362500, 12813763,
+               16200670, 22981545, 27263159, 18009407, 17781660 },     /* 7 * 16^20 */
+               { 44357633, 28250434, 54201256, 20785565, 51297352,
+               25757378, 52269845, 17000211, 65241845, 8398969 },
+               { 49887941, 24009210, 39324209, 14166834, 29815394,
+               7444469, 29551787, 29827013, 19288548, 1325865 } },
+       {       { 20909212, 13023121, 57899112, 16251777, 61330449,
+               25459517, 12412150, 10018715, 2213263, 19676059 },      /* 8 * 16^20 */
+               { 15100138, 17718680, 43184885, 32549333, 40658671,
+               15509407, 12376730, 30075286, 33166106, 25511682 },
+               { 32529814, 22479743, 30361438, 16864679, 57972923,
+               1513225, 22922121, 6382134, 61341936, 8371347 } },
+},
+{ /* 16^22 */
+       {       { 44511638, 26541766, 8587002, 25296571, 4084308,
+               20584370, 361725, 2610596, 43187334, 22099236 },        /* 1 * 16^22 */
+               { 9923462, 11271500, 12616794, 3544722, 37110496,
+               31832805, 12891686, 25361300, 40665920, 10486143 },
+               { 5408392, 32417741, 62139741, 10561667, 24145918,
+               14240566, 31319731, 29318891, 19985174, 30118346 } },
+       {       { 58787919, 21504805, 31204562, 5839400, 46481576,
+               32497154, 47665921, 6922163, 12743482, 23753914 },      /* 2 * 16^22 */
+               { 53114407, 16616820, 14549246, 3341099, 32155958,
+               13648976, 49531796, 8849296, 65030, 8370684 },
+               { 64747493, 12678784, 28815050, 4759974, 43215817,
+               4884716, 23783145, 11038569, 18800704, 255233 } },
+       {       { 64172210, 22726896, 56676774, 14516792, 63468078,
+               4372540, 35173943, 2209389, 65584811, 2055793 },        /* 3 * 16^22 */
+               { 61839187, 31780545, 13957885, 7990715, 23132995,
+               728773, 13393847, 9066957, 19258688, 18800639 },
+               { 580882, 16705327, 5468415, 30871414, 36182444,
+               18858431, 59905517, 24560042, 37087844, 7394434 } },
+       {       { 13345610, 9759151, 3371034, 17416641, 16353038,
+               8577942, 31129804, 13496856, 58052846, 7402517 },       /* 4 * 16^22 */
+               { 23838809, 1822728, 51370421, 15242726, 8318092,
+               29821328, 45436683, 30062226, 62287122, 14799920 },
+               { 2286874, 29118501, 47066405, 31546095, 53412636,
+               5038121, 11006906, 17794080, 8205060, 1607563 } },
+       {       { 39420813, 1585952, 56333811, 931068, 37988643,
+               22552112, 52698034, 12029092, 9944378, 8024 },  /* 5 * 16^22 */
+               { 14414067, 25552300, 3331829, 30346215, 22249150,
+               27960244, 18364660, 30647474, 30019586, 24525154 },
+               { 4368715, 29844802, 29874199, 18531449, 46878477,
+               22143727, 50994269, 32555346, 58966475, 5640029 } },
+       {       { 27425505, 27835351, 3055005, 10660664, 23458024,
+               595578, 51710259, 32381236, 48766680, 9742716 },        /* 6 * 16^22 */
+               { 10299591, 13746483, 11661824, 16234854, 7630238,
+               5998374, 9809887, 16859868, 15219797, 19226649 },
+               { 6744077, 2427284, 26042789, 2720740, 66260958,
+               1118973, 32324614, 7406442, 12420155, 1994844 } },
+       {       { 16412671, 29047065, 10772640, 15929391, 50040076,
+               28895810, 10555944, 23070383, 37006495, 28815383 },     /* 7 * 16^22 */
+               { 14012502, 28529712, 48724410, 23975962, 40623521,
+               29617992, 54075385, 22644628, 24319928, 27108099 },
+               { 22397363, 25786748, 57815702, 20761563, 17166286,
+               23799296, 39775798, 6199365, 21880021, 21303672 } },
+       {       { 51661137, 709326, 60189418, 22684253, 37330941,
+               6522331, 45388683, 12130071, 52312361, 5005756 },       /* 8 * 16^22 */
+               { 62825557, 5368522, 35991846, 8163388, 36785801,
+               3209127, 16557151, 8890729, 8840445, 4957760 },
+               { 64994094, 19246303, 23019041, 15765735, 41839181,
+               6002751, 10183197, 20315106, 50713577, 31378319 } },
+},
+{ /* 16^24 */
+       {       { 3065054, 32141671, 41510189, 33192999, 49425798,
+               27851016, 58944651, 11248526, 63417650, 26140247 },     /* 1 * 16^24 */
+               { 48083108, 1632004, 13466291, 25559332, 43468412,
+               16573536, 35094956, 30497327, 22208661, 2000468 },
+               { 10379208, 27508878, 8877318, 1473647, 37817580,
+               21046851, 16690914, 2553332, 63976176, 16400288 } },
+       {       { 24158868, 12938817, 11085297, 25376834, 39045385,
+               29097348, 36532400, 64451, 60291780, 30861549 },        /* 2 * 16^24 */
+               { 15716668, 1254266, 48636174, 7446273, 58659946,
+               6344163, 45011593, 26268851, 26894936, 9132066 },
+               { 13488534, 7794716, 22236231, 5989356, 25426474,
+               20976224, 2350709, 30135921, 62420857, 2364225 } },
+       {       { 29004188, 25687351, 28661401, 32914020, 54314860,
+               25611345, 31863254, 29418892, 66830813, 17795152 },     /* 3 * 16^24 */
+               { 16335033, 9132434, 25640582, 6678888, 1725628,
+               8517937, 55301840, 21856974, 15445874, 25756331 },
+               { 60986784, 18687766, 38493958, 14569918, 56250865,
+               29962602, 10343411, 26578142, 37280576, 22738620 } },
+       {       { 20263915, 11434237, 61343429, 11236809, 13505955,
+               22697330, 50997518, 6493121, 47724353, 7639713 },       /* 4 * 16^24 */
+               { 27081650, 3463984, 14099042, 29036828, 1616302,
+               27348828, 29542635, 15372179, 17293797, 960709 },
+               { 64278047, 18715199, 25403037, 25339236, 58791851,
+               17380732, 18006286, 17510682, 29994676, 17746311 } },
+       {       { 12286395, 13076066, 45333675, 32377809, 42105665,
+               4057651, 35090736, 24663557, 16102006, 13205847 },      /* 5 * 16^24 */
+               { 9769828, 5202651, 42951466, 19923039, 39057860,
+               21992807, 42495722, 19693649, 35924288, 709463 },
+               { 13733362, 5599946, 10557076, 3195751, 61550873,
+               8536969, 41568694, 8525971, 10151379, 10394400 } },
+       {       { 51229064, 29029191, 58528116, 30620370, 14634844,
+               32856154, 57659786, 3137093, 55571978, 11721157 },      /* 6 * 16^24 */
+               { 4024660, 17416881, 22436261, 12276534, 58009849,
+               30868332, 19698228, 11743039, 33806530, 8934413 },
+               { 17555920, 28540494, 8268605, 2331751, 44370049,
+               9761012, 9319229, 8835153, 57903375, 32274386 } },
+       {       { 62038564, 12367916, 36445330, 3234472, 32617080,
+               25131790, 29880582, 20071101, 40210373, 25686972 },     /* 7 * 16^24 */
+               { 66647436, 25724417, 20614117, 16688288, 59594098,
+               28747312, 22300303, 505429, 6108462, 27371017 },
+               { 35133562, 5726538, 26934134, 10237677, 63935147,
+               32949378, 24199303, 3795095, 7592688, 18562353 } },
+       {       { 46458361, 21592935, 39872588, 570497, 3767144,
+               31836892, 13891941, 31985238, 13717173, 10805743 },     /* 8 * 16^24 */
+               { 21594432, 18590204, 17466407, 29477210, 32537083,
+               2739898, 6407723, 12018833, 38852812, 4298411 },
+               { 52432215, 17910135, 15287173, 11927123, 24177847,
+               25378864, 66312432, 14860608, 40169934, 27690595 } },
+},
+{ /* 16^26 */
+       {       { 18512060, 11319350, 46985740, 15090308, 18818594,
+               5271736, 44380960, 3666878, 43141434, 30255002 },       /* 1 * 16^26 */
+               { 12962541, 5311799, 57048096, 11658279, 18855286,
+               25600231, 13286262, 20745728, 62727807, 9882021 },
+               { 60319844, 30408388, 16192428, 13241070, 15898607,
+               19348318, 57023983, 26893321, 64705764, 5276064 } },
+       {       { 10342807, 3098505, 2119311, 193222, 25702612,
+               12233820, 23697382, 15056736, 46092426, 25352431 },     /* 2 * 16^26 */
+               { 30169808, 28236784, 26306205, 21803573, 27814963,
+               7069267, 7152851, 3684982, 1449224, 13082861 },
+               { 33958735, 3261607, 22745853, 7948688, 19370557,
+               18376767, 40936887, 6482813, 56808784, 22494330 } },
+       {       { 29506904, 4457497, 3377935, 23757988, 36598817,
+               12935079, 1561737, 3841096, 38105225, 26896789 },       /* 3 * 16^26 */
+               { 32869458, 28145887, 25609742, 15678670, 56421095,
+               18083360, 26112420, 2521008, 44444576, 6904814 },
+               { 10340844, 26924055, 48452231, 31276001, 12621150,
+               20215377, 30878496, 21730062, 41524312, 5181965 } },
+       {       { 45343161, 9916822, 65808455, 4079497, 66080518,
+               11909558, 1782390, 12641087, 20603771, 26992690 },      /* 4 * 16^26 */
+               { 25940096, 20896407, 17324187, 23247058, 58437395,
+               15029093, 24396252, 17103510, 64786011, 21165857 },
+               { 48226577, 21881051, 24849421, 11501709, 13161720,
+               28785558, 1925522, 11914390, 4662781, 7820689 } },
+       {       { 56758909, 18873868, 58896884, 2330219, 49446315,
+               19008651, 10658212, 6671822, 19012087, 3772772 },       /* 5 * 16^26 */
+               { 12241050, 33128450, 8132690, 9393934, 32846760,
+               31954812, 29749455, 12172924, 16136752, 15264020 },
+               { 3753511, 30133366, 10617073, 2028709, 14841030,
+               26832768, 28718731, 17791548, 20527770, 12988982 } },
+       {       { 50331161, 18301130, 57466446, 4978982, 3308785,
+               8755439, 6943197, 6461331, 41525717, 8991217 }, /* 6 * 16^26 */
+               { 52286360, 27757162, 63400876, 12689772, 66209881,
+               22639565, 42925817, 22989488, 3299664, 21129479 },
+               { 49882601, 1816361, 65435576, 27467992, 31783887,
+               25378441, 34160718, 7417949, 36866577, 1507264 } },
+       {       { 63627275, 8707080, 32188102, 5672294, 22096700,
+               1711240, 34088169, 9761486, 4170404, 31469107 },        /* 7 * 16^26 */
+               { 29692644, 6829891, 56610064, 4334895, 20945975,
+               21647936, 38221255, 8209390, 14606362, 22907359 },
+               { 55521375, 14855944, 62981086, 32022574, 40459774,
+               15084045, 22186522, 16002000, 52832027, 25153633 } },
+       {       { 59366301, 25297669, 52340529, 19898171, 43876480,
+               12387165, 4498947, 14147411, 29514390, 4302863 },       /* 8 * 16^26 */
+               { 62297408, 13761028, 35404987, 31070512, 63796392,
+               7869046, 59995292, 23934339, 13240844, 10965870 },
+               { 53695440, 21146572, 20757301, 19752600, 14785142,
+               8976368, 62047588, 31410058, 17846987, 19582505 } },
+},
+{ /* 16^28 */
+       {       { 57202067, 17484121, 21134159, 12198166, 40044289,
+               708125, 387813, 13770293, 47974538, 10958662 }, /* 1 * 16^28 */
+               { 64864412, 32799703, 62511833, 32488122, 60861691,
+               1455298, 45461136, 24339642, 61886162, 12650266 },
+               { 22470984, 12369526, 23446014, 28113323, 45588061,
+               23855708, 55336367, 21979976, 42025033, 4271861 } },
+       {       { 15854951, 4148314, 58214974, 7259001, 11666551,
+               13824734, 36577666, 2697371, 24154791, 24093489 },      /* 2 * 16^28 */
+               { 41939299, 23500789, 47199531, 15361594, 61124506,
+               2159191, 75375, 29275903, 34582642, 8469672 },
+               { 15446137, 17747788, 29759746, 14019369, 30811221,
+               23944241, 35526855, 12840103, 24913809, 9815020 } },
+       {       { 11933045, 9281483, 5081055, 28370608, 64480701,
+               28648802, 59381042, 22658328, 44380208, 16199063 },     /* 3 * 16^28 */
+               { 62399578, 27940162, 35267365, 21265538, 52665326,
+               10799413, 58005188, 13438768, 18735128, 9466238 },
+               { 14576810, 379472, 40322331, 25237195, 37682355,
+               22741457, 67006097, 1876698, 30801119, 2164795 } },
+       {       { 56818250, 29895392, 63822271, 10948817, 23037027,
+               3794475, 63638526, 20954210, 50053494, 3565903 },       /* 4 * 16^28 */
+               { 15995086, 3199873, 13672555, 13712240, 47730029,
+               28906785, 54027253, 18058162, 53616056, 1268051 },
+               { 29210069, 24135095, 61189071, 28601646, 10834810,
+               20226706, 50596761, 22733718, 39946641, 19523900 } },
+       {       { 61955989, 29753495, 57802388, 27482848, 16243068,
+               14684434, 41435776, 17373631, 13491505, 4641841 },      /* 5 * 16^28 */
+               { 53946955, 15508587, 16663704, 25398282, 38758921,
+               9019122, 37925443, 29785008, 2244110, 19552453 },
+               { 10813398, 643330, 47920349, 32825515, 30292061,
+               16954354, 27548446, 25833190, 14476988, 20787001 } },
+       {       { 35923332, 32741048, 22271203, 11835308, 10201545,
+               15351028, 17099662, 3988035, 21721536, 30405492 },      /* 6 * 16^28 */
+               { 10292079, 9984945, 6481436, 8279905, 59857350,
+               7032742, 27282937, 31910173, 39196053, 12651323 },
+               { 10202177, 27008593, 35735631, 23979793, 34958221,
+               25434748, 54202543, 3852693, 13216206, 14842320 } },
+       {       { 14465486, 19721101, 34974879, 18815558, 39665676,
+               12990491, 33046193, 15796406, 60056998, 25514317 },     /* 7 * 16^28 */
+               { 51293224, 22953365, 60569911, 26295436, 60124204,
+               26972653, 35608016, 13765823, 39674467, 9900183 },
+               { 30924398, 25274812, 6359015, 20738097, 16508376,
+               9071735, 41620263, 15413634, 9524356, 26535554 } },
+       {       { 64157555, 8903984, 17349946, 601635, 50676049,
+               28941875, 53376124, 17665097, 44850385, 4659090 },      /* 8 * 16^28 */
+               { 12274201, 20378885, 32627640, 31769106, 6736624,
+               13267305, 5237659, 28444949, 15663515, 4035784 },
+               { 50192582, 28601458, 36715152, 18395610, 20774811,
+               15897498, 5736189, 15026997, 64930608, 20098846 } },
+},
+{ /* 16^30 */
+       {       { 10226222, 27625730, 15139955, 120818, 52241171,
+               5218602, 32937275, 11551483, 50536904, 26111567 },      /* 1 * 16^30 */
+               { 58249865, 31335375, 28571665, 23398914, 66634396,
+               23448733, 63307367, 278094, 23440562, 33264224 },
+               { 17932739, 21117156, 43069306, 10749059, 11316803,
+               7535897, 22503767, 5561594, 63462240, 3898660 } },
+       {       { 26958440, 18896406, 4314585, 8346991, 61431100,
+               11960071, 34519569, 32934396, 36706772, 16838219 },     /* 2 * 16^30 */
+               { 7749907, 32584865, 50769132, 33537967, 42090752,
+               15122142, 65535333, 7152529, 21831162, 1245233 },
+               { 54942968, 9166946, 33491384, 13673479, 29787085,
+               13096535, 6280834, 14587357, 44770839, 13987524 } },
+       {       { 9681908, 26817309, 35157219, 13591837, 60225043,
+               386949, 31622781, 6439245, 52527852, 4091396 }, /* 3 * 16^30 */
+               { 42758936, 7778774, 21116000, 15572597, 62275598,
+               28196653, 62807965, 28429792, 59639082, 30696363 },
+               { 58682418, 1470726, 38999185, 31957441, 3978626,
+               28430809, 47486180, 12092162, 29077877, 18812444 } },
+       {       { 32264008, 18146780, 61721128, 32394338, 65017541,
+               29607531, 23104803, 20684524, 5727337, 189038 },        /* 4 * 16^30 */
+               { 5269168, 26694706, 53878652, 25533716, 25932562,
+               1763552, 61502754, 28048550, 47091016, 2357888 },
+               { 14609104, 24599962, 61108297, 16931650, 52531476,
+               25810533, 40363694, 10942114, 41219933, 18669734 } },
+       {       { 41534488, 11967825, 29233242, 12948236, 60354399,
+               4713226, 58167894, 14059179, 12878652, 8511905 },       /* 5 * 16^30 */
+               { 20513481, 5557931, 51504251, 7829530, 26413943,
+               31535028, 45729895, 7471780, 13913677, 28416557 },
+               { 41452044, 3393630, 64153449, 26478905, 64858154,
+               9366907, 36885446, 6812973, 5568676, 30426776 } },
+       {       { 27117677, 23547054, 35826092, 27984343, 1127281,
+               12772488, 37262958, 10483305, 55556115, 32525717 },     /* 6 * 16^30 */
+               { 11630004, 12144454, 2116339, 13606037, 27378885,
+               15676917, 49700111, 20050058, 52713667, 8070817 },
+               { 10637467, 27866368, 5674780, 1072708, 40765276,
+               26572129, 65424888, 9177852, 39615702, 15431202 } },
+       {       { 37084402, 5626925, 66557297, 23573344, 753597,
+               11981191, 25244767, 30314666, 63752313, 9594023 },      /* 7 * 16^30 */
+               { 20525126, 10892566, 54366392, 12779442, 37615830,
+               16150074, 38868345, 14943141, 52052074, 25618500 },
+               { 43356201, 2636869, 61944954, 23450613, 585133,
+               7877383, 11345683, 27062142, 13352334, 22577348 } },
+       {       { 20239939, 6607058, 6203985, 3483793, 48721888,
+               32775202, 46385121, 15077869, 44358105, 14523816 },     /* 8 * 16^30 */
+               { 65177046, 28146973, 3304648, 20669563, 17015805,
+               28677341, 37325013, 25801949, 53893326, 33235227 },
+               { 27406023, 27512775, 27423595, 29057038, 4996213,
+               10002360, 38266833, 29008937, 36936121, 28748764 } },
+},
+{ /* 16^32 */
+       {       { 54378055, 10311866, 1510375, 10778093, 64989409,
+               24408729, 32676002, 11149336, 40985213, 4985767 },      /* 1 * 16^32 */
+               { 11374242, 12660715, 17861383, 21013599, 10935567,
+               1099227, 53222788, 24462691, 39381819, 11358503 },
+               { 48012542, 341146, 60911379, 33315398, 15756972,
+               24757770, 66125820, 13794113, 47694557, 17933176 } },
+       {       { 1656478, 13457317, 15370807, 6364910, 13605745,
+               8362338, 47934242, 28078708, 50312267, 28522993 },      /* 2 * 16^32 */
+               { 6490062, 11940286, 25495923, 25828072, 8668372,
+               24803116, 3367602, 6970005, 65417799, 24549641 },
+               { 44835530, 20030007, 67044178, 29220208, 48503227,
+               22632463, 46537798, 26546453, 67009010, 23317098 } },
+       {       { 31932008, 28568291, 47496481, 16366579, 22023614,
+               88450, 11371999, 29810185, 4882241, 22927527 }, /* 3 * 16^32 */
+               { 17747446, 10039260, 19368299, 29503841, 46478228,
+               17513145, 31992682, 17696456, 37848500, 28042460 },
+               { 29796488, 37186, 19818052, 10115756, 55279832,
+               3352735, 18551198, 3272828, 61917932, 29392022 } },
+       {       { 6384877, 2899513, 17807477, 7663917, 64749976,
+               12363164, 25366522, 24980540, 66837568, 12071498 },     /* 4 * 16^32 */
+               { 12501267, 4044383, 58495907, 20162046, 34678811,
+               5136598, 47878486, 30024734, 330069, 29895023 },
+               { 58743349, 29511910, 25133447, 29037077, 60897836,
+               2265926, 34339246, 1936674, 61949167, 3829362 } },
+       {       { 56041645, 11871230, 27385719, 22994888, 62522949,
+               22365119, 10004785, 24844944, 45347639, 8930323 },      /* 5 * 16^32 */
+               { 28425966, 27718999, 66531773, 28857233, 52891308,
+               6870929, 7921550, 26986645, 26333139, 14267664 },
+               { 45911060, 17158396, 25654215, 31829035, 12282011,
+               11008919, 1541940, 4757911, 40617363, 17145491 } },
+       {       { 49686272, 15157789, 18705543, 29619, 24409717,
+               33293956, 27361680, 9257833, 65152338, 31777517 },      /* 6 * 16^32 */
+               { 13537262, 25794942, 46504023, 10961926, 61186044,
+               20336366, 53952279, 6217253, 51165165, 13814989 },
+               { 42063564, 23362465, 15366584, 15166509, 54003778,
+               8423555, 37937324, 12361134, 48422886, 4578289 } },
+       {       { 60580251, 31142934, 9442965, 27628844, 12025639,
+               32067012, 64127349, 31885225, 13006805, 2355433 },      /* 7 * 16^32 */
+               { 24579768, 3711570, 1342322, 22374306, 40103728,
+               14124955, 44564335, 14074918, 21964432, 8235257 },
+               { 50803946, 19949172, 60476436, 28412082, 16974358,
+               22643349, 27202043, 1719366, 1141648, 20758196 } },
+       {       { 11423316, 28086373, 32344215, 8962751, 24989809,
+               9241752, 53843611, 16086211, 38367983, 17912338 },      /* 8 * 16^32 */
+               { 54244920, 20334445, 58790597, 22536340, 60298718,
+               28710537, 13475065, 30420460, 32674894, 13715045 },
+               { 65699196, 12530727, 60740138, 10847386, 19531186,
+               19422272, 55399715, 7791793, 39862921, 4383346 } },
+},
+{ /* 16^34 */
+       {       { 51914908, 5362277, 65324971, 2695833, 4960227,
+               12840725, 23061898, 3260492, 22510453, 8577507 },       /* 1 * 16^34 */
+               { 38137966, 5271446, 65842855, 23817442, 54653627,
+               16732598, 62246457, 28647982, 27193556, 6245191 },
+               { 54476394, 11257345, 34415870, 13548176, 66387860,
+               10879010, 31168030, 13952092, 37537372, 29918525 } },
+       {       { 50833043, 14667796, 15906460, 12155291, 44997715,
+               24514713, 32003001, 24722143, 5773084, 25132323 },      /* 2 * 16^34 */
+               { 3877321, 23981693, 32416691, 5405324, 56104457,
+               19897796, 3759768, 11935320, 5611860, 8164018 },
+               { 43320746, 25300131, 1950874, 8937633, 18686727,
+               16459170, 66203139, 12376319, 31632953, 190926 } },
+       {       { 8884438, 27670423, 6023973, 10104341, 60227295,
+               28612898, 18722940, 18768427, 65436375, 827624 },       /* 3 * 16^34 */
+               { 42515238, 17415546, 58684872, 13378745, 14162407,
+               6901328, 58820115, 4508563, 41767309, 29926903 },
+               { 34388281, 17265135, 34605316, 7101209, 13354605,
+               2659080, 65308289, 19446395, 42230385, 1541285 } },
+       {       { 27019610, 12299467, 53450576, 31951197, 54247203,
+               28692960, 47568713, 28538373, 29439640, 15138866 },     /* 4 * 16^34 */
+               { 2901328, 32436745, 3880375, 23495044, 49487923,
+               29941650, 45306746, 29986950, 20456844, 31669399 },
+               { 21536104, 26928012, 34661045, 22864223, 44700786,
+               5175813, 61688824, 17193268, 7779327, 109896 } },
+       {       { 26572828, 3405927, 35407164, 12890904, 47843196,
+               5335865, 60615096, 2378491, 4439158, 20275085 },        /* 5 * 16^34 */
+               { 30279725, 14648750, 59063993, 6425557, 13639621,
+               32810923, 28698389, 12180118, 23177719, 33000357 },
+               { 44392139, 3489069, 57883598, 33221678, 18875721,
+               32414337, 14819433, 20822905, 49391106, 28092994 } },
+       {       { 48635543, 16596774, 66727204, 15663610, 22860960,
+               15585581, 39264755, 29971692, 43848403, 25125843 },     /* 6 * 16^34 */
+               { 62052362, 16566550, 15953661, 3767752, 56672365,
+               15627059, 66287910, 2177224, 8550082, 18440267 },
+               { 34628313, 15707274, 58902952, 27902350, 29464557,
+               2713815, 44383727, 15860481, 45206294, 1494192 } },
+       {       { 38643965, 1553204, 32536856, 23080703, 42417258,
+               33148257, 58194238, 30620535, 37205105, 15553882 },     /* 7 * 16^34 */
+               { 47546773, 19467038, 41524991, 24254879, 13127841,
+               759709, 21923482, 16529112, 8742704, 12967017 },
+               { 21877890, 3230008, 9881174, 10539357, 62311749,
+               2841331, 11543572, 14513274, 19375923, 20906471 } },
+       {       { 29306751, 5123106, 20245049, 19404543, 9592565,
+               8447059, 65031740, 30564351, 15511448, 4789663 },       /* 8 * 16^34 */
+               { 8832269, 19058947, 13253510, 5137575, 5037871,
+               4078777, 24880818, 27331716, 2862652, 9455043 },
+               { 46429108, 7004546, 8824831, 24119455, 63063159,
+               29803695, 61354101, 108892, 23513200, 16652362 } },
+},
+{ /* 16^36 */
+       {       { 2756062, 8598110, 7383731, 26694540, 22312758,
+               32449420, 21179800, 2600940, 57120566, 21047965 },      /* 1 * 16^36 */
+               { 33852691, 4144781, 62632835, 26975308, 10770038,
+               26398890, 60458447, 20618131, 48789665, 10212859 },
+               { 42463153, 13317461, 36659605, 17900503, 21365573,
+               22684775, 11344423, 864440, 64609187, 16844368 } },
+       {       { 65784982, 3911312, 60160120, 14759764, 37081714,
+               7851206, 21690126, 8518463, 26699843, 5276295 },        /* 2 * 16^36 */
+               { 40676061, 6148328, 49924452, 19080277, 18782928,
+               33278435, 44547329, 211299, 2719757, 4940997 },
+               { 53958991, 27125364, 9396248, 365013, 24703301,
+               23065493, 1321585, 149635, 51656090, 7159368 } },
+       {       { 18155857, 17049442, 19744715, 9006923, 15154154,
+               23015456, 24256459, 28689437, 44560690, 9334108 },      /* 3 * 16^36 */
+               { 9987761, 30149673, 17507961, 9505530, 9731535,
+               31388918, 22356008, 8312176, 22477218, 25151047 },
+               { 2986088, 28642539, 10776627, 30080588, 10620589,
+               26471229, 45695018, 14253544, 44521715, 536905 } },
+       {       { 47766460, 867879, 9277171, 30335973, 52677291,
+               31567988, 19295825, 17757482, 6378259, 699185 },        /* 4 * 16^36 */
+               { 4377737, 8115836, 24567078, 15495314, 11625074,
+               13064599, 7390551, 10589625, 10838060, 18134008 },
+               { 7895007, 4057113, 60027092, 20476675, 49222032,
+               33231305, 66392824, 15693154, 62063800, 20180469 } },
+       {       { 10188286, 17783598, 59772502, 13427542, 22223443,
+               14896287, 30743455, 7116568, 45322357, 5427592 },       /* 5 * 16^36 */
+               { 59371282, 27685029, 52542544, 26147512, 11385653,
+               13201616, 31730678, 22591592, 63190227, 23885106 },
+               { 696102, 13206899, 27047647, 22922350, 15285304,
+               23701253, 10798489, 28975712, 19236242, 12477404 } },
+       {       { 17800790, 19518253, 40108434, 21787760, 23887826,
+               3149671, 23466177, 23016261, 10322026, 15313801 },      /* 6 * 16^36 */
+               { 55879425, 11243795, 50054594, 25513566, 66320635,
+               25386464, 63211194, 11180503, 43939348, 7733643 },
+               { 26246234, 11968874, 32263343, 28085704, 6830754,
+               20231401, 51314159, 33452449, 42659621, 10890803 } },
+       {       { 66522290, 10376443, 34522450, 22268075, 19801892,
+               10997610, 2276632, 9482883, 316878, 13820577 }, /* 7 * 16^36 */
+               { 35743198, 10271362, 54448239, 27287163, 16690206,
+               20491888, 52126651, 16484930, 25180797, 28219548 },
+               { 57226037, 29044064, 64993357, 16457135, 56008783,
+               11674995, 30756178, 26039378, 30696929, 29841583 } },
+       {       { 58253184, 15927860, 9866406, 29905021, 64711949,
+               16898650, 36699387, 24419436, 25112946, 30627788 },     /* 8 * 16^36 */
+               { 32988917, 23951020, 12499365, 7910787, 56491607,
+               21622917, 59766047, 23569034, 34759346, 7392472 },
+               { 64604801, 33117465, 25621773, 27875660, 15085041,
+               28074555, 42223985, 20028237, 5537437, 19640113 } },
+},
+{ /* 16^38 */
+       {       { 57475529, 116425, 26083934, 2897444, 60744427,
+               30866345, 609720, 15878753, 60138459, 24519663 },       /* 1 * 16^38 */
+               { 55883280, 2320284, 57524584, 10149186, 33664201,
+               5808647, 52232613, 31824764, 31234589, 6090599 },
+               { 39351007, 247743, 51914090, 24551880, 23288160,
+               23542496, 43239268, 6503645, 20650474, 1804084 } },
+       {       { 51801891, 2839643, 22530074, 10026331, 4602058,
+               5048462, 28248656, 5031932, 55733782, 12714368 },       /* 2 * 16^38 */
+               { 39519059, 15456423, 8972517, 8469608, 15640622,
+               4439847, 3121995, 23224719, 27842615, 33352104 },
+               { 20807691, 26283607, 29286140, 11421711, 39232341,
+               19686201, 45881388, 1035545, 47375635, 12796919 } },
+       {       { 34747315, 5457596, 28548107, 7833186, 7303070,
+               21600887, 42745799, 17632556, 33734809, 2771024 },      /* 3 * 16^38 */
+               { 12076880, 19253146, 58323862, 21705509, 42096072,
+               16400683, 49517369, 20654993, 3480664, 18371617 },
+               { 45719598, 421931, 26597266, 6860826, 22486084,
+               26817260, 49971378, 29344205, 42556581, 15673396 } },
+       {       { 6120100, 814863, 55314462, 32931715, 6812204,
+               17806661, 2019593, 7975683, 31123697, 22595451 },       /* 4 * 16^38 */
+               { 46924223, 2338215, 19788685, 23933476, 63107598,
+               24813538, 46837679, 4733253, 3727144, 20619984 },
+               { 30069250, 22119100, 30434653, 2958439, 18399564,
+               32578143, 12296868, 9204260, 50676426, 9648164 } },
+       {       { 17219846, 2375039, 35537917, 27978816, 47649184,
+               9219902, 294711, 15298639, 2662509, 17257359 }, /* 5 * 16^38 */
+               { 32705413, 32003455, 30705657, 7451065, 55303258,
+               9631812, 3305266, 5248604, 41100532, 22176930 },
+               { 65935918, 25995736, 62742093, 29266687, 45762450,
+               25120105, 32087528, 32331655, 32247247, 19164571 } },
+       {       { 65680039, 23875441, 57873182, 6549686, 59725795,
+               33085767, 23046501, 9803137, 17597934, 2346211 },       /* 6 * 16^38 */
+               { 14312609, 1221556, 17395390, 24854289, 62163122,
+               24869796, 38911119, 23916614, 51081240, 20175586 },
+               { 18510781, 15337574, 26171504, 981392, 44867312,
+               7827555, 43617730, 22231079, 3059832, 21771562 } },
+       {       { 33114149, 17665080, 40583177, 20211034, 33076704,
+               8716171, 1151462, 1521897, 66126199, 26716628 },        /* 7 * 16^38 */
+               { 10141598, 6082907, 17829293, 31606789, 9830091,
+               13613136, 41552228, 28009845, 33606651, 3592095 },
+               { 34169699, 29298616, 23947180, 33230254, 34035889,
+               21248794, 50471177, 3891703, 26353178, 693168 } },
+       {       { 52738210, 25781902, 1510300, 6434173, 48324075,
+               27291703, 32732229, 20445593, 17901440, 16011505 },     /* 8 * 16^38 */
+               { 30374239, 1595580, 50224825, 13186930, 4600344,
+               406904, 9585294, 33153764, 31375463, 14369965 },
+               { 18171223, 21619806, 54608461, 15197121, 56070717,
+               18324396, 47936623, 17508055, 8764034, 12309598 } },
+},
+{ /* 16^40 */
+       {       { 5811932, 31839139, 3442886, 31285122, 48741515,
+               25194890, 49064820, 18144304, 61543482, 12348899 },     /* 1 * 16^40 */
+               { 5975889, 28311244, 47649501, 23872684, 55567586,
+               14015781, 43443107, 1228318, 17544096, 22960650 },
+               { 35709185, 11407554, 25755363, 6891399, 63851926,
+               14872273, 42259511, 8141294, 56476330, 32968952 } },
+       {       { 8247747, 26843490, 40546482, 25845122, 52706924,
+               18905521, 4652151, 2488540, 23550156, 33283200 },       /* 2 * 16^40 */
+               { 54433560, 694025, 62032719, 13300343, 14015258,
+               19103038, 57410191, 22225381, 30944592, 1130208 },
+               { 17294297, 29765994, 7026747, 15626851, 22990044,
+               113481, 2267737, 27646286, 66700045, 33416712 } },
+       {       { 62198760, 20221544, 18550886, 10864893, 50649539,
+               26262835, 44079994, 20349526, 54360141, 2701325 },      /* 3 * 16^40 */
+               { 16091066, 17300506, 18599251, 7340678, 2137637,
+               32332775, 63744702, 14550935, 3260525, 26388161 },
+               { 58534169, 16099414, 4629974, 17213908, 46322650,
+               27548999, 57090500, 9276970, 11329923, 1862132 } },
+       {       { 8894987, 30108338, 6150752, 3013931, 301220,
+               15693451, 35127648, 30644714, 51670695, 11595569 },     /* 4 * 16^40 */
+               { 14763057, 17650824, 36190593, 3689866, 3511892,
+               10313526, 45157776, 12219230, 58070901, 32614131 },
+               { 15214943, 3537601, 40870142, 19495559, 4418656,
+               18323671, 13947275, 10730794, 53619402, 29190761 } },
+       {       { 54642373, 4195083, 57897332, 550903, 51543527,
+               12917919, 19118110, 33114591, 36574330, 19216518 },     /* 5 * 16^40 */
+               { 64570558, 7682792, 32759013, 263109, 37124133,
+               25598979, 44776739, 23365796, 977107, 699994 },
+               { 31788442, 19046775, 4799988, 7372237, 8808585,
+               18806489, 9408236, 23502657, 12493931, 28145115 } },
+       {       { 842132, 30759739, 62345482, 24831616, 26332017,
+               21148791, 11831879, 6985184, 57168503, 2854095 },       /* 6 * 16^40 */
+               { 41428258, 5260743, 47873055, 27269961, 63412921,
+               16566086, 27218280, 2607121, 29375955, 6024730 },
+               { 62261602, 25585100, 2516241, 27706719, 9695690,
+               26333246, 16512644, 960770, 12121869, 16648078 } },
+       {       { 47820798, 4453151, 15298546, 17376044, 22115042,
+               17581828, 12544293, 20083975, 1068880, 21054527 },      /* 7 * 16^40 */
+               { 51890212, 14667095, 53772635, 2013716, 30598287,
+               33090295, 35603941, 25672367, 20237805, 2838411 },
+               { 57549981, 17035596, 33238497, 13506958, 30505848,
+               32439836, 58621956, 30924378, 12521377, 4845654 } },
+       {       { 43547042, 6230155, 46726851, 10655313, 43068279,
+               21933259, 10477733, 32314216, 63995636, 13974497 },     /* 8 * 16^40 */
+               { 38910324, 10744107, 64150484, 10199663, 7759311,
+               20465832, 3409347, 32681032, 60626557, 20668561 },
+               { 12966261, 15550616, 35069916, 31939085, 21025979,
+               32924988, 5642324, 7188737, 18895762, 12629579 } },
+},
+{ /* 16^42 */
+       {       { 10758205, 15755439, 62598914, 9243697, 62229442,
+               6879878, 64904289, 29988312, 58126794, 4429646 },       /* 1 * 16^42 */
+               { 14741879, 18607545, 22177207, 21833195, 1279740,
+               8058600, 11758140, 789443, 32195181, 3895677 },
+               { 64654951, 15725972, 46672522, 23143759, 61304955,
+               22514211, 59972993, 21911536, 18047435, 18272689 } },
+       {       { 21987233, 700364, 42603816, 14972007, 59334599,
+               27836036, 32155025, 2581431, 37149879, 8773374 },       /* 2 * 16^42 */
+               { 41935844, 22247266, 29759955, 11776784, 44846481,
+               17733976, 10993113, 20703595, 49488162, 24145963 },
+               { 41540495, 454462, 53896929, 16126714, 25240068,
+               8594567, 20656846, 12017935, 59234475, 19634276 } },
+       {       { 54829870, 16624276, 987579, 27631834, 32908202,
+               1248608, 7719845, 29387734, 28408819, 6816612 },        /* 3 * 16^42 */
+               { 6028163, 6263078, 36097058, 22252721, 66289944,
+               2461771, 35267690, 28086389, 65387075, 30777706 },
+               { 56750770, 25316602, 19549650, 21385210, 22082622,
+               16147817, 20613181, 13982702, 56769294, 5067942 } },
+       {       { 30528792, 3601899, 65151774, 4619784, 39747042,
+               18118043, 24180792, 20984038, 27679907, 31905504 },     /* 4 * 16^42 */
+               { 36602878, 29732664, 12074680, 13582412, 47230892,
+               2443950, 47389578, 12746131, 5331210, 23448488 },
+               { 9402385, 19597367, 32834042, 10838634, 40528714,
+               20317236, 26653273, 24868867, 22611443, 20839026 } },
+       {       { 58798126, 30600981, 58846284, 30166382, 56707132,
+               33282502, 13424425, 29987205, 26404408, 13001963 },     /* 5 * 16^42 */
+               { 22190590, 1118029, 22736441, 15130463, 36648172,
+               27563110, 19189624, 28905490, 4854858, 6622139 },
+               { 35867026, 18138731, 64114613, 8939345, 11562230,
+               20713762, 41044498, 21932711, 51703708, 11020692 } },
+       {       { 66660290, 31776765, 13018550, 3194501, 57528444,
+               22392694, 24760584, 29207344, 25577410, 20175752 },     /* 6 * 16^42 */
+               { 1866042, 25604943, 59210214, 23253421, 12483314,
+               13477547, 3175636, 21130269, 28761761, 1406734 },
+               { 42818486, 4759344, 66418211, 31701615, 2066746,
+               10693769, 37513074, 9884935, 57739938, 4745409 } },
+       {       { 50547351, 14112679, 59096219, 4817317, 59068400,
+               22139825, 44255434, 10856640, 46638094, 13434653 },     /* 7 * 16^42 */
+               { 57967561, 6049713, 47577803, 29213020, 35848065,
+               9944275, 51646856, 22242579, 10931923, 21622501 },
+               { 22759470, 23480998, 50342599, 31683009, 13637441,
+               23386341, 1765143, 20900106, 28445306, 28189722 } },
+       {       { 40903181, 11014232, 57266213, 30918946, 40200743,
+               7532293, 48391976, 24018933, 3843902, 9367684 },        /* 8 * 16^42 */
+               { 29875063, 12493613, 2795536, 29768102, 1710619,
+               15181182, 56913147, 24765756, 9074233, 1167180 },
+               { 56139269, 27150720, 9591133, 9582310, 11349256,
+               108879, 16235123, 8601684, 66969667, 4242894 } },
+},
+{ /* 16^44 */
+       {       { 56051142, 3042015, 13770083, 24296510, 584235,
+               33009577, 59338006, 2602724, 39757248, 14247412 },      /* 1 * 16^44 */
+               { 22092954, 20363309, 65066070, 21585919, 32186752,
+               22037044, 60534522, 2470659, 39691498, 16625500 },
+               { 6314156, 23289540, 34336361, 15957556, 56951134,
+               168749, 58490057, 14290060, 27108877, 32373552 } },
+       {       { 22833421, 9293594, 34459416, 19935764, 57971897,
+               14756818, 44180005, 19583651, 56629059, 17356469 },     /* 2 * 16^44 */
+               { 58522267, 26383465, 13241781, 10960156, 34117849,
+               19759835, 33547975, 22495543, 39960412, 981873 },
+               { 59340277, 3326785, 38997067, 10783823, 19178761,
+               14905060, 22680049, 13906969, 51175174, 3797898 } },
+       {       { 9209251, 18419377, 53852306, 27386633, 66377847,
+               15289672, 25947805, 15286587, 30997318, 26851369 },     /* 3 * 16^44 */
+               { 21721337, 29341686, 54902740, 9310181, 63226625,
+               19901321, 23740223, 30845200, 20491982, 25512280 },
+               { 7392013, 16618386, 23946583, 25514540, 53843699,
+               32020573, 52911418, 31232855, 17649997, 33304352 } },
+       {       { 49550191, 1763593, 33994528, 15908609, 37067994,
+               21380136, 7335079, 25082233, 63934189, 3440182 },       /* 4 * 16^44 */
+               { 57807776, 19360604, 30609525, 30504889, 41933794,
+               32270679, 51867297, 24028707, 64875610, 7662145 },
+               { 47219164, 27577423, 42997570, 23865561, 10799742,
+               16982475, 40449, 29122597, 4862399, 1133 } },
+       {       { 63335436, 31988495, 28985339, 7499440, 24445838,
+               9325937, 29727763, 16527196, 18278453, 15405622 },      /* 5 * 16^44 */
+               { 34252636, 25680474, 61686474, 14860949, 50789833,
+               7956141, 7258061, 311861, 36513873, 26175010 },
+               { 62726958, 8508651, 47210498, 29880007, 61124410,
+               15149969, 53795266, 843522, 45233802, 13626196 } },
+       {       { 31727126, 26374577, 48671360, 25270779, 2875792,
+               17164102, 41838969, 26539605, 43656557, 5964752 },      /* 6 * 16^44 */
+               { 2281448, 20067377, 56193445, 30944521, 1879357,
+               16164207, 56324982, 3953791, 13340839, 15928663 },
+               { 4100401, 27594980, 49929526, 6017713, 48403027,
+               12227140, 40424029, 11344143, 2538215, 25983677 } },
+       {       { 40304287, 4260918, 11851389, 9658551, 35091757,
+               16367491, 46903439, 20363143, 11659921, 22439314 },     /* 7 * 16^44 */
+               { 57675240, 6123112, 11159803, 31397824, 30016279,
+               14966241, 46633881, 1485420, 66479608, 17595569 },
+               { 26180377, 10015009, 36264640, 24973138, 5418196,
+               9480663, 2231568, 23384352, 33100371, 32248261 } },
+       {       { 16166467, 24070699, 56004733, 6023907, 35182066,
+               32189508, 2340059, 17299464, 56373093, 23514607 },      /* 8 * 16^44 */
+               { 15121094, 28352561, 56718958, 15427820, 39598927,
+               17561924, 21670946, 4486675, 61177054, 19088051 },
+               { 28042865, 29997343, 54982337, 12259705, 63391366,
+               26608532, 6766452, 24864833, 18036435, 5803270 } },
+},
+{ /* 16^46 */
+       {       { 36077558, 19298237, 17332028, 31170912, 31312681,
+               27587249, 696308, 50292, 47013125, 11763583 },  /* 1 * 16^46 */
+               { 66291264, 6763911, 11803561, 1585585, 10958447,
+               30883267, 23855390, 4598332, 60949433, 19436993 },
+               { 66514282, 31040148, 34874710, 12643979, 12650761,
+               14811489, 665117, 20940800, 47335652, 22840869 } },
+       {       { 18357166, 26559999, 7766381, 16342475, 37783946,
+               411173, 14578841, 8080033, 55534529, 22952821 },        /* 2 * 16^46 */
+               { 30464590, 22291560, 62981387, 20819953, 19835326,
+               26448819, 42712688, 2075772, 50088707, 992470 },
+               { 19598397, 10334610, 12555054, 2555664, 18821899,
+               23214652, 21873262, 16014234, 26224780, 16452269 } },
+       {       { 14187449, 3448569, 56472628, 22743496, 44444983,
+               30120835, 7268409, 22663988, 27394300, 12015369 },      /* 3 * 16^46 */
+               { 36884939, 5145195, 5944548, 16385966, 3976735,
+               2009897, 55731060, 25936245, 46575034, 3698649 },
+               { 19695742, 16087646, 28032085, 12999827, 6817792,
+               11427614, 20244189, 32241655, 53849736, 30151970 } },
+       {       { 61389038, 22309106, 65198214, 15569034, 26642876,
+               25966672, 61319509, 18435777, 62132699, 12651792 },     /* 4 * 16^46 */
+               { 30860084, 12735208, 65220619, 28854697, 50133957,
+               2256939, 58942851, 12298311, 58558340, 23160969 },
+               { 64260450, 9953420, 11531313, 28271553, 26895122,
+               20857343, 53990043, 17036529, 9768697, 31021214 } },
+       {       { 18860224, 15980149, 48121624, 31991861, 40875851,
+               22482575, 59264981, 13944023, 42736516, 16582018 },     /* 5 * 16^46 */
+               { 42389405, 1894650, 66821166, 28850346, 15348718,
+               25397902, 32767512, 12765450, 4940095, 10678226 },
+               { 51604604, 4970267, 37215820, 4175592, 46115652,
+               31354675, 55404809, 15444559, 56105103, 7989036 } },
+       {       { 49800177, 17674491, 35586086, 33551600, 34221481,
+               16375548, 8680158, 17182719, 28550067, 26697300 },      /* 6 * 16^46 */
+               { 31490433, 5568061, 64696061, 2182382, 34772017,
+               4531685, 35030595, 6200205, 47422751, 18754260 },
+               { 38981977, 27866340, 16837844, 31733974, 60258182,
+               12700015, 37068883, 4364037, 1155602, 5988841 } },
+       {       { 33972757, 23041680, 9975415, 6841041, 35549071,
+               16356535, 3070187, 26528504, 1466168, 10740210 },       /* 7 * 16^46 */
+               { 21890435, 20281525, 54484852, 12154348, 59276991,
+               15300495, 23148983, 29083951, 24618406, 8283181 },
+               { 65599446, 18066246, 53605478, 22898515, 32799043,
+               909394, 53169961, 27774712, 34944214, 18227391 } },
+       {       { 24740822, 5052253, 37014733, 8961360, 25877428,
+               6165135, 42740684, 14397371, 59728495, 27410326 },      /* 8 * 16^46 */
+               { 3960804, 19286629, 39082773, 17636380, 47704005,
+               13146867, 15567327, 951507, 63848543, 32980496 },
+               { 38220480, 3510802, 39005586, 32395953, 55870735,
+               22922977, 51667400, 19101303, 65483377, 27059617 } },
+},
+{ /* 16^48 */
+       {       { 5666214, 525582, 20782575, 25516013, 42570364,
+               14657739, 16099374, 1468826, 60937436, 18367850 },      /* 1 * 16^48 */
+               { 793280, 24323954, 8836301, 27318725, 39747955,
+               31184838, 33152842, 28669181, 57202663, 32932579 },
+               { 62249590, 29775088, 64191105, 26806412, 7778749,
+               11688288, 36704511, 23683193, 65549940, 23690785 } },
+       {       { 10566929, 12612572, 35164652, 11118702, 54475488,
+               12362878, 21752402, 8822496, 24003793, 14264025 },      /* 2 * 16^48 */
+               { 10896313, 25834728, 824274, 472601, 47648556,
+               3009586, 25248958, 14783338, 36527388, 17796587 },
+               { 27713843, 26198459, 56100623, 9227529, 27050101,
+               2504721, 23886875, 20436907, 13958494, 27821979 } },
+       {       { 4646495, 25543308, 44342840, 22021777, 23184552,
+               8566613, 31366726, 32173371, 52042079, 23179239 },      /* 3 * 16^48 */
+               { 43627235, 4867225, 39861736, 3900520, 29838369,
+               25342141, 35219464, 23512650, 7340520, 18144364 },
+               { 49838347, 12723031, 50115803, 14878793, 21619651,
+               27356856, 27584816, 3093888, 58265170, 3849920 } },
+       {       { 55051311, 22376525, 21115584, 20189277, 8808711,
+               21523724, 16489529, 13378448, 41263148, 12741425 },     /* 4 * 16^48 */
+               { 58043933, 2103171, 25561640, 18428694, 61869039,
+               9582957, 32477045, 24536477, 5002293, 18004173 },
+               { 61162478, 10645102, 36197278, 15390283, 63821882,
+               26435754, 24306471, 15852464, 28834118, 25908360 } },
+       {       { 13669229, 17458950, 54626889, 23351392, 52539093,
+               21661233, 42112877, 11293806, 38520660, 24132599 },     /* 5 * 16^48 */
+               { 49773116, 24447374, 42577584, 9434952, 58636780,
+               32971069, 54018092, 455840, 20461858, 5491305 },
+               { 28497909, 6272777, 34085870, 14470569, 8906179,
+               32328802, 18504673, 19389266, 29867744, 24758489 } },
+       {       { 24191359, 16712145, 53177067, 15217830, 14542237,
+               1646131, 18603514, 22516545, 12876622, 31441985 },      /* 6 * 16^48 */
+               { 50901822, 13517195, 39309234, 19856633, 24009063,
+               27180541, 60741263, 20379039, 22853428, 29542421 },
+               { 17902668, 4518229, 66697162, 30725184, 26878216,
+               5258055, 54248111, 608396, 16031844, 3723494 } },
+       {       { 47103464, 21542479, 31520463, 605201, 2543521,
+               5991821, 64163800, 7229063, 57189218, 24727572 },       /* 7 * 16^48 */
+               { 38476072, 12763727, 46662418, 7577503, 33001348,
+               20536687, 17558841, 25681542, 23896953, 29240187 },
+               { 28816026, 298879, 38943848, 17633493, 19000927,
+               31888542, 54428030, 30605106, 49057085, 31471516 } },
+       {       { 10151868, 10572098, 27312476, 7922682, 14825339,
+               4723128, 34252933, 27035413, 57088296, 3852847 },       /* 8 * 16^48 */
+               { 16000882, 33209536, 3493091, 22107234, 37604268,
+               20394642, 12577739, 16041268, 47393624, 7847706 },
+               { 55678375, 15697595, 45987307, 29133784, 5386313,
+               15063598, 16514493, 17622322, 29330898, 18478208 } },
+},
+{ /* 16^50 */
+       {       { 15683501, 27551389, 18109119, 23573784, 15337967,
+               27556609, 50391428, 15921865, 16103996, 29823217 },     /* 1 * 16^50 */
+               { 41609129, 29175637, 51885955, 26653220, 16615730,
+               2051784, 3303702, 15490, 39560068, 12314390 },
+               { 43939021, 22773182, 13588191, 31925625, 63310306,
+               32479502, 47835256, 5402698, 37293151, 23713330 } },
+       {       { 21374101, 30000182, 33584214, 9874410, 15377179,
+               11831242, 33578960, 6134906, 4931255, 11987849 },       /* 2 * 16^50 */
+               { 23190676, 2384583, 34394524, 3462153, 37205209,
+               32025299, 55842007, 8911516, 41903005, 2739712 },
+               { 67101132, 30575573, 50885377, 7277596, 105524,
+               33232381, 35628324, 13861387, 37032554, 10117929 } },
+       {       { 45136504, 21783052, 66157804, 29135591, 14704839,
+               2695116, 903376, 23126293, 12885166, 8311031 }, /* 3 * 16^50 */
+               { 37607694, 22809559, 40945095, 13051538, 41483300,
+               5089642, 60783361, 6704078, 12890019, 15728940 },
+               { 49592363, 5352193, 10384213, 19742774, 7506450,
+               13453191, 26423267, 4384730, 1888765, 28119028 } },
+       {       { 43500868, 30888657, 66582772, 4651135, 5765089,
+               4618330, 6092245, 14845197, 17151279, 23700316 },       /* 4 * 16^50 */
+               { 41291507, 30447119, 53614264, 30371925, 30896458,
+               19632703, 34857219, 20846562, 47644429, 30214188 },
+               { 42278406, 20820711, 51942885, 10367249, 37577956,
+               33289075, 22825804, 26467153, 50242379, 16176524 } },
+       {       { 56482264, 29068029, 53788301, 28429114, 3432135,
+               27161203, 23632036, 31613822, 32808309, 1099883 },      /* 5 * 16^50 */
+               { 43525589, 6564960, 20063689, 3798228, 62368686,
+               7359224, 2006182, 23191006, 38362610, 23356922 },
+               { 15030958, 5768825, 39657628, 30667132, 60681485,
+               18193060, 51830967, 26745081, 2051440, 18328567 } },
+       {       { 4577067, 16802144, 13249840, 18250104, 19958762,
+               19017158, 18559669, 22794883, 8402477, 23690159 },      /* 6 * 16^50 */
+               { 63746541, 26315059, 7517889, 9824992, 23555850,
+               295369, 5148398, 19400244, 44422509, 16633659 },
+               { 38702534, 32502850, 40318708, 32646733, 49896449,
+               22523642, 9453450, 18574360, 17983009, 9967138 } },
+       {       { 56688388, 29436320, 14584638, 15971087, 51340543,
+               8861009, 26556809, 27979875, 48555541, 22197296 },      /* 7 * 16^50 */
+               { 41346370, 6524721, 26585488, 9969270, 24709298,
+               1220360, 65430874, 7806336, 17507396, 3651560 },
+               { 2839082, 14284142, 4029895, 3472686, 14402957,
+               12689363, 40466743, 8459446, 61503401, 25932490 } },
+       {       { 18164541, 22959256, 49953981, 32012014, 19237077,
+               23809137, 23357532, 18337424, 26908269, 12150756 },     /* 8 * 16^50 */
+               { 62269556, 30018987, 9744960, 2871048, 25113978,
+               3187018, 41998051, 32705365, 17258083, 25576693 },
+               { 36843994, 25906566, 5112248, 26517760, 65609056,
+               26580174, 43167, 28016731, 34806789, 16215818 } },
+},
+{ /* 16^52 */
+       {       { 39765323, 17038963, 39957339, 22831480, 946345,
+               16291093, 254968, 7168080, 21676107, 31611404 },        /* 1 * 16^52 */
+               { 60209940, 9824393, 54804085, 29153342, 35711722,
+               27277596, 32574488, 12532905, 59605792, 24879084 },
+               { 21260942, 25129680, 50276977, 21633609, 43430902,
+               3968120, 63456915, 27338965, 63552672, 25641356 } },
+       {       { 64693606, 17976703, 18312302, 4964443, 51836334,
+               20900867, 26820650, 16690659, 25459437, 28989823 },     /* 2 * 16^52 */
+               { 16544735, 13250366, 50304436, 15546241, 62525861,
+               12757257, 64646556, 24874095, 48201831, 23891632 },
+               { 41964155, 11425019, 28423002, 22533875, 60963942,
+               17728207, 9142794, 31162830, 60676445, 31909614 } },
+       {       { 36775618, 13979674, 7503222, 21186118, 55152142,
+               28932738, 36836594, 2682241, 25993170, 21075909 },      /* 3 * 16^52 */
+               { 44004212, 6253475, 16964147, 29785560, 41994891,
+               21257994, 39651638, 17209773, 6335691, 7249989 },
+               { 4364628, 5930691, 32304656, 23509878, 59054082,
+               15091130, 22857016, 22955477, 31820367, 15075278 } },
+       {       { 19073683, 14851414, 42705695, 21694263, 7625277,
+               11091125, 47489674, 2074448, 57694925, 14905376 },      /* 4 * 16^52 */
+               { 31879134, 24635739, 17258760, 90626, 59067028,
+               28636722, 24162787, 23903546, 49138625, 12833044 },
+               { 24483648, 21618865, 64589997, 22007013, 65555733,
+               15355505, 41826784, 9253128, 27628530, 25998952 } },
+       {       { 510886, 14337390, 35323607, 16638631, 6328095,
+               2713355, 46891447, 21690211, 8683220, 2921426 },        /* 5 * 16^52 */
+               { 17597607, 8340603, 19355617, 552187, 26198470,
+               30377849, 4593323, 24396850, 52997988, 15297015 },
+               { 18606791, 11874196, 27155355, 28272950, 43077121,
+               6265445, 41930624, 32275507, 4674689, 13890525 } },
+       {       { 9922506, 33035038, 13613106, 5883594, 48350519,
+               33120168, 54804801, 8317627, 23388070, 16052080 },      /* 6 * 16^52 */
+               { 13609624, 13069022, 39736503, 20498523, 24360585,
+               9592974, 14977157, 9835105, 4389687, 288396 },
+               { 12719997, 11937594, 35138804, 28525742, 26900119,
+               8561328, 46953177, 21921452, 52354592, 22741539 } },
+       {       { 11038231, 21972036, 39798381, 26237869, 56610336,
+               17246600, 43629330, 24182562, 45715720, 2465073 },      /* 7 * 16^52 */
+               { 15961858, 14150409, 26716931, 32888600, 44314535,
+               13603568, 11829573, 7467844, 38286736, 929274 },
+               { 20017144, 29231206, 27915241, 1529148, 12396362,
+               15675764, 13817261, 23896366, 2463390, 28932292 } },
+       {       { 65377275, 18398561, 63845933, 16143081, 19294135,
+               13385325, 14741514, 24450706, 7903885, 2348101 },       /* 8 * 16^52 */
+               { 50749986, 20890520, 55043680, 4996453, 65852442,
+               1073571, 9583558, 12851107, 4003896, 12673717 },
+               { 24536016, 17039225, 12715591, 29692277, 1511292,
+               10047386, 63266518, 26425272, 38731325, 10048126 } },
+},
+{ /* 16^54 */
+       {       { 40630742, 22450567, 11546243, 31701949, 9180879,
+               7656409, 45764914, 2095754, 29769758, 6593415 },        /* 1 * 16^54 */
+               { 54486638, 27349611, 30718824, 2591312, 56491836,
+               12192839, 18873298, 26257342, 34811107, 15221631 },
+               { 35114656, 30646970, 4176911, 3264766, 12538965,
+               32686321, 26312344, 27435754, 30958053, 8292160 } },
+       {       { 22648882, 1402143, 44308880, 13746058, 7936347,
+               365344, 58440231, 31879998, 63350620, 31249806 },       /* 2 * 16^54 */
+               { 31429803, 19595316, 29173531, 15632448, 12174511,
+               30794338, 32808830, 3977186, 26143136, 30405556 },
+               { 51616947, 8012312, 64594134, 20851969, 43143017,
+               23300402, 65496150, 32018862, 50444388, 8194477 } },
+       {       { 26287105, 4821776, 25476601, 29408529, 63344350,
+               17765447, 49100281, 1182478, 41014043, 20474836 },      /* 3 * 16^54 */
+               { 27338066, 26047012, 59694639, 10140404, 48082437,
+               26964542, 27277190, 8855376, 28572286, 3005164 },
+               { 59937691, 3178079, 23970071, 6201893, 49913287,
+               29065239, 45232588, 19571804, 32208682, 32356184 } },
+       {       { 15941010, 24148500, 45741813, 8062054, 31876073,
+               33315803, 51830470, 32110002, 15397330, 29424239 },     /* 4 * 16^54 */
+               { 50451143, 2817642, 56822502, 14811297, 6024667,
+               13349505, 39793360, 23056589, 39436278, 22014573 },
+               { 8934485, 20068965, 43822466, 20131190, 34662773,
+               14047985, 31170398, 32113411, 39603297, 15087183 } },
+       {       { 65161459, 16013772, 21750665, 3714552, 49707082,
+               17498998, 63338576, 23231111, 31322513, 21938797 },     /* 5 * 16^54 */
+               { 48751602, 31397940, 24524912, 16876564, 15520426,
+               27193656, 51606457, 11461895, 16788528, 27685490 },
+               { 21426636, 27904214, 53460576, 28206894, 38296674,
+               28633461, 48833472, 18933017, 13040861, 21441484 } },
+       {       { 41213962, 15323293, 58619073, 25496531, 25967125,
+               20128972, 2825959, 28657387, 43137087, 22287016 },      /* 6 * 16^54 */
+               { 11293895, 12478086, 39972463, 15083749, 37801443,
+               14748871, 14555558, 20137329, 1613710, 4896935 },
+               { 51184079, 28324551, 49665331, 6410663, 3622847,
+               10243618, 20615400, 12405433, 43355834, 25118015 } },
+       {       { 4565804, 17528778, 20084411, 25711615, 1724998,
+               189254, 24767264, 10103221, 48596551, 2424777 },        /* 7 * 16^54 */
+               { 60017550, 12556207, 46917512, 9025186, 50036385,
+               4333800, 4378436, 2432030, 23097949, 32988414 },
+               { 366633, 21577626, 8173089, 26664313, 30788633,
+               5745705, 59940186, 1344108, 63466311, 12412658 } },
+       {       { 18289503, 18829478, 8056944, 16430056, 45379140,
+               7842513, 61107423, 32067534, 48424218, 22110928 },      /* 8 * 16^54 */
+               { 43107073, 7690285, 14929416, 33386175, 34898028,
+               20141445, 24162696, 18227928, 63967362, 11179384 },
+               { 476239, 6601091, 60956074, 23831056, 17503544,
+               28690532, 27672958, 13403813, 11052904, 5219329 } },
+},
+{ /* 16^56 */
+       {       { 53464795, 23204192, 51146355, 5075807, 65594203,
+               22019831, 34006363, 9160279, 8473550, 30297594 },       /* 1 * 16^56 */
+               { 20678527, 25178694, 34436965, 8849122, 62099106,
+               14574751, 31186971, 29580702, 9014761, 24975376 },
+               { 24900749, 14435722, 17209120, 18261891, 44516588,
+               9878982, 59419555, 17218610, 42540382, 11788947 } },
+       {       { 51449703, 16736705, 44641714, 10215877, 58011687,
+               7563910, 11871841, 21049238, 48595538, 8464117 },       /* 2 * 16^56 */
+               { 63990690, 22159237, 53306774, 14797440, 9652448,
+               26708528, 47071426, 10410732, 42540394, 32095740 },
+               { 43708233, 8348506, 52522913, 32692717, 63158658,
+               27181012, 14325288, 8628612, 33313881, 25183915 } },
+       {       { 60160060, 31759219, 34483180, 17533252, 32635413,
+               26180187, 15989196, 20716244, 28358191, 29300528 },     /* 3 * 16^56 */
+               { 46921872, 28586496, 22367355, 5271547, 66011747,
+               28765593, 42303196, 23317577, 58168128, 27736162 },
+               { 43547083, 30755372, 34757181, 31892468, 57961144,
+               10429266, 50471180, 4072015, 61757200, 5596588 } },
+       {       { 59865506, 30307471, 62515396, 26001078, 66980936,
+               32642186, 66017961, 29049440, 42448372, 3442909 },      /* 4 * 16^56 */
+               { 38872266, 30164383, 12312895, 6213178, 3117142,
+               16078565, 29266239, 2557221, 1768301, 15373193 },
+               { 36898293, 5124042, 14181784, 8197961, 18964734,
+               21615339, 22597930, 7176455, 48523386, 13365929 } },
+       {       { 25008885, 22782833, 62803832, 23916421, 16265035,
+               15721635, 683793, 21730648, 15723478, 18390951 },       /* 5 * 16^56 */
+               { 59231455, 32054473, 8324672, 4690079, 6261860,
+               890446, 24538107, 24984246, 57419264, 30522764 },
+               { 57448220, 12374378, 40101865, 26528283, 59384749,
+               21239917, 11879681, 5400171, 519526, 32318556 } },
+       {       { 59027556, 25089834, 58885552, 9719709, 19259459,
+               18206220, 23994941, 28272877, 57640015, 4763277 },      /* 6 * 16^56 */
+               { 22258397, 17222199, 59239046, 14613015, 44588609,
+               30603508, 46754982, 7315966, 16648397, 7605640 },
+               { 45409620, 9220968, 51378240, 1084136, 41632757,
+               30702041, 31088446, 25789909, 55752334, 728111 } },
+       {       { 17510331, 33231575, 5854288, 8403524, 17133918,
+               30441820, 38997856, 12327944, 10750447, 10014012 },     /* 7 * 16^56 */
+               { 26047201, 21802961, 60208540, 17032633, 24092067,
+               9158119, 62835319, 20998873, 37743427, 28056159 },
+               { 56796096, 3936951, 9156313, 24656749, 16498691,
+               32559785, 39627812, 32887699, 3424690, 7540221 } },
+       {       { 13054543, 30774935, 19155473, 469045, 54626067,
+               4566041, 5631406, 2711395, 1062915, 28418087 }, /* 8 * 16^56 */
+               { 30322361, 26590322, 11361004, 29411115, 7433303,
+               4989748, 60037442, 17237212, 57864598, 15258045 },
+               { 47868616, 22299832, 37599834, 26054466, 61273100,
+               13005410, 61042375, 12194496, 32960380, 1459310 } },
+},
+{ /* 16^58 */
+       {       { 31395515, 15098109, 26581030, 8030562, 50580950,
+               28547297, 9012485, 25970078, 60465776, 28111795 },      /* 1 * 16^58 */
+               { 19852015, 7027924, 23669353, 10020366, 8586503,
+               26896525, 394196, 27452547, 18638002, 22379495 },
+               { 57916680, 31207054, 65111764, 4529533, 25766844,
+               607986, 67095642, 9677542, 34813975, 27098423 } },
+       {       { 51872508, 18120922, 7766469, 746860, 26346930,
+               23332670, 39775412, 10754587, 57677388, 5203575 },      /* 2 * 16^58 */
+               { 64664349, 33404494, 29348901, 8186665, 1873760,
+               12489863, 36174285, 25714739, 59256019, 25416002 },
+               { 31834314, 14135496, 66338857, 5159117, 20917671,
+               16786336, 59640890, 26216907, 31809242, 7347066 } },
+       {       { 54445282, 31372712, 1168161, 29749623, 26747876,
+               19416341, 10609329, 12694420, 33473243, 20172328 },     /* 3 * 16^58 */
+               { 57502122, 21680191, 20414458, 13033986, 13716524,
+               21862551, 19797969, 21343177, 15192875, 31466942 },
+               { 33184999, 11180355, 15832085, 22169002, 65475192,
+               225883, 15089336, 22530529, 60973201, 14480052 } },
+       {       { 46790012, 18404192, 10933842, 17376410, 8335351,
+               26008410, 36100512, 20943827, 26498113, 66511 },        /* 4 * 16^58 */
+               { 31308717, 27934434, 31030839, 31657333, 15674546,
+               26971549, 5496207, 13685227, 27595050, 8737275 },
+               { 22644435, 24792703, 50437087, 4884561, 64003250,
+               19995065, 30540765, 29267685, 53781076, 26039336 } },
+       {       { 23711543, 32881517, 31206560, 25191721, 6164646,
+               23844445, 33572981, 32128335, 8236920, 16492939 },      /* 5 * 16^58 */
+               { 39091017, 9834844, 18617207, 30873120, 63706907,
+               20246925, 8205539, 13585437, 49981399, 15115438 },
+               { 43198286, 20038905, 40809380, 29050590, 25005589,
+               25867162, 19574901, 10071562, 6708380, 27332008 } },
+       {       { 3096359, 9271816, 45488000, 18032587, 52260867,
+               25961494, 41216721, 20918836, 57191288, 6216607 },      /* 6 * 16^58 */
+               { 2101372, 28624378, 19702730, 2367575, 51681697,
+               1047674, 5301017, 9328700, 29955601, 21876122 },
+               { 34493015, 338662, 41913253, 2510421, 37895298,
+               19734218, 24822829, 27407865, 40341383, 7525078 } },
+       {       { 21691500, 19929806, 66467532, 19187410, 3285880,
+               30070836, 42044197, 9718257, 59631427, 13381417 },      /* 7 * 16^58 */
+               { 44042215, 19568808, 16133486, 25658254, 63719298,
+               778787, 66198528, 30771936, 47722230, 11994100 },
+               { 18445390, 29352196, 14979845, 11622458, 65381754,
+               29971451, 23111647, 27179185, 28535281, 15779576 } },
+       {       { 9734894, 18977602, 59635230, 24415696, 2060391,
+               11313496, 48682835, 9924398, 20194861, 13380996 },      /* 8 * 16^58 */
+               { 30098034, 3089662, 57874477, 16662134, 45801924,
+               11308410, 53040410, 12021729, 9955285, 17251076 },
+               { 40730762, 25589224, 44941042, 15789296, 49053522,
+               27385639, 65123949, 15707770, 26342023, 10146099 } },
+},
+{ /* 16^60 */
+       {       { 54031477, 1184227, 23562814, 27583990, 46757619,
+               27205717, 25764460, 12243797, 46252298, 11649657 },     /* 1 * 16^60 */
+               { 41091971, 33334488, 21339190, 33513044, 19745255,
+               30675732, 37471583, 2227039, 21612326, 33008704 },
+               { 57077370, 11262625, 27384172, 2271902, 26947504,
+               17556661, 39943, 6114064, 33514190, 2333242 } },
+       {       { 62992557, 22282898, 43222677, 4843614, 37020525,
+               690622, 35572776, 23147595, 8317859, 12352766 },        /* 2 * 16^60 */
+               { 45675257, 21132610, 8119781, 7219913, 45278342,
+               24538297, 60429113, 20883793, 24350577, 20104431 },
+               { 18200138, 19078521, 34021104, 30857812, 43406342,
+               24451920, 43556767, 31266881, 20712162, 6719373 } },
+       {       { 49939907, 18700334, 63713187, 17184554, 47154818,
+               14050419, 21728352, 9493610, 18620611, 17125804 },      /* 3 * 16^60 */
+               { 26656189, 6075253, 59250308, 1886071, 38764821,
+               4262325, 11117530, 29791222, 26224234, 30256974 },
+               { 53785524, 13325348, 11432106, 5964811, 18609221,
+               6062965, 61839393, 23828875, 36407290, 17074774 } },
+       {       { 25089769, 6742589, 17081145, 20148166, 21909292,
+               17486451, 51972569, 29789085, 45830866, 5473615 },      /* 4 * 16^60 */
+               { 43248326, 22321272, 26961356, 1640861, 34695752,
+               16816491, 12248508, 28313793, 13735341, 1934062 },
+               { 31883658, 25593331, 1083431, 21982029, 22828470,
+               13290673, 59983779, 12469655, 29111212, 28103418 } },
+       {       { 41468082, 30136590, 5217915, 16224624, 19987036,
+               29472163, 42872612, 27639183, 15766061, 8407814 },      /* 5 * 16^60 */
+               { 24244947, 18504025, 40845887, 2791539, 52111265,
+               16666677, 24367466, 6388839, 56813277, 452382 },
+               { 46701865, 13990230, 15495425, 16395525, 5377168,
+               15166495, 58191841, 29165478, 59040954, 2276717 } },
+       {       { 2041139, 19298082, 7783686, 13876377, 41161879,
+               20201972, 24051123, 13742383, 51471265, 13295221 },     /* 6 * 16^60 */
+               { 30157899, 12924066, 49396814, 9245752, 19895028,
+               3368142, 43281277, 5096218, 22740376, 26251015 },
+               { 33338218, 25048699, 12532112, 7977527, 9106186,
+               31839181, 49388668, 28941459, 62657506, 18884987 } },
+       {       { 23208049, 7979712, 33071466, 8149229, 1758231,
+               22719437, 30945527, 31860109, 33606523, 18786461 },     /* 7 * 16^60 */
+               { 47063583, 5454096, 52762316, 6447145, 28862071,
+               1883651, 64639598, 29412551, 7770568, 9620597 },
+               { 1439939, 17283952, 66028874, 32760649, 4625401,
+               10647766, 62065063, 1220117, 30494170, 22113633 } },
+       {       { 13908495, 30005160, 30919927, 27280607, 45587000,
+               7989038, 9021034, 9078865, 3353509, 4033511 },  /* 8 * 16^60 */
+               { 62071265, 20526136, 64138304, 30492664, 15640973,
+               26852766, 40369837, 926049, 65424525, 20220784 },
+               { 37445433, 18440821, 32259990, 33209950, 24295848,
+               20642309, 23161162, 8839127, 27485041, 7356032 } },
+},
+{ /* 16^62 */
+       {       { 43269631, 25243016, 41163352, 7480957, 49427195,
+               25200248, 44562891, 14150564, 15970762, 4099461 },      /* 1 * 16^62 */
+               { 9661008, 705443, 11980065, 28184278, 65480320,
+               14661172, 60762722, 2625014, 28431036, 16782598 },
+               { 29262576, 16756590, 26350592, 24760869, 8529670,
+               22346382, 13617292, 23617289, 11465738, 8317062 } },
+       {       { 46724414, 19206718, 48772458, 13884721, 34069410,
+               2842113, 45498038, 29904543, 11177094, 14989547 },      /* 2 * 16^62 */
+               { 41615764, 26591503, 32500199, 24135381, 44070139,
+               31252209, 14898636, 3848455, 20969334, 28396916 },
+               { 42612143, 21838415, 16959895, 2278463, 12066309,
+               10137771, 13515641, 2581286, 38621356, 9930239 } },
+       {       { 33879670, 2553287, 32678213, 9875984, 8534129,
+               6889387, 57432090, 6957616, 4368891, 9788741 }, /* 3 * 16^62 */
+               { 49357223, 31456605, 16544299, 20545132, 51194056,
+               18605350, 18345766, 20150679, 16291480, 28240394 },
+               { 16660737, 7281060, 56278106, 12911819, 20108584,
+               25452756, 45386327, 24941283, 16250551, 22443329 } },
+       {       { 65754325, 14736940, 59741422, 20261545, 7710541,
+               19398842, 57127292, 4383044, 22546403, 437323 },        /* 4 * 16^62 */
+               { 47343357, 2390525, 50557833, 14161979, 1905286,
+               6414907, 4689584, 10604807, 36918461, 4782746 },
+               { 31665558, 21373968, 50922033, 1491338, 48740239,
+               3294681, 27343084, 2786261, 36475274, 19457415 } },
+       {       { 15121312, 17758270, 6377019, 27523071, 56310752,
+               20596586, 18952176, 15496498, 37728731, 11754227 },     /* 5 * 16^62 */
+               { 52641566, 32870716, 33734756, 7448551, 19294360,
+               14334329, 47418233, 2355318, 47824193, 27440058 },
+               { 64471568, 20071356, 8488726, 19250536, 12728760,
+               31931939, 7141595, 11724556, 22761615, 23420291 } },
+       {       { 11166615, 7338049, 60386341, 4531519, 37640192,
+               26252376, 31474878, 3483633, 65915689, 29523600 },      /* 6 * 16^62 */
+               { 16918416, 11729663, 49025285, 3022986, 36093132,
+               20214772, 38367678, 21327038, 32851221, 11717399 },
+               { 66923210, 9921304, 31456609, 20017994, 55095045,
+               13348922, 33142652, 6546660, 47123585, 29606055 } },
+       {       { 49102387, 12709067, 3991746, 27075244, 45617340,
+               23004006, 35973516, 17504552, 10928916, 3011958 },      /* 7 * 16^62 */
+               { 34648249, 11266711, 55911757, 25655328, 31703693,
+               3855903, 58571733, 20721383, 36336829, 18068118 },
+               { 60151107, 17960094, 31696058, 334240, 29576716,
+               14796075, 36277808, 20749251, 18008030, 10258577 } },
+       {       { 29701166, 19180498, 56230743, 9279287, 67091296,
+               13127209, 21382910, 11042292, 25838796, 4642684 },      /* 8 * 16^62 */
+               { 44660220, 15655568, 7018479, 29144429, 36794597,
+               32352840, 65255398, 1367119, 25127874, 6671743 },
+               { 46678630, 14955536, 42982517, 8124618, 61739576,
+               27563961, 30468146, 19653792, 18423288, 4177476 } },
+},
diff --git a/crypto/libeddsa/lib/ed_lookup64.h b/crypto/libeddsa/lib/ed_lookup64.h
new file mode 100644 (file)
index 0000000..cb79412
--- /dev/null
@@ -0,0 +1,835 @@
+/*
+ * this file is auto generated! see gentable64.gp
+ */
+{ /* 16^0 */
+       {       { 62697248952638, 204681361388450, 631292143396476, 338455783676468, 1213667448819585 },        /* 1 * 16^0 */
+               { 1288382639258501, 245678601348599, 269427782077623, 1462984067271730, 137412439391563 },
+               { 301289933810280, 1259582250014073, 1422107436869536, 796239922652654, 1953934009299142 } },
+       {       { 463307831301544, 432984605774163, 1610641361907204, 750899048855000, 1894842303421586 },      /* 2 * 16^0 */
+               { 1380971894829527, 790832306631236, 2067202295274102, 1995808275510000, 1566530869037010 },
+               { 748439484463711, 1033211726465151, 1396005112841647, 1611506220286469, 1972177495910992 } },
+       {       { 316559037616741, 2177824224946892, 1459442586438991, 1461528397712656, 751590696113597 },     /* 3 * 16^0 */
+               { 1601611775252272, 1720807796594148, 1132070835939856, 1260455018889551, 2147779492816911 },
+               { 1850748884277385, 1200145853858453, 1068094770532492, 672251375690438, 1586055907191707 } },
+       {       { 1694390458783935, 1735906047636159, 705069562067493, 648033061693059, 696214010414170 },      /* 4 * 16^0 */
+               { 934282339813791, 1846903124198670, 1172395437954843, 1007037127761661, 1830588347719256 },
+               { 1121406372216585, 192876649532226, 190294192191717, 1994165897297032, 2245000007398739 } },
+       {       { 425251763115706, 608463272472562, 442562545713235, 837766094556764, 374555092627893 },        /* 5 * 16^0 */
+               { 769950342298419, 132954430919746, 844085933195555, 974092374476333, 726076285546016 },
+               { 1086255230780037, 274979815921559, 1960002765731872, 929474102396301, 1190409889297339 } },
+       {       { 7380825640100, 146210432690483, 304903576448906, 1198869323871120, 997689833219095 }, /* 6 * 16^0 */
+               { 1388594989461809, 316767091099457, 394298842192982, 1230079486801005, 1440737038838979 },
+               { 1181317918772081, 114573476638901, 262805072233344, 265712217171332, 294181933805782 } },
+       {       { 2019367628972465, 676711900706637, 110710997811333, 1108646842542025, 517791959672113 },      /* 7 * 16^0 */
+               { 665000864555967, 2065379846933859, 370231110385876, 350988370788628, 1233371373142985 },
+               { 965130719900578, 247011430587952, 526356006571389, 91986625355052, 2157223321444601 } },
+       {       { 2073601412052185, 31021124762708, 264500969797082, 248034690651703, 1030252227928288 },       /* 8 * 16^0 */
+               { 2068619540119183, 1966274918058806, 957728544705549, 729906502578991, 159834893065166 },
+               { 551790716293402, 1989538725166328, 801169423371717, 2052451893578887, 678432056995012 } },
+},
+{ /* 16^2 */
+       {       { 953638594433374, 1092333936795051, 1419774766716690, 805677984380077, 859228993502513 },      /* 1 * 16^2 */
+               { 1368953770187805, 790347636712921, 437508475667162, 2142576377050580, 1932081720066286 },
+               { 1200766035879111, 20142053207432, 1465634435977050, 1645256912097844, 295121984874596 } },
+       {       { 1060098822528990, 1586825862073490, 212301317240126, 1975302711403555, 666724059764335 },     /* 2 * 16^2 */
+               { 1735718747031557, 1248237894295956, 1204753118328107, 976066523550493, 65943769534592 },
+               { 1091990273418756, 1572899409348578, 80968014455247, 306009358661350, 1520450739132526 } },
+       {       { 2151330273626164, 762045184746182, 1688074332551515, 823046109005759, 907602769079491 },      /* 3 * 16^2 */
+               { 1480517209436112, 1511153322193952, 1244343858991172, 304788150493241, 369136856496443 },
+               { 2047386910586836, 168470092900250, 1552838872594810, 340951180073789, 360819374702533 } },
+       {       { 980234343912898, 1712256739246056, 588935272190264, 204298813091998, 841798321043288 },       /* 4 * 16^2 */
+               { 1982622644432056, 2014393600336956, 128909208804214, 1617792623929191, 105294281913815 },
+               { 197561292938973, 454817274782871, 1963754960082318, 2113372252160468, 971377527342673 } },
+       {       { 732262946680281, 1674412764227063, 2182456405662809, 1350894754474250, 558458873295247 },     /* 5 * 16^2 */
+               { 164699448829328, 3127451757672, 1199504971548753, 1766155447043652, 1899238924683527 },
+               { 2103305098582922, 1960809151316468, 715134605001343, 1454892949167181, 40827143824949 } },
+       {       { 2232056027107988, 987343914584615, 2115594492994461, 1819598072792159, 1119305654014850 },    /* 6 * 16^2 */
+               { 1239289043050212, 1744654158124578, 758702410031698, 1796762995074688, 1603056663766 },
+               { 320153677847348, 939613871605645, 641883205761567, 1930009789398224, 329165806634126 } },
+       {       { 276821765317453, 1536835591188030, 1305212741412361, 61473904210175, 2051377036983058 },      /* 7 * 16^2 */
+               { 980930490474130, 1242488692177893, 1251446316964684, 1086618677993530, 1961430968465772 },
+               { 833449923882501, 1750270368490475, 1123347002068295, 185477424765687, 278090826653186 } },
+       {       { 1504846112759364, 1203096289004681, 562139421471418, 274333017451844, 1284344053775441 },     /* 8 * 16^2 */
+               { 794524995833413, 1849907304548286, 53348672473145, 1272368559505217, 1147304168324779 },
+               { 483048732424432, 2116063063343382, 30120189902313, 292451576741007, 1156379271702225 } },
+},
+{ /* 16^4 */
+       {       { 137732961814206, 706670923917341, 1387038086865771, 1965643813686352, 1384777115696347 },     /* 1 * 16^4 */
+               { 928372153029038, 2147692869914564, 1455665844462196, 1986737809425946, 185207050258089 },
+               { 481144981981577, 2053319313589856, 2065402289827512, 617954271490316, 1106602634668125 } },
+       {       { 657390353372855, 998499966885562, 991893336905797, 810470207106761, 343139804608786 },        /* 2 * 16^4 */
+               { 696298019648792, 893299659040895, 1148636718636009, 26734077349617, 2203955659340681 },
+               { 791736669492960, 934767652997115, 824656780392914, 1759463253018643, 361530362383518 } },
+       {       { 1287487199965223, 2215311941380308, 1552928390931986, 1664859529680196, 1125004975265243 },   /* 3 * 16^4 */
+               { 2022541353055597, 2094700262587466, 1551008075025686, 242785517418164, 695985404963562 },
+               { 677434665154918, 989582503122485, 1817429540898386, 1052904935475344, 1143826298169798 } },
+       {       { 773360688841258, 1815381330538070, 363773437667376, 539629987070205, 783280434248437 },       /* 4 * 16^4 */
+               { 367266328308408, 318431188922404, 695629353755355, 634085657580832, 24581612564426 },
+               { 180820816194166, 168937968377394, 748416242794470, 1227281252254508, 1567587861004268 } },
+       {       { 1984740906540026, 1079164179400229, 1056021349262661, 1659958556483663, 1088529069025527 },   /* 5 * 16^4 */
+               { 478775558583645, 2062896624554807, 699391259285399, 358099408427873, 1277310261461761 },
+               { 580736401511151, 1842931091388998, 1177201471228238, 2075460256527244, 1301133425678027 } },
+       {       { 1295295738269652, 1714742313707026, 545583042462581, 2034411676262552, 1513248090013606 },    /* 6 * 16^4 */
+               { 1515728832059182, 1575261009617579, 1510246567196186, 191078022609704, 116661716289141 },
+               { 230710545179830, 30821514358353, 760704303452229, 390668103790604, 573437871383156 } },
+       {       { 2102254323485823, 1570832666216754, 34696906544624, 1993213739807337, 70638552271463 },       /* 7 * 16^4 */
+               { 1169380107545646, 263167233745614, 2022901299054448, 819900753251120, 2023898464874585 },
+               { 894132856735058, 548675863558441, 845349339503395, 1942269668326667, 1615682209874691 } },
+       {       { 793388516527298, 1315457083650035, 1972286999342417, 1901825953052455, 338269477222410 },     /* 8 * 16^4 */
+               { 1287670217537834, 1222355136884920, 1846481788678694, 1150426571265110, 1613523400722047 },
+               { 550201530671806, 778605267108140, 2063911101902983, 115500557286349, 2041641272971022 } },
+},
+{ /* 16^6 */
+       {       { 261715221532238, 1795354330069993, 1496878026850283, 499739720521052, 389031152673770 },      /* 1 * 16^6 */
+               { 717255318455100, 519313764361315, 2080406977303708, 541981206705521, 774328150311600 },
+               { 1997217696294013, 1717306351628065, 1684313917746180, 1644426076011410, 1857378133465451 } },
+       {       { 2022306639183567, 726296063571875, 315345054448644, 1058733329149221, 1448201136060677 },     /* 2 * 16^6 */
+               { 1475434724792648, 76931896285979, 1116729029771667, 2002544139318042, 725547833803938 },
+               { 1710065158525665, 1895094923036397, 123988286168546, 1145519900776355, 1607510767693874 } },
+       {       { 1548495173745801, 442310529226540, 998072547000384, 553054358385281, 644824326376171 },       /* 3 * 16^6 */
+               { 561605375422540, 1071733543815037, 131496498800990, 1946868434569999, 828138133964203 },
+               { 1445526537029440, 2225519789662536, 914628859347385, 1064754194555068, 1660295614401091 } },
+       {       { 876926774220824, 554618976488214, 1012056309841565, 839961821554611, 1414499340307677 },      /* 4 * 16^6 */
+               { 1199690223111956, 24028135822341, 66638289244341, 57626156285975, 565093967979607 },
+               { 703047626104145, 1266841406201770, 165556500219173, 486991595001879, 1011325891650656 } },
+       {       { 334886927423922, 489511099221528, 129160865966726, 1720809113143481, 619700195649254 },       /* 5 * 16^6 */
+               { 1622861044480487, 1156394801573634, 1869132565415504, 327103985777730, 2095342781472284 },
+               { 1646545795166119, 1758370782583567, 714746174550637, 1472693650165135, 898994790308209 } },
+       {       { 1811196219982022, 1068969825533602, 289602974833439, 1988956043611592, 863562343398367 },     /* 6 * 16^6 */
+               { 333403773039279, 295772542452938, 1693106465353610, 912330357530760, 471235657950362 },
+               { 906282429780072, 2108672665779781, 432396390473936, 150625823801893, 1708930497638539 } },
+       {       { 1479786007267725, 1738881859066675, 68646196476567, 2146507056100328, 1247662817535471 },     /* 7 * 16^6 */
+               { 925664675702328, 21416848568684, 1831436641861340, 601157008940113, 371818055044496 },
+               { 52035296774456, 939969390708103, 312023458773250, 59873523517659, 1231345905848899 } },
+       {       { 129358342392716, 1932811617704777, 1176749390799681, 398040349861790, 1170779668090425 },     /* 8 * 16^6 */
+               { 643355106415761, 290186807495774, 2013561737429023, 319648069511546, 393736678496162 },
+               { 2051980782668029, 121859921510665, 2048329875753063, 1235229850149665, 519062146124755 } },
+},
+{ /* 16^8 */
+       {       { 1837656083115103, 1510134048812070, 906263674192061, 1821064197805734, 565375124676301 },     /* 1 * 16^8 */
+               { 1608170971973096, 415809060360428, 1350468408164766, 2038620059057678, 1026904485989112 },
+               { 578027192365650, 2034800251375322, 2128954087207123, 478816193810521, 2196171989962750 } },
+       {       { 462189358480054, 1784816734159228, 1611334301651368, 1303938263943540, 707589560319424 },     /* 2 * 16^8 */
+               { 1633188840273139, 852787172373708, 1548762607215796, 1266275218902681, 1107218203325133 },
+               { 1038829280972848, 38176604650029, 753193246598573, 1136076426528122, 595709990562434 } },
+       {       { 4701053362120, 1647641066302348, 1047553002242085, 1923635013395977, 206970314902065 },       /* 3 * 16^8 */
+               { 1408451820859834, 2194984964010833, 2198361797561729, 1061962440055713, 1645147963442934 },
+               { 1750479161778571, 1362553355169293, 1891721260220598, 966109370862782, 1024913988299801 } },
+       {       { 636808533673210, 1262201711667560, 390951380330599, 1663420692697294, 561951321757406 },      /* 4 * 16^8 */
+               { 212699049131723, 1117950018299775, 1873945661751056, 1403802921984058, 130896082652698 },
+               { 520731594438141, 1446301499955692, 273753264629267, 1565101517999256, 1019411827004672 } },
+       {       { 1464651961852572, 1483737295721717, 1519450561335517, 1161429831763785, 405914998179977 },    /* 5 * 16^8 */
+               { 926527492029409, 1191853477411379, 734233225181171, 184038887541270, 1790426146325343 },
+               { 996126634382301, 796204125879525, 127517800546509, 344155944689303, 615279846169038 } },
+       {       { 622917337413835, 1218989177089035, 1284857712846592, 970502061709359, 351025208117090 },      /* 6 * 16^8 */
+               { 738724080975276, 2188666632415296, 1961313708559162, 1506545807547587, 1151301638969740 },
+               { 2067814584765580, 1677855129927492, 2086109782475197, 235286517313238, 1416314046739645 } },
+       {       { 678489922928203, 2016657584724032, 90977383049628, 1026831907234582, 615271492942522 },       /* 7 * 16^8 */
+               { 586844262630358, 307444381952195, 458399356043426, 602068024507062, 1028548203415243 },
+               { 301225714012278, 1094837270268560, 1202288391010439, 644352775178361, 1647055902137983 } },
+       {       { 1135604073198207, 1683322080485474, 769147804376683, 2086688130589414, 900445683120379 },     /* 8 * 16^8 */
+               { 1210746697896478, 1416608304244708, 686487477217856, 1245131191434135, 1051238336855737 },
+               { 1971518477615628, 401909519527336, 448627091057375, 1409486868273821, 1214789035034363 } },
+},
+{ /* 16^10 */
+       {       { 1045230323257973, 818206601145807, 630513189076103, 1672046528998132, 807204017562437 },      /* 1 * 16^10 */
+               { 1364039144731711, 1897497433586190, 2203097701135459, 145461396811251, 1349844460790699 },
+               { 439961968385997, 386362664488986, 1382706320807688, 309894000125359, 2207801346498567 } },
+       {       { 2003766096898049, 170074059235165, 1141124258967971, 1485419893480973, 1573762821028725 },    /* 2 * 16^10 */
+               { 1229004686397588, 920643968530863, 123975893911178, 681423993215777, 1400559197080973 },
+               { 729905708611432, 1270323270673202, 123353058984288, 426460209632942, 2195574535456672 } },
+       {       { 1761608437466135, 583360847526804, 1586706389685493, 2157056599579261, 1170692369685772 },    /* 3 * 16^10 */
+               { 1271140255321235, 2044363183174497, 52125387634689, 1445120246694705, 942541986339084 },
+               { 871476219910823, 1878769545097794, 2241832391238412, 548957640601001, 690047440233174 } },
+       {       { 999628998628371, 1132836708493400, 2084741674517453, 469343353015612, 678782988708035 },      /* 4 * 16^10 */
+               { 297194732135507, 1366347803776820, 1301185512245601, 561849853336294, 1533554921345731 },
+               { 2189427607417022, 699801937082607, 412764402319267, 1478091893643349, 2244675696854460 } },
+       {       { 508561155940631, 966928475686665, 2236717801150132, 424543858577297, 2089272956986143 },      /* 5 * 16^10 */
+               { 1712292055966563, 204413590624874, 1405738637332841, 408981300829763, 861082219276721 },
+               { 221245220129925, 1156020201681217, 491145634799213, 542422431960839, 828100817819207 } },
+       {       { 559086812798481, 573177704212711, 1629737083816402, 1399819713462595, 1646954378266038 },     /* 6 * 16^10 */
+               { 153756971240384, 1299874139923977, 393099165260502, 1058234455773022, 996989038681183 },
+               { 1887963056288059, 228507035730124, 1468368348640282, 930557653420194, 613513962454686 } },
+       {       { 1076287717051609, 1114455570543035, 187297059715481, 250446884292121, 1885187512550540 },     /* 7 * 16^10 */
+               { 1224529808187553, 1577022856702685, 2206946542980843, 625883007765001, 279930793512158 },
+               { 902497362940219, 76749815795675, 1657927525633846, 1420238379745202, 1340321636548352 } },
+       {       { 628740660038789, 1943038498527841, 467786347793886, 1093341428303375, 235413859513003 },      /* 8 * 16^10 */
+               { 1129576631190784, 1281994010027327, 996844254743018, 257876363489249, 1150850742055018 },
+               { 237425418909360, 469614029179605, 1512389769174935, 1241726368345357, 441602891065214 } },
+},
+{ /* 16^12 */
+       {       { 1960754663920689, 497040957888962, 1909832851283095, 1271432136996826, 2219780368020940 },    /* 1 * 16^12 */
+               { 1736417953058555, 726531315520508, 1833335034432527, 1629442561574747, 624418919286085 },
+               { 1537037379417136, 1358865369268262, 2130838645654099, 828733687040705, 1999987652890901 } },
+       {       { 1811562332665373, 1501882019007673, 2213763501088999, 359573079719636, 36370565049116 },      /* 2 * 16^12 */
+               { 629042105241814, 1098854999137608, 887281544569320, 1423102019874777, 7911258951561 },
+               { 218907117361280, 1209298913016966, 1944312619096112, 1130690631451061, 1342327389191701 } },
+       {       { 2230701885562825, 1348173180338974, 2172856128624598, 1426538746123771, 444193481326151 },    /* 3 * 16^12 */
+               { 1369976867854704, 1396479602419169, 1765656654398856, 2203659200586299, 998327836117241 },
+               { 784210426627951, 918204562375674, 1284546780452985, 1324534636134684, 1872449409642708 } },
+       {       { 1901860206695915, 2004489122065736, 1625847061568236, 973529743399879, 2075287685312905 },    /* 4 * 16^12 */
+               { 319638829540294, 596282656808406, 2037902696412608, 1557219121643918, 341938082688094 },
+               { 1371853944110545, 1042332820512553, 1949855697918254, 1791195775521505, 37487364849293 } },
+       {       { 2082717129583892, 27829425539422, 145655066671970, 1690527209845512, 1865260509673478 },      /* 5 * 16^12 */
+               { 687200189577855, 1082536651125675, 644224940871546, 340923196057951, 343581346747396 },
+               { 1059729620568824, 2163709103470266, 1440302280256872, 1769143160546397, 869830310425069 } },
+       {       { 2024821921041576, 426948675450149, 595133284085473, 471860860885970, 600321679413000 },       /* 6 * 16^12 */
+               { 1609516219779025, 777277757338817, 2101121130363987, 550762194946473, 1905542338659364 },
+               { 598474602406721, 1468128276358244, 1191923149557635, 1501376424093216, 1281662691293476 } },
+       {       { 719520245587143, 393380711632345, 132350400863381, 1543271270810729, 1819543295798660 },      /* 7 * 16^12 */
+               { 1721138489890707, 1264336102277790, 433064545421287, 1359988423149466, 1561871293409447 },
+               { 396397949784152, 1811354474471839, 1362679985304303, 2117033964846756, 498041172552279 } },
+       {       { 650623932407995, 1137551288410575, 2125223403615539, 1725658013221271, 2134892965117796 },    /* 8 * 16^12 */
+               { 1812471844975748, 1856491995543149, 126579494584102, 1036244859282620, 1975108050082550 },
+               { 522584000310195, 1241762481390450, 1743702789495384, 2227404127826575, 1686746002148897 } },
+},
+{ /* 16^14 */
+       {       { 318101947455002, 248138407995851, 1481904195303927, 309278454311197, 1258516760217879 },      /* 1 * 16^14 */
+               { 427904865186312, 1703211129693455, 1585368107547509, 1436984488744336, 761188534613978 },
+               { 1275068538599310, 513726919533379, 349926553492294, 688428871968420, 1702400196000666 } },
+       {       { 1558816436882417, 1962896332636523, 1337709822062152, 1501413830776938, 294436165831932 },    /* 2 * 16^14 */
+               { 1061864036265233, 961611260325381, 321859632700838, 1045600629959517, 1985130202504038 },
+               { 818359826554971, 1862173000996177, 626821592884859, 573655738872376, 1749691246745455 } },
+       {       { 2146513703733331, 584788900394667, 464965657279958, 2183973639356127, 238371159456790 },      /* 3 * 16^14 */
+               { 1988022651432119, 1082111498586040, 1834020786104821, 1454826876423687, 692929915223122 },
+               { 1129007025494441, 2197883144413266, 265142755578169, 971864464758890, 1983715884903702 } },
+       {       { 444548969917454, 1452286453853356, 2113731441506810, 645188273895859, 810317625309512 },      /* 4 * 16^14 */
+               { 1291366624493075, 381456718189114, 1711482489312444, 1815233647702022, 892279782992467 },
+               { 2242724082797924, 1373354730327868, 1006520110883049, 2147330369940688, 1151816104883620 } },
+       {       { 163723479936298, 115424889803150, 1156016391581227, 1894942220753364, 1970549419986329 },     /* 5 * 16^14 */
+               { 1745720200383796, 1911723143175317, 2056329390702074, 355227174309849, 879232794371100 },
+               { 681981452362484, 267208874112496, 1374683991933094, 638600984916117, 646178654558546 } },
+       {       { 260683893467075, 854060306077237, 913639551980112, 4704576840123, 280254810808712 },  /* 6 * 16^14 */
+               { 13378654854251, 106237307029567, 1944412051589651, 1841976767925457, 230702819835573 },
+               { 715374893080287, 1173334812210491, 1806524662079626, 1894596008000979, 398905715033393 } },
+       {       { 2096421546958141, 1922523000950363, 789831022876840, 427295144688779, 320923973161730 },      /* 7 * 16^14 */
+               { 500026409727661, 1596431288195371, 1420380351989370, 985211561521489, 392444930785633 },
+               { 1927770723575450, 1485792977512719, 1850996108474547, 551696031508956, 2126047405475647 } },
+       {       { 383905201636970, 859946997631870, 855623867637644, 1017125780577795, 794250831877809 },       /* 8 * 16^14 */
+               { 2112099158080148, 742570803909715, 6484558077432, 1951119898618916, 93090382703416 },
+               { 77571826285752, 999304298101753, 487841111777762, 1038031143212339, 339066367948762 } },
+},
+{ /* 16^16 */
+       {       { 1001412661522686, 348196197067298, 1666614366723946, 888424995032760, 580747687801357 },      /* 1 * 16^16 */
+               { 674994775520533, 266035846330789, 826951213393478, 1405007746162285, 1781791018620876 },
+               { 1939560076207777, 1409892634407635, 552574736069277, 383854338280405, 190706709864139 } },
+       {       { 676962063230039, 1880275537148808, 2046721011602706, 888463247083003, 1318301552024067 },     /* 2 * 16^16 */
+               { 2177087163428741, 1439255351721944, 1208070840382793, 2230616362004769, 1396886392021913 },
+               { 1466980508178206, 617045217998949, 652303580573628, 757303753529064, 207583137376902 } },
+       {       { 1853982405405128, 1878664056251147, 1528011020803992, 1019626468153565, 1128438412189035 },   /* 3 * 16^16 */
+               { 1511056752906902, 105403126891277, 493434892772846, 1091943425335976, 1802717338077427 },
+               { 1963939888391106, 293456433791664, 697897559513649, 985882796904380, 796244541237972 } },
+       {       { 1428358296490651, 1027115282420478, 304840698058337, 441410174026628, 1819358356278573 },     /* 4 * 16^16 */
+               { 416770998629779, 389655552427054, 1314476859406756, 1749382513022778, 1161905598739491 },
+               { 204943430200135, 1554861433819175, 216426658514651, 264149070665950, 2047097371738319 } },
+       {       { 662035583584445, 286736105093098, 1131773000510616, 818494214211439, 472943792054479 },       /* 5 * 16^16 */
+               { 1934415182909034, 1393285083565062, 516409331772960, 1157690734993892, 121039666594268 },
+               { 665784778135882, 1893179629898606, 808313193813106, 276797254706413, 1563426179676396 } },
+       {       { 2031433403516252, 203996615228162, 170487168837083, 981513604791390, 843573964916831 },       /* 6 * 16^16 */
+               { 945205108984232, 526277562959295, 1324180513733566, 1666970227868664, 153547609289173 },
+               { 1476570093962618, 838514669399805, 1857930577281364, 2017007352225784, 317085545220047 } },
+       {       { 1293543509393474, 2143624609202546, 1058361566797508, 214097127393994, 946888515472729 },     /* 7 * 16^16 */
+               { 1461557121912842, 1600674043318359, 2157134900399597, 1670641601940616, 127765583803283 },
+               { 357067959932916, 1290876214345711, 521245575443703, 1494975468601005, 800942377643885 } },
+       {       { 617256647603209, 1652107761099439, 1857213046645471, 1085597175214970, 817432759830522 },     /* 8 * 16^16 */
+               { 566116659100033, 820247422481740, 994464017954148, 327157611686365, 92591318111744 },
+               { 771808161440705, 1323510426395069, 680497615846440, 851580615547985, 1320806384849017 } },
+},
+{ /* 16^18 */
+       {       { 1327968293887866, 1335500852943256, 1401587164534264, 558137311952440, 1551360549268902 },    /* 1 * 16^18 */
+               { 1219260086131915, 647169006596815, 79601124759706, 2161724213426748, 404861897060198 },
+               { 417621685193956, 1429953819744454, 396157358457099, 1940470778873255, 214000046234152 } },
+       {       { 1627072914981959, 2211603081280073, 1912369601616504, 1191770436221309, 2187309757525860 },   /* 2 * 16^18 */
+               { 1268047918491973, 2172375426948536, 1533916099229249, 1761293575457130, 1590622667026765 },
+               { 1149147819689533, 378692712667677, 828475842424202, 2218619146419342, 70688125792186 } },
+       {       { 2040723824657366, 399555637875075, 632543375452995, 872649937008051, 1235394727030233 },      /* 3 * 16^18 */
+               { 1299739417079761, 1438616663452759, 1536729078504412, 2053896748919838, 1008421032591246 },
+               { 2211311599327900, 2139787259888175, 938706616835350, 12609661139114, 2081897930719789 } },
+       {       { 1845522914617879, 1222198248335542, 150841072760134, 1927029069940982, 1189913404498011 },    /* 4 * 16^18 */
+               { 1324994503390450, 336982330582631, 1183998925654177, 1091654665913274, 48727673971319 },
+               { 1079559557592645, 2215338383666441, 1903569501302605, 49033973033940, 305703433934152 } },
+       {       { 1432015813136298, 440364795295369, 1395647062821501, 1976874522764578, 934452372723352 },     /* 5 * 16^18 */
+               { 94653405416909, 1386121349852999, 1062130477891762, 36553947479274, 833669648948846 },
+               { 1296625309219774, 2068273464883862, 1858621048097805, 1492281814208508, 2235868981918946 } },
+       {       { 1282462923712748, 741885683986255, 2027754642827561, 518989529541027, 1826610009555945 },     /* 6 * 16^18 */
+               { 1490330266465570, 1858795661361448, 1436241134969763, 294573218899647, 1208140011028933 },
+               { 1525827120027511, 723686461809551, 1597702369236987, 244802101764964, 1502833890372311 } },
+       {       { 2041668749310338, 2184405322203901, 1633400637611036, 2110682505536899, 2048144390084644 },   /* 7 * 16^18 */
+               { 113622036244513, 1233740067745854, 674109952278496, 2114345180342965, 166764512856263 },
+               { 503058759232932, 760293024620937, 2027152777219493, 666858468148475, 1539184379870952 } },
+       {       { 678039535434506, 570587290189340, 1605302676614120, 2147762562875701, 1706063797091704 },     /* 8 * 16^18 */
+               { 1916168475367211, 915626432541343, 883217071712575, 363427871374304, 1976029821251593 },
+               { 1439489648586438, 2194580753290951, 832380563557396, 561521973970522, 584497280718389 } },
+},
+{ /* 16^20 */
+       {       { 1413466089534451, 410844090765630, 1397263346404072, 408227143123410, 1594561803147811 },     /* 1 * 16^20 */
+               { 187989455492609, 681223515948275, 1933493571072456, 1872921007304880, 488162364135671 },
+               { 2102170800973153, 719462588665004, 1479649438510153, 1097529543970028, 1302363283777685 } },
+       {       { 1146565545556377, 1661971299445212, 406681704748893, 564452436406089, 1109109865829139 },     /* 2 * 16^20 */
+               { 942065717847195, 1069313679352961, 2007341951411051, 70973416446291, 1419433790163706 },
+               { 2214421081775077, 1165671861210569, 1890453018796184, 3556249878661, 442116172656317 } },
+       {       { 615171919212796, 1523849404854568, 854560460547503, 2067097370290715, 1765325848586042 },     /* 3 * 16^20 */
+               { 753830546620811, 1666955059895019, 1530775289309243, 1119987029104146, 2164156153857580 },
+               { 1094538949313667, 1796592198908825, 870221004284388, 2025558921863561, 1699010892802384 } },
+       {       { 1014323197538413, 869150639940606, 1756009942696599, 1334952557375672, 1544945379082874 },    /* 4 * 16^20 */
+               { 1951351290725195, 1916457206844795, 198025184438026, 1909076887557595, 1938542290318919 },
+               { 764055910920305, 1603590757375439, 146805246592357, 1843313433854297, 954279890114939 } },
+       {       { 74497112547268, 740094153192149, 1745254631717581, 727713886503130, 1283034364416928 },       /* 5 * 16^20 */
+               { 80113526615750, 764536758732259, 1055139345100233, 469252651759390, 617897512431515 },
+               { 525892105991110, 1723776830270342, 1476444848991936, 573789489857760, 133864092632978 } },
+       {       { 64123227344372, 1239927720647794, 1360722983445904, 222610813654661, 62429487187991 },        /* 6 * 16^20 */
+               { 542611720192581, 1986812262899321, 1162535242465837, 481498966143464, 544600533583622 },
+               { 1793193323953132, 91096687857833, 70945970938921, 2158587638946380, 1537042406482111 } },
+       {       { 141358280486863, 91435889572504, 1087208572552643, 1829599652522921, 1193307020643647 },      /* 7 * 16^20 */
+               { 1895854577604609, 1394895708949416, 1728548428495944, 1140864900240149, 563645333603061 },
+               { 1611230858525381, 950720175540785, 499589887488610, 2001656988495019, 88977313255908 } },
+       {       { 873966876953756, 1090638350350440, 1708559325189137, 672344594801910, 1320437969700239 },     /* 8 * 16^20 */
+               { 1189080501479658, 2184348804772597, 1040818725742319, 2018318290311834, 1712060030915354 },
+               { 1508590048271766, 1131769479776094, 101550868699323, 428297785557897, 561791648661744 } },
+},
+{ /* 16^22 */
+       {       { 1781187809325462, 1697624151492346, 1381393690939988, 175194132284669, 1483054666415238 },    /* 1 * 16^22 */
+               { 756417570499462, 237882279232602, 2136263418594016, 1701968045454886, 703713185137472 },
+               { 2175517777364616, 708781536456029, 955668231122942, 1967557500069555, 2021208005604118 } },
+       {       { 1443163092879439, 391875531646162, 2180847134654632, 464538543018753, 1594098196837178 },     /* 2 * 16^22 */
+               { 1115135966606887, 224217372950782, 915967306279222, 593866251291540, 561747094208006 },
+               { 850858855888869, 319436476624586, 327807784938441, 740785849558761, 17128415486016 } },
+       {       { 1525176236978354, 974205476721062, 293436255662638, 148269621098039, 137961998433963 },       /* 3 * 16^22 */
+               { 2132756334090067, 536247820155645, 48907151276867, 608473197600695, 1261689545022784 },
+               { 1121075518299410, 2071745529082111, 1265567917414828, 1648196578317805, 496232102750820 } },
+       {       { 654925550560074, 1168810995576858, 575655959430926, 905758704861388, 496774564663534 },       /* 4 * 16^22 */
+               { 122321229299801, 1022922077493685, 2001275453369484, 2017441881607947, 993205880778002 },
+               { 1954109525779738, 2117022646152485, 338102630417180, 1194140505732026, 107881734943492 } },
+       {       { 106431476499341, 62482972120563, 1513446655109411, 807258751769522, 538491469114 },   /* 5 * 16^22 */
+               { 1714785840001267, 2036500018681589, 1876380234251966, 2056717182974196, 1645855254384642 },
+               { 2002850762893643, 1243624520538135, 1486040410574605, 2184752338181213, 378495998083531 } },
+       {       { 1867998812076769, 715425053580701, 39968586461416, 2173068014586163, 653822651801304 },       /* 6 * 16^22 */
+               { 922510868424903, 1089502620807680, 402544072617374, 1131446598479839, 1290278588136533 },
+               { 162892278589453, 182585796682149, 75093073137630, 497037941226502, 133871727117371 } },
+       {       { 1949315551096831, 1069003344994464, 1939165033499916, 1548227205730856, 1933767655861407 },   /* 7 * 16^22 */
+               { 1914596576579670, 1608999621851578, 1987629837704609, 1519655314857977, 1819193753409464 },
+               { 1730519386931635, 1393284965610134, 1597143735726030, 416032382447158, 1429665248828629 } },
+       {       { 47602113726801, 1522314509708010, 437706261372925, 814035330438027, 335930650933545 },        /* 8 * 16^22 */
+               { 360275475604565, 547835731063078, 215360904187529, 596646739879007, 332709650425085 },
+               { 1291597595523886, 1058020588994081, 402837842324045, 1363323695882781, 2105763393033193 } },
+},
+{ /* 16^24 */
+       {       { 2156991030936798, 2227544497153325, 1869050094431622, 754875860479115, 1754242344267058 },    /* 1 * 16^24 */
+               { 109521982566564, 1715257748585139, 1112231216891516, 2046641005101484, 134249157157013 },
+               { 1846089562873800, 98894784984326, 1412430299204844, 171351226625762, 1100604760929008 } },
+       {       { 868309334532756, 1703010512741873, 1952690008738057, 4325269926064, 2071083554962116 },       /* 2 * 16^24 */
+               { 84172382130492, 499710970700046, 425749630620778, 1762872794206857, 612842602127960 },
+               { 523094549451158, 401938899487815, 1407690589076010, 2022387426254453, 158660516411257 } },
+       {       { 1723848973783452, 2208822520534681, 1718748322776940, 1974268454121942, 1194212502258141 },   /* 3 * 16^24 */
+               { 612867287630009, 448212612103814, 571629077419196, 1466796750919376, 1728478129663858 },
+               { 1254114807944608, 977770684047110, 2010756238954993, 1783628927194099, 1525962994408256 } },
+       {       { 767338676040683, 754089548318405, 1523192045639075, 435746025122062, 512692508440385 },       /* 4 * 16^24 */
+               { 232464058235826, 1948628555342434, 1835348780427694, 1031609499437291, 64472106918373 },
+               { 1255955808701983, 1700487367990941, 1166401238800299, 1175121994891534, 1190934801395380 } },
+       {       { 877519947135419, 2172838026132651, 272304391224129, 1655143327559984, 886229406429814 },      /* 5 * 16^24 */
+               { 349144008168292, 1337012557669162, 1475912332999108, 1321618454900458, 47611291904320 },
+               { 375806028254706, 214463229793940, 572906353144089, 572168269875638, 697556386112979 } },
+       {       { 1948116082078088, 2054898304487796, 2204939184983900, 210526805152138, 786593586607626 },     /* 6 * 16^24 */
+               { 1168827102357844, 823864273033637, 2071538752104697, 788062026895924, 599578340743362 },
+               { 1915320147894736, 156481169009469, 655050471180417, 592917090415421, 2165897438660879 } },
+       {       { 829996854845988, 217061778005138, 1686565909803640, 1346948817219846, 1723823550730181 },     /* 7 * 16^24 */
+               { 1726336468579724, 1119932070398949, 1929199510967666, 33918788322959, 1836837863503150 },
+               { 384301494966394, 687038900403062, 2211195391021739, 254684538421383, 1245698430589680 } },
+       {       { 1449077384734201, 38285445457996, 2136537659177832, 2146493000841573, 725161151123125 },      /* 8 * 16^24 */
+               { 1247567493562688, 1978182094455847, 183871474792955, 806570235643435, 288461518067916 },
+               { 1201928866368855, 800415690605445, 1703146756828343, 997278587541744, 1858284414104014 } },
+},
+{ /* 16^26 */
+       {       { 759628738230460, 1012693474275852, 353780233086498, 246080061387552, 2030378857679162 },      /* 1 * 16^26 */
+               { 356468809648877, 782373916933152, 1718002439402870, 1392222252219254, 663171266061951 },
+               { 2040672435071076, 888593182036908, 1298443657189359, 1804780278521327, 354070726137060 } },
+       {       { 207937160991127, 12966911039119, 820997788283092, 1010440472205286, 1701372890140810 },       /* 2 * 16^26 */
+               { 1894938527423184, 1463213041477277, 474410505497651, 247294963033299, 877975941029128 },
+               { 218882774543183, 533427444716285, 1233243976733245, 435054256891319, 1509568989549904 } },
+       {       { 299137589460312, 1594371588983567, 868058494039073, 257771590636681, 1805012993142921 },      /* 3 * 16^26 */
+               { 1888838535711826, 1052177758340622, 1213553803324135, 169182009127332, 463374268115872 },
+               { 1806842755664364, 2098896946025095, 1356630998422878, 1458279806348064, 347755825962072 } },
+       {       { 665506704253369, 273770475169863, 799236974202630, 848328990077558, 1811448782807931 },       /* 4 * 16^26 */
+               { 1402334161391744, 1560083671046299, 1008585416617747, 1147797150908892, 1420416683642459 },
+               { 1468412523962641, 771866649897997, 1931766110147832, 799561180078482, 524837559150077 } },
+       {       { 1266603897524861, 156378408858100, 1275649024228779, 447738405888420, 253186462063095 },      /* 5 * 16^26 */
+               { 2223212657821850, 630416247363666, 2144451165500328, 816911130947791, 1024351058410032 },
+               { 2022215964509735, 136144366993649, 1800716593296582, 1193970603800203, 871675847064218 } },
+       {       { 1228168094547481, 334133883362894, 587567568420081, 433612590281181, 603390400373205 },       /* 6 * 16^26 */
+               { 1862751661970328, 851596246739884, 1519315554814041, 1542798466547449, 1417975335901520 },
+               { 121893973206505, 1843345804916664, 1703118377384911, 497810164760654, 101150811654673 } },
+       {       { 584322311184395, 380661238802118, 114839394528060, 655082270500073, 2111856026034852 },       /* 7 * 16^26 */
+               { 458346255946468, 290909935619344, 1452768413850679, 550922875254215, 1537286854336538 },
+               { 996965581008991, 2148998626477022, 1012273164934654, 1073876063914522, 1688031788934939 } },
+       {       { 1697697887804317, 1335343703828273, 831288615207040, 949416685250051, 288760277392022 },      /* 8 * 16^26 */
+               { 923487018849600, 2085106799623355, 528082801620136, 1606206360876188, 735907091712524 },
+               { 1419122478109648, 1325574567803701, 602393874111094, 2107893372601700, 1314159682671307 } },
+},
+{ /* 16^28 */
+       {       { 1173339555550611, 818605084277583, 47521504364289, 924108720564965, 735423405754506 },        /* 1 * 16^28 */
+               { 2201150872731804, 2180241023425241, 97663456423163, 1633405770247824, 848945042443986 },
+               { 830104860549448, 1886653193241086, 1600929509383773, 1475051275443631, 286679780900937 } },
+       {       { 278388655910247, 487143369099838, 927762205508727, 181017540174210, 1616886700741287 },       /* 2 * 16^28 */
+               { 1577111294832995, 1030899169768747, 144900916293530, 1964672592979567, 568390100955250 },
+               { 1191033906638969, 940823957346562, 1606870843663445, 861684761499847, 658674867251089 } },
+       {       { 622869792298357, 1903919278950367, 1922588621661629, 1520574711600434, 1087100760174640 },    /* 3 * 16^28 */
+               { 1875032594195546, 1427106132796197, 724736390962158, 901860512044740, 635268497268760 },
+               { 25465949416618, 1693639527318811, 1526153382657203, 125943137857169, 145276964043999 } },
+       {       { 2006245852772938, 734762734836159, 254642929763427, 1406213292755966, 239303749517686 },      /* 4 * 16^28 */
+               { 214739857969358, 920212862967915, 1939901550972269, 1211862791775221, 85097515720120 },
+               { 1619678837192149, 1919424032779215, 1357391272956794, 1525634040073113, 1310226789796241 } },
+       {       { 1996723311435669, 1844342766567060, 985455700466044, 1165924681400960, 311508689870129 },     /* 5 * 16^28 */
+               { 1040763709762123, 1704449869235352, 605263070456329, 1998838089036355, 1312142911487502 },
+               { 43173156290518, 2202883069785309, 1137787467085917, 1733636061944606, 1394992037553852 } },
+       {       { 2197214573372804, 794254097241315, 1030190060513737, 267632515541902, 2040478049202624 },     /* 6 * 16^28 */
+               { 670078326344559, 555655025059356, 471959386282438, 2141455487356409, 849015953823125 },
+               { 1812516004670529, 1609256702920783, 1706897079364493, 258549904773295, 996051247540686 } },
+       {       { 1323460699404750, 1262690757880991, 871777133477900, 1060078894988977, 1712236889662886 },    /* 7 * 16^28 */
+               { 1540374301420584, 1764656898914615, 1810104162020396, 923808779163088, 664390074196579 },
+               { 1696163952057966, 1391710137550823, 608793846867416, 1034391509472039, 1780770894075012 } },
+       {       { 597536315471731, 40375058742586, 1942256403956049, 1185484645495932, 312666282024145 },       /* 8 * 16^28 */
+               { 1367603834210841, 2131988646583224, 890353773628144, 1908908219165595, 270836895252891 },
+               { 1919411405316294, 1234508526402192, 1066863051997083, 1008444703737597, 1348810787701552 } },
+},
+{ /* 16^30 */
+       {       { 1853931367696942, 8107973870707, 350214504129299, 775206934582587, 1752317649166792 },        /* 1 * 16^30 */
+               { 2102881477513865, 1570274565945361, 1573617900503708, 18662635732583, 2232324307922098 },
+               { 1417148368003523, 721357181628282, 505725498207811, 373232277872983, 261634707184480 } },
+       {       { 1268116367301224, 560157088142809, 802626839600444, 2210189936605713, 1129993785579988 },     /* 2 * 16^30 */
+               { 2186733281493267, 2250694917008620, 1014829812957440, 479998161452389, 83566193876474 },
+               { 615183387352312, 917611676109240, 878893615973325, 978940963313282, 938686890583575 } },
+       {       { 1799679152208884, 912132775900387, 25967768040979, 432130448590461, 274568990261996 },        /* 3 * 16^30 */
+               { 522024729211672, 1045059315315808, 1892245413707790, 1907891107684253, 2059998109500714 },
+               { 98698809797682, 2144627600856209, 1907959298569602, 811491302610148, 1262481774981493 } },
+       {       { 1217809823321928, 2173947284933160, 1986927836272325, 1388114931125539, 12686131160169 },     /* 4 * 16^30 */
+               { 1791451399743152, 1713538728337276, 118349997257490, 1882306388849954, 158235232210248 },
+               { 1650875518872272, 1136263858253897, 1732115601395988, 734312880662190, 1252904681142109 } },
+       {       { 803147181835288, 868941437997146, 316299302989663, 943495589630550, 571224287904572 },        /* 5 * 16^30 */
+               { 372986456113865, 525430915458171, 2116279931702135, 501422713587815, 1907002872974925 },
+               { 227742695588364, 1776969298667369, 628602552821802, 457210915378118, 2041906378111140 } },
+       {       { 1580216071604333, 1877997504342444, 857147161260913, 703522726778478, 2182763974211603 },     /* 6 * 16^30 */
+               { 815000523470260, 913085688728307, 1052060118271173, 1345536665214223, 541623413135555 },
+               { 1870080310923419, 71988220958492, 1783225432016732, 615915287105016, 1035570475990230 } },
+       {       { 377616581647602, 1581980403078513, 804044118130621, 2034382823044191, 643844048472185 },      /* 7 * 16^30 */
+               { 730987750830150, 857613889540280, 1083813157271766, 1002817255970169, 1719228484436074 },
+               { 176957326463017, 1573744060478586, 528642225008045, 1816109618372371, 1515140189765006 } },
+       {       { 443392177002051, 233793396845137, 2199506622312416, 1011858706515937, 974676837063129 },      /* 8 * 16^30 */
+               { 1888911448245718, 1387110895611080, 1924503794066429, 1731539523700949, 2230378382645454 },
+               { 1846351103143623, 1949984838808427, 671247021915253, 1946756846184401, 1929296930380217 } },
+},
+{ /* 16^32 */
+       {       { 692017667358279, 723305578826727, 1638042139863265, 748219305990306, 334589200523901 },       /* 1 * 16^32 */
+               { 849646212452002, 1410198775302919, 73767886183695, 1641663456615812, 762256272452411 },
+               { 22893968530686, 2235758574399251, 1661465835630252, 925707319443452, 1203475116966621 } },
+       {       { 903105258014366, 427141894933047, 561187017169777, 1884330244401954, 1914145708422219 },      /* 2 * 16^32 */
+               { 801299035785166, 1733292596726131, 1664508947088596, 467749120991922, 1647498584535623 },
+               { 1344191060517578, 1960935031767890, 1518838929955259, 1781502350597190, 1564784025565682 } },
+       {       { 1917185587363432, 1098342571752737, 5935801044414, 2000527662351839, 1538640296181569 },      /* 3 * 16^32 */
+               { 673723351748086, 1979969272514923, 1175287312495508, 1187589090978666, 1881897672213940 },
+               { 2495540013192, 678856913479236, 224998292422872, 219635787698590, 1972465269000940 } },
+       {       { 194583029968109, 514316781467765, 829677956235672, 1676415686873082, 810104584395840 },       /* 4 * 16^32 */
+               { 271413961212179, 1353052061471651, 344711291283483, 2014925838520662, 2006221033113941 },
+               { 1980510813313589, 1948645276483975, 152063780665900, 129968026417582, 256984195613935 } },
+       {       { 796664815624365, 1543160838872951, 1500897791837765, 1667315977988401, 599303877030711 },     /* 5 * 16^32 */
+               { 1860190562533102, 1936576191345085, 461100292705964, 1811043097042830, 957486749306835 },
+               { 1151480509533204, 2136010406720455, 738796060240027, 319298003765044, 1150614464349587 } },
+       {       { 1017222050227968, 1987716148359, 2234319589635701, 621282683093392, 2132553131763026 },       /* 6 * 16^32 */
+               { 1731069268103150, 735642447616087, 1364750481334268, 417232839982871, 927108269127661 },
+               { 1567828528453324, 1017807205202360, 565295260895298, 829541698429100, 307243822276582 } },
+       {       { 2089966982947227, 1854140343916181, 2151980759220007, 2139781292261749, 158070445864917 },    /* 7 * 16^32 */
+               { 249079270936248, 1501514259790706, 947909724204848, 944551802437487, 552658763982480 },
+               { 1338766321464554, 1906702607371284, 1519569445519894, 115384726262267, 1393058953390992 } },
+       {       { 1884844597333588, 601480070269079, 620203503079537, 1079527400117915, 1202076693132015 },     /* 8 * 16^32 */
+               { 1364621558265400, 1512388234908357, 1926731583198686, 2041482526432505, 920401122333774 },
+               { 840922919763324, 727955812569642, 1303406629750194, 522898432152867, 294161410441865 } },
+},
+{ /* 16^34 */
+       {       { 359856369838236, 180914355488683, 861726472646627, 218807937262986, 575626773232501 },        /* 1 * 16^34 */
+               { 353760790835310, 1598361541848743, 1122905698202299, 1922533590158905, 419107700666580 },
+               { 755467689082474, 909202735047934, 730078068932500, 936309075711518, 2007798262842972 } },
+       {       { 984339177776787, 815727786505884, 1645154585713747, 1659074964378553, 1686601651984156 },     /* 2 * 16^34 */
+               { 1609384177904073, 362745185608627, 1335318541768201, 800965770436248, 547877979267412 },
+               { 1697863093781930, 599794399429786, 1104556219769607, 830560774794755, 12812858601017 } },
+       {       { 1856930662813910, 678090852002597, 1920179140755167, 1259527833759868, 55540971895511 },      /* 3 * 16^34 */
+               { 1168737550514982, 897832437380552, 463140296333799, 302564600022547, 2008360505135501 },
+               { 1158643631044921, 476554103621892, 178447851439725, 1305025542653569, 103433927680625 } },
+       {       { 825403285195098, 2144208587560784, 1925552004644643, 1915177840006985, 1015952128947864 },    /* 4 * 16^34 */
+               { 2176793111709008, 1576725716350391, 2009350167273523, 2012390194631546, 2125297410909580 },
+               { 1807108316634472, 1534392066433717, 347342975407218, 1153820745616376, 7375003497471 } },
+       {       { 228567918409756, 865093958780220, 358083886450556, 159617889659320, 1360637926292598 },       /* 5 * 16^34 */
+               { 983061001799725, 431211889901241, 2201903782961093, 817393911064341, 2214616493042167 },
+               { 234147501399755, 2229469128637390, 2175289352258889, 1397401514549353, 1885288963089922 } },
+       {       { 1113790697840279, 1051167139966244, 1045930658550944, 2011366241542643, 1686166824620755 },   /* 6 * 16^34 */
+               { 1111762412951562, 252849572507389, 1048714233823341, 146111095601446, 1237505378776770 },
+               { 1054097349305049, 1872495070333352, 182121071220717, 1064378906787311, 100273572924182 } },
+       {       { 104233794644221, 1548919791188248, 2224541913267306, 2054909377116478, 1043803389015153 },    /* 7 * 16^34 */
+               { 1306410853171605, 1627717417672447, 50983221088417, 1109249951172250, 870201789081392 },
+               { 216762189468802, 707284285441622, 190678557969733, 973969342604308, 1403009538434867 } },
+       {       { 343805853118335, 1302216857414201, 566872543223541, 2051138939539004, 321428858384280 },      /* 8 * 16^34 */
+               { 1279024291038477, 344776835218310, 273722096017199, 1834200436811442, 634517197663804 },
+               { 470067171324852, 1618629234173951, 2000092177515639, 7307679772789, 1117521120249968 } },
+},
+{ /* 16^36 */
+       {       { 577009397403102, 1791440261786291, 2177643735971638, 174546149911960, 1412505077782326 },     /* 1 * 16^36 */
+               { 278151578291475, 1810282338562947, 1771599529530998, 1383659409671631, 685373414471841 },
+               { 893719721537457, 1201282458018197, 1522349501711173, 58011597740583, 1130406465887139 } },
+       {       { 262483770854550, 990511055108216, 526885552771698, 571664396646158, 354086190278723 },        /* 2 * 16^36 */
+               { 412607348255453, 1280455764199780, 2233277987330768, 14180080401665, 331584698417165 },
+               { 1820352417585487, 24495617171480, 1547899057533253, 10041836186225, 480457105094042 } },
+       {       { 1144168702609745, 604444390410187, 1544541121756138, 1925315550126027, 626401428894002 },     /* 3 * 16^36 */
+               { 2023310314989233, 637905337525881, 2106474638900687, 557820711084072, 1687858215057826 },
+               { 1922168257351784, 2018674099908659, 1776454117494445, 956539191509034, 36031129147635 } },
+       {       { 58242421545916, 2035812695641843, 2118491866122923, 1191684463816273, 46921517454099 },       /* 4 * 16^36 */
+               { 544644538748041, 1039872944430374, 876750409130610, 710657711326551, 1216952687484972 },
+               { 272268252444639, 1374166457774292, 2230115177009552, 1053149803909880, 1354288411641016 } },
+       {       { 1193437069800958, 901107149704790, 999672920611411, 477584824802207, 364239578697845 },       /* 5 * 16^36 */
+               { 1857910905368338, 1754729879288912, 885945464109877, 1516096106802166, 1602902393369811 },
+               { 886299989548838, 1538292895758047, 1590564179491896, 1944527126709657, 837344427345298 } },
+       {       { 1309847803895382, 1462151862813074, 211370866671570, 1544595152703681, 1027691798954090 },    /* 6 * 16^36 */
+               { 754558365378305, 1712186480903618, 1703656826337531, 750310918489786, 518996040250900 },
+               { 803217563745370, 1884799722343599, 1357706345069218, 2244955901722095, 730869460037413 } },
+       {       { 696351368613042, 1494385251239250, 738037133616932, 636385507851544, 927483222611406 },       /* 7 * 16^36 */
+               { 689299471295966, 1831210565161071, 1375187341585438, 1106284977546171, 1893781834054269 },
+               { 1949114198209333, 1104419699537997, 783495707664463, 1747473107602770, 2002634765788641 } },
+       {       { 1068900648804224, 2006891997072550, 1134049269345549, 1638760646180091, 2055396084625778 },   /* 8 * 16^36 */
+               { 1607325776830197, 530883941415333, 1451089452727895, 1581691157083423, 496100432831154 },
+               { 2222475519314561, 1870703901472013, 1884051508440561, 1344072275216753, 1318025677799069 } },
+},
+{ /* 16^38 */
+       {       { 7813206966729, 194444201427550, 2071405409526507, 1065605076176312, 1645486789731291 },       /* 1 * 16^38 */
+               { 155711679280656, 681100400509288, 389811735211209, 2135723811340709, 408733211204125 },
+               { 16625790644959, 1647648827778410, 1579910185572704, 436452271048548, 121070048451050 } },
+       {       { 190565267697443, 672855706028058, 338796554369226, 337687268493904, 853246848691734 },        /* 2 * 16^38 */
+               { 1037263028552531, 568385780377829, 297953104144430, 1558584511931211, 2238221839292471 },
+               { 1763863028400139, 766498079432444, 1321118624818005, 69494294452268, 858786744165651 } },
+       {       { 366253102478259, 525676242508811, 1449610995265438, 1183300845322183, 185960306491545 },      /* 3 * 16^38 */
+               { 1292056768563024, 1456632109855638, 1100631247050184, 1386133165675321, 1232898350193752 },
+               { 28315355815982, 460422265558930, 1799675876678724, 1969256312504498, 1051823843138725 } },
+       {       { 54684536365732, 2210010038536222, 1194984798155308, 535239027773705, 1516355079301361 },      /* 4 * 16^38 */
+               { 156914999361983, 1606148405719949, 1665208410108430, 317643278692271, 1383783705665320 },
+               { 1484387703771650, 198537510937949, 2186282186359116, 617687444857508, 647477376402122 } },
+       {       { 159386186465542, 1877626593362941, 618737197060512, 1026674284330807, 1158121760792685 },     /* 5 * 16^38 */
+               { 2147715541830533, 500032538445817, 646380016884826, 352227855331122, 1488268620408052 },
+               { 1744544377739822, 1964054180355661, 1685781755873170, 2169740670377448, 1286112621104591 } },
+       {       { 1602253788689063, 439542044889886, 2220348297664483, 657877410752869, 157451572512238 },      /* 6 * 16^38 */
+               { 81977249784993, 1667943117713086, 1668983819634866, 1605016835177615, 1353960708075544 },
+               { 1029287186166717, 65860128430192, 525298368814832, 1491902500801986, 1461064796385400 } },
+       {       { 1185483484383269, 1356339572588553, 584932367316448, 102132779946470, 1792922621116791 },     /* 7 * 16^38 */
+               { 408216988729246, 2121095722306989, 913562102267595, 1879708920318308, 241061448436731 },
+               { 1966196870701923, 2230044620318636, 1425982460745905, 261167817826569, 46517743394330 } },
+       {       { 1730194207717538, 431790042319772, 1831515233279467, 1372080552768581, 1074513929381760 },    /* 8 * 16^38 */
+               { 107077591595359, 884959942172345, 27306869797400, 2224911448949390, 964352058245223 },
+               { 1450880638731607, 1019861580989005, 1229729455116861, 1174945729836143, 826083146840706 } },
+},
+{ /* 16^40 */
+       {       { 2136688454840028, 2099509000964294, 1690800495246475, 1217643678575476, 828720645084218 },    /* 1 * 16^40 */
+               { 1899935429242705, 1602068751520477, 940583196550370, 82431069053859, 1540863155745696 },
+               { 765548025667841, 462473984016099, 998061409979798, 546353034089527, 2212508972466858 } },
+       {       { 1801436127943107, 1734436817907890, 1268728090345068, 167003097070711, 2233597765834956 },    /* 2 * 16^40 */
+               { 46575283771160, 892570971573071, 1281983193144090, 1491520128287375, 75847005908304 },
+               { 1997562060465113, 1048700225534011, 7615603985628, 1855310849546841, 2242557647635213 } },
+       {       { 1357044908364776, 729130645262438, 1762469072918979, 1365633616878458, 181282906404941 },     /* 3 * 16^40 */
+               { 1161017320376250, 492624580169043, 2169815802355237, 976496781732542, 1770879511019629 },
+               { 1080413443139865, 1155205815510486, 1848782073549786, 622566975152580, 124965574467971 } },
+       {       { 2020536369003019, 202261491735136, 1053169669150884, 2056531979272544, 778165514694311 },     /* 4 * 16^40 */
+               { 1184526762066993, 247622751762817, 692129017206356, 820018689412496, 2188697339828085 },
+               { 237404399610207, 1308324858405118, 1229680749538400, 720131409105291, 1958958863624906 } },
+       {       { 281527309158085, 36970532401524, 866906920877543, 2222282602952734, 1289598729589882 },       /* 5 * 16^40 */
+               { 515583508038846, 17656978857189, 1717918437373989, 1568052070792483, 46975803123923 },
+               { 1278207464902042, 494742455008756, 1262082121427081, 1577236621659884, 1888786707293291 } },
+       {       { 2064251142068628, 1666421603389706, 1419271365315441, 468767774902855, 191535130366583 },     /* 6 * 16^40 */
+               { 353042527954210, 1830056151907359, 1111731275799225, 174960955838824, 404312815582675 },
+               { 1716987058588002, 1859366439773457, 1767194234188234, 64476199777924, 1117233614485261 } },
+       {       { 298845952651262, 1166086588952562, 1179896526238434, 1347812759398693, 1412945390096208 },    /* 7 * 16^40 */
+               { 984292135520292, 135138246951259, 2220652137473167, 1722843421165029, 190482558012909 },
+               { 1143239552672925, 906436640714209, 2177000572812152, 2075299936108548, 325186347798433 } },
+       {       { 418098668140962, 715065997721283, 1471916138376055, 2168570337288357, 937812682637044 },      /* 8 * 16^40 */
+               { 721024854374772, 684487861263316, 1373438744094159, 2193186935276995, 1387043709851261 },
+               { 1043584187226485, 2143395746619356, 2209558562919611, 482427979307092, 847556718384018 } },
+},
+{ /* 16^42 */
+       {       { 1057329623869501, 620334067429122, 461700859268034, 2012481616501857, 297268569108938 },      /* 1 * 16^42 */
+               { 1248731221520759, 1465200936117687, 540803492710140, 52978634680892, 261434490176109 },
+               { 1055352180870759, 1553151421852298, 1510903185371259, 1470458349428097, 1226259419062731 } },
+       {       { 47000654413729, 1004754424173864, 1868044813557703, 173236934059409, 588771199737015 },       /* 2 * 16^42 */
+               { 1492988790301668, 790326625573331, 1190107028409745, 1389394752159193, 1620408196604194 },
+               { 30498470091663, 1082245510489825, 576771653181956, 806509986132686, 1317634017056939 } },
+       {       { 1115636332012334, 1854340990964155, 83792697369514, 1972177451994021, 457455116057587 },      /* 3 * 16^42 */
+               { 420308055751555, 1493354863316002, 165206721528088, 1884845694919786, 2065456951573059 },
+               { 1698968457310898, 1435137169051090, 1083661677032510, 938363267483709, 340103887207182 } },
+       {       { 241719380661528, 310028521317150, 1215881323380194, 1408214976493624, 2141142156467363 },     /* 4 * 16^42 */
+               { 1995325341336574, 911500251774648, 164010755403692, 855378419194762, 1573601397528842 },
+               { 1315157046163473, 727368447885818, 1363466668108618, 1668921439990361, 1398483384337907 } },
+       {       { 2053597130993710, 2024431685856332, 2233550957004860, 2012407275509545, 872546993104440 },    /* 5 * 16^42 */
+               { 75029678299646, 1015388206460473, 1849729037055212, 1939814616452984, 444404230394954 },
+               { 1217269667678610, 599909351968693, 1390077048548598, 1471879360694802, 739586172317596 } },
+       {       { 2132502667405250, 214379346175414, 1502748313768060, 1960071701057800, 1353971822643138 },    /* 6 * 16^42 */
+               { 1718318639380794, 1560510726633958, 904462881159922, 1418028351780052, 94404349451937 },
+               { 319394212043702, 2127459436033571, 717646691535162, 663366796076914, 318459064945314 } },
+       {       { 947085906234007, 323284730494107, 1485778563977200, 728576821512394, 901584347702286 },       /* 7 * 16^42 */
+               { 405989424923593, 1960452633787083, 667349034401665, 1492674260767112, 1451061489880787 },
+               { 1575783124125742, 2126210792434375, 1569430791264065, 1402582372904727, 1891780248341114 } },
+       {       { 739152638255629, 2074935399403557, 505483666745895, 1611883356514088, 628654635394878 },      /* 8 * 16^42 */
+               { 838432205560695, 1997703511451664, 1018791879907867, 1662001808174331, 78328132957753 },
+               { 1822054032121349, 643057948186973, 7306757352712, 577249257962099, 284735863382083 } },
+},
+{ /* 16^44 */
+       {       { 204146226972102, 1630511199034723, 2215235214174763, 174665910283542, 956127674017216 },      /* 1 * 16^44 */
+               { 1366558556363930, 1448606567552086, 1478881020944768, 165803179355898, 1115718458123498 },
+               { 1562934578796716, 1070893489712745, 11324610642270, 958989751581897, 2172552325473805 } },
+       {       { 623682558650637, 1337866509471512, 990313350206649, 1314236615762469, 1164772974270275 },     /* 2 * 16^44 */
+               { 1770564423056027, 735523631664565, 1326060113795289, 1509650369341127, 65892421582684 },
+               { 223256821462517, 723690150104139, 1000261663630601, 933280913953265, 254872671543046 } },
+       {       { 1236103475266979, 1837885883267218, 1026072585230455, 1025865513954973, 1801964901432134 },   /* 3 * 16^44 */
+               { 1969087237026041, 624795725447124, 1335555107635969, 2069986355593023, 1712100149341902 },
+               { 1115241013365517, 1712251818829143, 2148864332502771, 2096001471438138, 2235017246626125 } },
+       {       { 118352772338543, 1067608711804704, 1434796676193498, 1683240170548391, 230866769907437 },     /* 4 * 16^44 */
+               { 1299268198601632, 2047148477845621, 2165648650132450, 1612539282026145, 514197911628890 },
+               { 1850689576796636, 1601590730430274, 1139674615958142, 1954384401440257, 76039205311 } },
+       {       { 2146711623855116, 503278928021499, 625853062251406, 1109121378393107, 1033853809911861 },     /* 5 * 16^44 */
+               { 1723387471374172, 997301467038410, 533927635123657, 20928644693965, 1756575222802513 },
+               { 571005965509422, 2005213373292546, 1016697270349626, 56607856974274, 914438579435146 } },
+       {       { 1769967932677654, 1695893319756416, 1151863389675920, 1781042784397689, 400287774418285 },    /* 6 * 16^44 */
+               { 1346698876211176, 2076651707527589, 1084761571110205, 265334478828406, 1068954492309671 },
+               { 1851867764003121, 403841933237558, 820549523771987, 761292590207581, 1743735048551143 } },
+       {       { 285945406881439, 648174397347453, 1098403762631981, 1366547441102991, 1505876883139217 },     /* 7 * 16^44 */
+               { 410915148140008, 2107072311871739, 1004367461876503, 99684895396761, 1180818713503224 },
+               { 672095903120153, 1675918957959872, 636236529315028, 1569297300327696, 2164144194785875 } },
+       {       { 1615357281742403, 404257611616381, 2160201349780978, 1160947379188955, 1578038619549541 },    /* 8 * 16^44 */
+               { 1902708175321798, 1035343530915438, 1178560808893263, 301095684058146, 1280977479761118 },
+               { 2013087639791217, 822734930507457, 1785668418619014, 1668650702946164, 389450875221715 } },
+},
+{ /* 16^46 */
+       {       { 1295082798350326, 2091844511495996, 1851348972587817, 3375039684596, 789440738712837 },       /* 1 * 16^46 */
+               { 453918449698368, 106406819929001, 2072540975937135, 308588860670238, 1304394580755385 },
+               { 2083069137186154, 848523102004566, 993982213589257, 1405313299916317, 1532824818698468 } },
+       {       { 1782411379088302, 1096724939964781, 27593390721418, 542241850291353, 1540337798439873 },      /* 2 * 16^46 */
+               { 1495961298852430, 1397203457344779, 1774950217066942, 139302743555696, 66603584342787 },
+               { 693543956581437, 171507720360750, 1557908942697227, 1074697073443438, 1104093109037196 } },
+       {       { 231429562203065, 1526290236421172, 2021375064026423, 1520954495658041, 806337791525116 },     /* 3 * 16^46 */
+               { 345288228393419, 1099643569747172, 134881908403743, 1740551994106740, 248212179299770 },
+               { 1079623667189886, 872403650198613, 766894200588288, 2163700860774109, 2023464507911816 } },
+       {       { 1497138821904622, 1044820250515590, 1742593886423484, 1237204112746837, 849047450816987 },    /* 4 * 16^46 */
+               { 854645372543796, 1936406001954827, 151460662541253, 825325739271555, 1554306377287556 },
+               { 667962773375330, 1897271816877105, 1399712621683474, 1143302161683099, 2081798441209593 } },
+       {       { 1072409664800960, 2146937497077528, 1508780108920651, 935767602384853, 1112800433544068 },    /* 5 * 16^46 */
+               { 127147851567005, 1936114012888110, 1704424366552046, 856674880716312, 716603621335359 },
+               { 333549023751292, 280219272863308, 2104176666454852, 1036466864875785, 536135186520207 } },
+       {       { 1186115062588401, 2251609796968486, 1098944457878953, 1153112761201374, 1791625503417267 },   /* 6 * 16^46 */
+               { 373666279883137, 146457241530109, 304116267127857, 416088749147715, 1258577131183391 },
+               { 1870078460219737, 2129630962183380, 852283639691142, 292865602592851, 401904317342226 } },
+       {       { 1546301003424277, 459094500062839, 1097668518375311, 1780297770129643, 720763293687608 },     /* 7 * 16^46 */
+               { 1361070124828035, 815664541425524, 1026798897364671, 1951790935390647, 555874891834790 },
+               { 1212405311403990, 1536693382542438, 61028431067459, 1863929423417129, 1223219538638038 } },
+       {       { 339050984211414, 601386726509773, 413735232134068, 966191255137228, 1839475899458159 },       /* 8 * 16^46 */
+               { 1294303766540260, 1183557465955093, 882271357233093, 63854569425375, 2213283684565087 },
+               { 235605972169408, 2174055643032978, 1538335001838863, 1281866796917192, 1815940222628465 } },
+},
+{ /* 16^48 */
+       {       { 35271216625062, 1712350667021807, 983664255668860, 98571260373038, 1232645608559836 },        /* 1 * 16^48 */
+               { 1632352921721536, 1833328609514701, 2092779091951987, 1923956201873226, 2210068022482919 },
+               { 1998172393429622, 1798947921427073, 784387737563581, 1589352214827263, 1589861734168180 } },
+       {       { 846415389605137, 746163495539180, 829658752826080, 592067705956946, 957242537821393 },        /* 2 * 16^48 */
+               { 1733739258725305, 31715717059538, 201969945218860, 992093044556990, 1194308773174556 },
+               { 1758148849754419, 619249044817679, 168089007997045, 1371497636330523, 1867101418880350 } },
+       {       { 1714182387328607, 1477856482074168, 574895689942184, 2159118410227270, 1555532449716575 },    /* 3 * 16^48 */
+               { 326633984209635, 261759506071016, 1700682323676193, 1577907266349064, 1217647663383016 },
+               { 853828206885131, 998498946036955, 1835887550391235, 207627336608048, 258363815956050 } },
+       {       { 1501663228068911, 1354879465566912, 1444432675498247, 897812463852601, 855062598754348 },     /* 4 * 16^48 */
+               { 141141474651677, 1236728744905256, 643101419899887, 1646615130509173, 1208239602291765 },
+               { 714380763546606, 1032824444965790, 1774073483745338, 1063840874947367, 1738680636537158 } },
+       {       { 1171650314802029, 1567085444565577, 1453660792008405, 757914533009261, 1619511342778196 },    /* 5 * 16^48 */
+               { 1640635546696252, 633168953192112, 2212651044092396, 30590958583852, 368515260889378 },
+               { 420958967093237, 971103481109486, 2169549185607107, 1301191633558497, 1661514101014240 } },
+       {       { 1121533090144639, 1021251337022187, 110469995947421, 1511059774758394, 2110035908131662 },    /* 6 * 16^48 */
+               { 907123651818302, 1332556122804146, 1824055253424487, 1367614217442959, 1982558335973172 },
+               { 303213233384524, 2061932261128138, 352862124777736, 40828818670255, 249879468482660 } },
+       {       { 1445691340537320, 40614383122127, 402104303144865, 485134269878232, 1659439323587426 },       /* 7 * 16^48 */
+               { 856559257852200, 508517664949010, 1378193767894916, 1723459126947129, 1962275756614521 },
+               { 20057458979482, 1183363722525800, 2140003847237215, 2053873950687614, 2112017736174909 } },
+       {       { 709481497028540, 531682216165724, 316963769431931, 1814315888453765, 258560242424104 },       /* 8 * 16^48 */
+               { 2228654250927986, 1483591363415267, 1368661293910956, 1076511285177291, 526650682059608 },
+               { 1053447823660455, 1955135194248683, 1010900954918985, 1182614026976701, 1240051576966610 } },
+},
+{ /* 16^50 */
+       {       { 1848942433095597, 1582009882530495, 1849292741020143, 1068498323302788, 2001402229799484 },   /* 1 * 16^50 */
+               { 1957943897155497, 1788667368028035, 137692910029106, 1039519607062, 826404763313028 },
+               { 1528282417624269, 2142492439828191, 2179662545816034, 362568973150328, 1591374675250271 } },
+       {       { 2013278155187349, 662660471354454, 793981225706267, 411706605985744, 804490933124791 },       /* 2 * 16^50 */
+               { 160026679434388, 232341189218716, 2149181472355545, 598041771119831, 183859001910173 },
+               { 2051892037280204, 488391251096321, 2230187337030708, 930221970662692, 679002758255210 } },
+       {       { 1461835919309432, 1955256480136428, 180866187813063, 1551979252664528, 557743861963950 },     /* 3 * 16^50 */
+               { 1530723630438670, 875873929577927, 341560134269988, 449903119530753, 1055551308214179 },
+               { 359179641731115, 1324915145732949, 902828372691474, 294254275669987, 1887036027752957 } },
+       {       { 2072902725256516, 312132452743412, 309930885642209, 996244312618453, 1590501300352303 },      /* 4 * 16^50 */
+               { 2043271609454323, 2038225437857464, 1317528426475850, 1398989128982787, 2027639881006861 },
+               { 1397254305160710, 695734355138021, 2233992044438756, 1776180593969996, 1085588199351115 } },
+       {       { 1950722461391320, 1907845598854797, 1822757481635527, 2121567704750244, 73811931471221 },     /* 5 * 16^50 */
+               { 440567051331029, 254894786356681, 493869224930222, 1556322069683366, 1567456540319218 },
+               { 387139307395758, 2058036430315676, 1220915649965325, 1794832055328951, 1230009312169328 } },
+       {       { 1127572801181483, 1224743760571696, 1276219889847274, 1529738721702581, 1589819666871853 },   /* 6 * 16^50 */
+               { 1765973779329517, 659344059446977, 19821901606666, 1301928341311214, 1116266004075885 },
+               { 2181229378964934, 2190885205260020, 1511536077659137, 1246504208580490, 668883326494241 } },
+       {       { 1975438052228868, 1071801519999806, 594652299224319, 1877697652668809, 1489635366987285 },    /* 7 * 16^50 */
+               { 437866655573314, 669026411194768, 81896997980338, 523874406393178, 245052060935236 },
+               { 958592545673770, 233048016518599, 851568750216589, 567703851596087, 1740300006094761 } },
+       {       { 1540769606609725, 2148289943846077, 1597804156127445, 1230603716683868, 815423458809453 },    /* 8 * 16^50 */
+               { 2014540178270324, 192672779514432, 213877182641530, 2194819933853411, 1716422829364835 },
+               { 1738560251245018, 1779576754536888, 1783765347671392, 1880170990446751, 1088225159617541 } },
+},
+{ /* 16^52 */
+       {       { 1143465490433355, 1532194726196059, 1093276745494697, 481041706116088, 2121405433561163 },    /* 1 * 16^52 */
+               { 659303913929492, 1956447718227573, 1830568515922666, 841069049744408, 1669607124206368 },
+               { 1686424298744462, 1451806974487153, 266296068846582, 1834686947542675, 1720762336132256 } },
+       {       { 1206396181488998, 333158148435054, 1402633492821422, 1120091191722026, 1945474114550509 },    /* 2 * 16^52 */
+               { 889217026388959, 1043290623284660, 856125087551909, 1669272323124636, 1603340330827879 },
+               { 766720088232571, 1512222781191002, 1189719893490790, 2091302129467914, 2141418006894941 } },
+       {       { 938160078005954, 1421776319053174, 1941643234741774, 180002183320818, 1414380336750546 },     /* 3 * 16^52 */
+               { 419663647306612, 1998875112167987, 1426599870253707, 1154928355379510, 486538532138187 },
+               { 398001940109652, 1577721237663248, 1012748649830402, 1540516006905144, 1011684812884559 } },
+       {       { 996661541407379, 1455877387952927, 744312806857277, 139213896196746, 1000282908547789 },      /* 4 * 16^52 */
+               { 1653276489969630, 6081825167624, 1921777941170836, 1604139841794531, 861211053640641 },
+               { 1450817495603008, 1476865707053229, 1030490562252053, 620966950353376, 1744760161539058 } },
+       {       { 962165956135846, 1116599660248791, 182090178006815, 1455605467021751, 196053588803284 },      /* 5 * 16^52 */
+               { 559728410002599, 37056661641185, 2038622963352006, 1637244893271723, 1026565352238948 },
+               { 796863823080135, 1897365583584155, 420466939481601, 2165972651724672, 932177357788289 } },
+       {       { 2216943882299338, 394841323190322, 2222656898319671, 558186553950529, 1077236877025190 },     /* 6 * 16^52 */
+               { 877047233620632, 1375632631944375, 643773611882121, 660022738847877, 19353932331831 },
+               { 801118384953213, 1914330175515892, 574541023311511, 1471123787903705, 1526158900256288 } },
+       {       { 1474518386765335, 1760793622169197, 1157399790472736, 1622864308058898, 165428294422792 },    /* 7 * 16^52 */
+               { 949617889087234, 2207116611267331, 912920039141287, 501158539198789, 62362560771472 },
+               { 1961673048027128, 102619413083113, 1051982726768458, 1603657989805485, 1941613251499678 } },
+       {       { 1234706593321979, 1083343891215917, 898273974314935, 1640859118399498, 157578398571149 },     /* 8 * 16^52 */
+               { 1401939116319266, 335306339903072, 72046196085786, 862423201496006, 850518754531384 },
+               { 1143483057726416, 1992614991758919, 674268662140796, 1773370048077526, 674318359920189 } },
+},
+{ /* 16^54 */
+       {       { 1506632088156630, 2127481795522179, 513812919490255, 140643715928370, 442476620300318 },      /* 1 * 16^54 */
+               { 1835401379538542, 173900035308392, 818247630716732, 1762100412152786, 1021506399448291 },
+               { 2056683376856736, 219094741662735, 2193541883188309, 1841182310235800, 556477468664293 } },
+       {       { 94096246544434, 922482381166992, 24517828745563, 2139430508542503, 2097139044231004 },        /* 2 * 16^54 */
+               { 1315019427910827, 1049075855992603, 2066573052986543, 266904467185534, 2040482348591520 },
+               { 537697207950515, 1399352016347350, 1563663552106345, 2148749520888918, 549922092988516 } },
+       {       { 323583936109569, 1973572998577657, 1192219029966558, 79354804385273, 1374043025560347 },      /* 3 * 16^54 */
+               { 1747985413252434, 680511052635695, 1809559829982725, 594274250930054, 201673170745982 },
+               { 213277331329947, 416202017849623, 1950535221091783, 1313441578103244, 2171386783823658 } },
+       {       { 1620578418245010, 541035331188469, 2235785724453865, 2154865809088198, 1974627268751826 },    /* 4 * 16^54 */
+               { 189088804229831, 993969372859110, 895870121536987, 1547301535298256, 1477373024911350 },
+               { 1346805451740245, 1350981335690626, 942744349501813, 2155094562545502, 1012483751693409 } },
+       {       { 1074666112436467, 249279386739593, 1174337926625354, 1559013532006480, 1472287775519121 },    /* 5 * 16^54 */
+               { 2107080134091762, 1132567062788208, 1824935377687210, 769194804343737, 1857941799971888 },
+               { 1872620123779532, 1892932666768992, 1921559078394978, 1270573311796160, 1438913646755037 } },
+       {       { 1028328827183114, 1711043289969857, 1350832470374933, 1923164689604327, 1495656368846911 },   /* 6 * 16^54 */
+               { 837390187648199, 1012253300223599, 989780015893987, 1351393287739814, 328627746545550 },
+               { 1900828492104143, 430212361082163, 687437570852799, 832514536673512, 1685641495940794 } },
+       {       { 1176336383453996, 1725477294339771, 12700622672454, 678015708818208, 162724078519879 },       /* 7 * 16^54 */
+               { 842632847936398, 605670026766216, 290836444839585, 163210774892356, 2213815011799645 },
+               { 1448049969043497, 1789411762943521, 385587766217753, 90201620913498, 832999441066823 } },
+       {       { 1263624896582495, 1102602401673328, 526302183714372, 2152015839128799, 1483839308490010 },    /* 8 * 16^54 */
+               { 516086333293313, 2240508292484616, 1351669528166508, 1223255565316488, 750235824427138 },
+               { 442991718646863, 1599275157036458, 1925389027579192, 899514691371390, 350263251085160 } },
+},
+{ /* 16^56 */
+       {       { 1557207018622683, 340631692799603, 1477725909476187, 614735951619419, 2033237123746766 },     /* 1 * 16^56 */
+               { 1689713572022143, 593854559254373, 978095044791970, 1985127338729499, 1676069120347625 },
+               { 968764929340557, 1225534776710944, 662967304013036, 1155521416178595, 791142883466590 } },
+       {       { 1123181311102823, 685575944875442, 507605465509927, 1412590462117473, 568017325228626 },      /* 2 * 16^56 */
+               { 1487081286167458, 993039441814934, 1792378982844640, 698652444999874, 2153908693179754 },
+               { 560258797465417, 2193971151466401, 1824086900849026, 579056363542056, 1690063960036441 } },
+       {       { 2131325168777276, 1176636658428908, 1756922641512981, 1390243617176012, 1966325177038383 },   /* 3 * 16^56 */
+               { 1918407319222416, 353767553059963, 1930426334528099, 1564816146005724, 1861342381708096 },
+               { 2063958120364491, 2140267332393533, 699896251574968, 273268351312140, 375580724713232 } },
+       {       { 2033900009388450, 1744902869870788, 2190580087917640, 1949474984254121, 231049754293748 },    /* 4 * 16^56 */
+               { 2024297515263178, 416959329722687, 1079014235017302, 171612225573183, 1031677520051053 },
+               { 343868674606581, 550155864008088, 1450580864229630, 481603765195050, 896972360018042 } },
+       {       { 1528930066340597, 1605003907059576, 1055061081337675, 1458319101947665, 1234195845213142 },   /* 5 * 16^56 */
+               { 2151139328380127, 314745882084928, 59756825775204, 1676664391494651, 2048348075599360 },
+               { 830430507734812, 1780282976102377, 1425386760709037, 362399353095425, 2168861579799910 } },
+       {       { 1683750316716132, 652278688286128, 1221798761193539, 1897360681476669, 319658166027343 },     /* 6 * 16^56 */
+               { 1155762232730333, 980662895504006, 2053766700883521, 490966214077606, 510405877041357 },
+               { 618808732869972, 72755186759744, 2060379135624181, 1730731526741822, 48862757828238 } },
+       {       { 2230133264691131, 563950955091024, 2042915975426398, 827314356293472, 672028980152815 },      /* 7 * 16^56 */
+               { 1463171970593505, 1143040711767452, 614590986558883, 1409210575145591, 1882816996436803 },
+               { 264204366029760, 1654686424479449, 2185050199932931, 2207056159091748, 506015669043634 } },
+       {       { 2065270940578383, 31477096270353, 306421879113491, 181958643936686, 1907105536686083 },       /* 8 * 16^56 */
+               { 1784446333136569, 1973746527984364, 334856327359575, 1156769775884610, 1023950124675478 },
+               { 1496516440779464, 1748485652986458, 872778352227340, 818358834654919, 97932669284220 } },
+},
+{ /* 16^58 */
+       {       { 1013216974933691, 538921919682598, 1915776722521558, 1742822441583877, 1886550687916656 },    /* 1 * 16^58 */
+               { 471636015770351, 672455402793577, 1804995246884103, 1842309243470804, 1501862504981682 },
+               { 2094270000643336, 303971879192276, 40801275554748, 649448917027930, 1818544418535447 } },
+       {       { 1216074541925116, 50120933933509, 1565829004133810, 721728156134580, 349206064666188 },       /* 2 * 16^58 */
+               { 2241737709499165, 549397817447461, 838180519319392, 1725686958520781, 1705639080897747 },
+               { 948617110470858, 346222547451945, 1126511960599975, 1759386906004538, 493053284802266 } },
+       {       { 2105387117364450, 1996463405126433, 1303008614294500, 851908115948209, 1353742049788635 },    /* 3 * 16^58 */
+               { 1454933046815146, 874696014266362, 1467170975468588, 1432316382418897, 2111710746366763 },
+               { 750300956351719, 1487736556065813, 15158817002104, 1511998221598392, 971739901354129 } },
+       {       { 1235084464747900, 1166111146432082, 1745394857881591, 1405516473883040, 4463504151617 },      /* 4 * 16^58 */
+               { 1874648163531693, 2124487685930551, 1810030029384882, 918400043048335, 586348627300650 },
+               { 1663810156463827, 327797390285791, 1341846161759410, 1964121122800605, 1747470312055380 } },
+       {       { 2206641276178231, 1690587809721504, 1600173622825126, 2156096097634421, 1106822408548216 },   /* 5 * 16^58 */
+               { 660005247548233, 2071860029952887, 1358748199950107, 911703252219107, 1014379923023831 },
+               { 1344788193552206, 1949552134239140, 1735915881729557, 675891104100469, 1834220014427292 } },
+       {       { 622221042073383, 1210146474039168, 1742246422343683, 1403839361379025, 417189490895736 },     /* 6 * 16^58 */
+               { 1920949492387964, 158885288387530, 70308263664033, 626038464897817, 1468081726101009 },
+               { 22727256592983, 168471543384997, 1324340989803650, 1839310709638189, 504999476432775 } },
+       {       { 1337466662091884, 1287645354669772, 2018019646776184, 652181229374245, 898011753211715 },     /* 7 * 16^58 */
+               { 1313240518756327, 1721896294296942, 52263574587266, 2065069734239232, 804910473424630 },
+               { 1969792547910734, 779969968247557, 2011350094423418, 1823964252907487, 1058949448296945 } },
+       {       { 1273565321399022, 1638509681964574, 759235866488935, 666015124346707, 897983460943405 },      /* 8 * 16^58 */
+               { 207343737062002, 1118176942430253, 758894594548164, 806764629546266, 1157700123092949 },
+               { 1717263794012298, 1059601762860786, 1837819172257618, 1054130665797229, 680893204263559 } },
+},
+{ /* 16^60 */
+       {       { 79472182719605, 1851130257050174, 1825744808933107, 821667333481068, 781795293511946 },       /* 1 * 16^60 */
+               { 2237039662793603, 2249022333361206, 2058613546633703, 149454094845279, 2215176649164582 },
+               { 755822026485370, 152464789723500, 1178207602290608, 410307889503239, 156581253571278 } },
+       {       { 1495380034400429, 325049476417173, 46346894893933, 1553408840354856, 828980101835683 },       /* 2 * 16^60 */
+               { 1418185496130297, 484520167728613, 1646737281442950, 1401487684670265, 1349185550126961 },
+               { 1280337889310282, 2070832742866672, 1640940617225222, 2098284908289951, 450929509534434 } },
+       {       { 1254958221100483, 1153235960999843, 942907704968834, 637105404087392, 1149293270147267 },     /* 3 * 16^60 */
+               { 407703353998781, 126572141483652, 286039827513621, 1999255076709338, 2030511179441770 },
+               { 894249020470196, 400291701616810, 406878712230981, 1599128793487393, 1145868722604026 } },
+       {       { 452487513298665, 1352120549024569, 1173495883910956, 1999111705922009, 367328130454226 },     /* 4 * 16^60 */
+               { 1497955250203334, 110116344653260, 1128535642171976, 1900106496009660, 129792717460909 },
+               { 1717539401269642, 1475188995688487, 891921989653942, 836824441505699, 1885988485608364 } },
+       {       { 2022432361201842, 1088816090685051, 1977843398539868, 1854834215890724, 564238862029357 },    /* 5 * 16^60 */
+               { 1241784121422547, 187337051947583, 1118481812236193, 428747751936362, 30358898927325 },
+               { 938868489100585, 1100285072929025, 1017806255688848, 1957262154788833, 152787950560442 } },
+       {       { 1295072362439987, 931227904689414, 1355731432641687, 922235735834035, 892227229410209 },      /* 6 * 16^60 */
+               { 867319417678923, 620471962942542, 226032203305716, 342001443957629, 1761675818237336 },
+               { 1680989767906154, 535362787031440, 2136691276706570, 1942228485381244, 1267350086882274 } },
+       {       { 535509430575217, 546885533737322, 1524675609547799, 2138095752851703, 1260738089896827 },     /* 7 * 16^60 */
+               { 366018233770527, 432660629755596, 126409707644535, 1973842949591662, 645627343442376 },
+               { 1159906385590467, 2198530004321610, 714559485023225, 81880727882151, 1484020820037082 } },
+       {       { 2013612215646735, 1830770575920375, 536135310219832, 609272325580394, 270684344495013 },      /* 8 * 16^60 */
+               { 1377485731340769, 2046328105512000, 1802058637158797, 62146136768173, 1356993908853901 },
+               { 1237542585982777, 2228682050256790, 1385281931622824, 593183794882890, 493654978552689 } },
+},
+{ /* 16^62 */
+       {       { 1694030170963455, 502038567066200, 1691160065225467, 949628319562187, 275110186693066 },      /* 1 * 16^62 */
+               { 47341488007760, 1891414891220257, 983894663308928, 176161768286818, 1126261115179708 },
+               { 1124515748676336, 1661673816593408, 1499640319059718, 1584929449166988, 558148594103306 } },
+       {       { 1288941072872766, 931787902039402, 190731008859042, 2006859954667190, 1005931482221702 },     /* 2 * 16^62 */
+               { 1784525599998356, 1619698033617383, 2097300287550715, 258265458103756, 1905684794832758 },
+               { 1465551264822703, 152905080555927, 680334307368453, 173227184634745, 666407097159852 } },
+       {       { 171348223915638, 662766099800389, 462338943760497, 466917763340314, 656911292869115 },        /* 3 * 16^62 */
+               { 2111017076203943, 1378760485794347, 1248583954016456, 1352289194864422, 1895180776543896 },
+               { 488623681976577, 866497561541722, 1708105560937768, 1673781214218839, 1506146329818807 } },
+       {       { 988979367990485, 1359729327576302, 1301834257246029, 294141160829308, 29348272277475 },       /* 4 * 16^62 */
+               { 160425464456957, 950394373239689, 430497123340934, 711676555398832, 320964687779005 },
+               { 1434382743317910, 100082049942065, 221102347892623, 186982837860588, 1305765053501834 } },
+       {       { 1191737341426592, 1847042034978363, 1382213545049056, 1039952395710448, 788812858896859 },    /* 5 * 16^62 */
+               { 2205916462268190, 499863829790820, 961960554686616, 158062762756985, 1841471168298305 },
+               { 1346965964571152, 1291881610839830, 2142916164336056, 786821641205979, 1571709146321039 } },
+       {       { 492448143532951, 304105152670757, 1761767168301056, 233782684697790, 1981295323106089 },      /* 6 * 16^62 */
+               { 787164375951248, 202869205373189, 1356590421032140, 1431233331032510, 786341368775957 },
+               { 665807507761866, 1343384868355425, 895831046139653, 439338948736892, 1986828765695105 } },
+       {       { 852891097972275, 1816988871354562, 1543772755726524, 1174710635522444, 202129090724628 },     /* 7 * 16^62 */
+               { 756096210874553, 1721699973539149, 258765301727885, 1390588532210645, 1212530909934781 },
+               { 1205281565824323, 22430498399418, 992947814485516, 1392458699738672, 688441466734558 } },
+       {       { 1287181461435438, 622722465530711, 880952150571872, 741035693459198, 311565274989772 },       /* 8 * 16^62 */
+               { 1050627428414972, 1955849529137135, 2171162376368357, 91745868298214, 447733118757826 },
+               { 1003649078149734, 545233927396469, 1849786171789880, 1318943684880434, 280345687170552 } },
+},
diff --git a/crypto/libeddsa/lib/eddsa.h b/crypto/libeddsa/lib/eddsa.h
new file mode 100644 (file)
index 0000000..fe00c88
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef EDDSA_H
+#define EDDSA_H
+
+#include <stddef.h>    /* for size_t */
+#include <stdbool.h>   /* foor bool */
+#include <stdint.h>    /* for uint8_t */
+
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
+#ifndef EDDSA_STATIC
+#  if defined(_WIN32) || defined(__CYGWIN__)
+#    ifdef EDDSA_BUILD
+#      define EDDSA_DECL __declspec(dllexport)
+#    else
+#      define EDDSA_DECL __declspec(dllimport)
+#    endif
+#  elif defined(EDDSA_BUILD) && defined(__GNUC__) && __GNUC__ >= 4
+#    define EDDSA_DECL __attribute__((visibility ("default")))
+#  elif defined(EDDSA_BUILD) && defined(__CLANG__) && __has_attribute(visibility)
+#    define EDDSA_DECL __attribute__((visibility ("default")))
+#  endif
+#endif
+
+#ifndef EDDSA_DECL
+#define EDDSA_DECL
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/*
+ * Ed25519 DSA
+ */
+
+#define ED25519_KEY_LEN                32
+#define ED25519_SIG_LEN                64
+
+EDDSA_DECL void        ed25519_genpub(uint8_t pub[ED25519_KEY_LEN],
+                              const uint8_t sec[ED25519_KEY_LEN]);
+
+EDDSA_DECL void        ed25519_sign(uint8_t sig[ED25519_SIG_LEN],
+                            const uint8_t sec[ED25519_KEY_LEN],
+                            const uint8_t pub[ED25519_KEY_LEN],
+                            const uint8_t *data, size_t len);
+
+EDDSA_DECL bool        ed25519_verify(const uint8_t sig[ED25519_SIG_LEN],
+                              const uint8_t pub[ED25519_KEY_LEN],
+                              const uint8_t *data, size_t len);
+
+
+
+/*
+ * X25519 Diffie-Hellman
+ */
+
+#define X25519_KEY_LEN         32
+
+EDDSA_DECL void        x25519_base(uint8_t out[X25519_KEY_LEN],
+                           const uint8_t scalar[X25519_KEY_LEN]);
+
+EDDSA_DECL void        x25519(uint8_t out[X25519_KEY_LEN],
+                      const uint8_t scalar[X25519_KEY_LEN],
+                      const uint8_t point[X25519_KEY_LEN]);
+
+
+
+/*
+ * Key-conversion between ed25519 and x25519
+ */
+
+EDDSA_DECL void pk_ed25519_to_x25519(uint8_t out[X25519_KEY_LEN],
+                                    const uint8_t in[ED25519_KEY_LEN]);
+
+EDDSA_DECL void sk_ed25519_to_x25519(uint8_t out[X25519_KEY_LEN],
+                                    const uint8_t in[ED25519_KEY_LEN]);
+
+
+
+
+
+/*
+ * Obsolete Interface
+ */
+
+/* eddsa */
+EDDSA_DECL void        eddsa_genpub(uint8_t pub[32], const uint8_t sec[32]);
+
+EDDSA_DECL void        eddsa_sign(uint8_t sig[64],
+                          const uint8_t sec[32],
+                          const uint8_t pub[32],
+                          const uint8_t *data, size_t len);
+
+EDDSA_DECL bool        eddsa_verify(const uint8_t sig[64],
+                            const uint8_t pub[32],
+                            const uint8_t *data, size_t len);
+
+
+/* diffie-hellman */
+EDDSA_DECL void        DH(uint8_t out[32], const uint8_t sec[32],
+                  const uint8_t point[32]);
+
+
+/* key conversion */
+EDDSA_DECL void eddsa_pk_eddsa_to_dh(uint8_t out[32],
+                                    const uint8_t in[32]);
+
+EDDSA_DECL void eddsa_sk_eddsa_to_dh(uint8_t out[32],
+                                    const uint8_t in[32]);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/crypto/libeddsa/lib/fld.c b/crypto/libeddsa/lib/fld.c
new file mode 100644 (file)
index 0000000..403617e
--- /dev/null
@@ -0,0 +1,709 @@
+/*
+ * code for the field GF(2^255-19).
+ *
+ * This code is in public domain.
+ *
+ * Philipp Lay <philipp.lay@illunis.net>
+ */
+
+#include "bitness.h"
+#include "fld.h"
+
+
+#ifdef USE_64BIT
+
+/*
+ * 64bit implementation
+ */
+
+/*
+ * exported field constants
+ */
+
+/* con_d = - 121665/121666 (mod q) */
+const fld_t con_d = {
+       929955233495203, 466365720129213, 1662059464998953, 2033849074728123,
+       1442794654840575 };
+
+/* con_2d = 2 * con_d (mod q) */
+const fld_t con_2d = {
+       1859910466990425, 932731440258426, 1072319116312658, 1815898335770999,
+       633789495995903 };
+
+/* con_m2d = -2 * con_d (mod q) */
+const fld_t con_m2d = {
+       391889346694804, 1319068373426821, 1179480697372589, 435901477914248,
+       1618010317689344 };
+
+/* con_j^2 = 1 (mod q) */
+const fld_t con_j = {
+       1718705420411056, 234908883556509, 2233514472574048, 2117202627021982,
+       765476049583133 };
+
+
+
+/*
+ * fld_reduce - returns the smallest non-negative representation of x modulo q
+ *             with 0 <= x[i] <= 2^51 - 1 for 0 <= i <= 4.
+ *
+ * This function assumes
+ *   abs(x[i]) <= 2^63 - 2^12 = 2^12 * (2^51 - 1), 
+ * for 0 <= i <= 4 to work properly.
+ */
+void
+fld_reduce(fld_t res, const fld_t x)
+{
+       /* first carry round with offset 19 */
+       res[0] = x[0] + 19;
+       res[1] = x[1] + (res[0] >> FLD_LIMB_BITS);
+       res[2] = x[2] + (res[1] >> FLD_LIMB_BITS);
+       res[3] = x[3] + (res[2] >> FLD_LIMB_BITS);
+       res[4] = x[4] + (res[3] >> FLD_LIMB_BITS);
+
+       /* -2^12 <= (res[4] >> FLD_LIMB_BITS) <= 2^12-1 */
+       res[0] = (res[0] & FLD_LIMB_MASK) + 19*(res[4] >> FLD_LIMB_BITS);
+       res[1] &= FLD_LIMB_MASK;
+       res[2] &= FLD_LIMB_MASK;
+       res[3] &= FLD_LIMB_MASK;
+       res[4] &= FLD_LIMB_MASK;
+
+       /* now we have
+        *   -19*2^12 <= res[0] <= 2^51-1 + 19*(2^12-1),
+        * and
+        *   0 <= res[i] <= 2^51-1 for 1 <= i <= 4.
+        */
+
+       /* second round */
+       res[1] += (res[0] >> FLD_LIMB_BITS);
+       res[2] += (res[1] >> FLD_LIMB_BITS);
+       res[3] += (res[2] >> FLD_LIMB_BITS);
+       res[4] += (res[3] >> FLD_LIMB_BITS);
+
+       /* -1 <= (res[4] >> FLD_LIMB_BITS) <= 1 */
+       res[0] = (res[0] & FLD_LIMB_MASK) + 19*(res[4] >> FLD_LIMB_BITS);
+
+       res[1] &= FLD_LIMB_MASK;
+       res[2] &= FLD_LIMB_MASK;
+       res[3] &= FLD_LIMB_MASK;
+       res[4] &= FLD_LIMB_MASK;
+
+       /* the second round yields 
+        *   -19 <= res[0] <= 2^51-1 + 19
+        * and
+        *   0 <= res[i] <= 2^51-1 for 1 <= i <= 4.
+        */
+       res[0] -= 19;
+
+       /* with the offset removed we have
+        *   -38 <= res[0] <= 2^51-1
+        * and need a third round to assure that res[0] is non-negative.
+        *
+        * please note, that no positive carry is possible at this point.
+        */
+
+       res[1] += (res[0] >> FLD_LIMB_BITS);
+       res[2] += (res[1] >> FLD_LIMB_BITS);
+       res[3] += (res[2] >> FLD_LIMB_BITS);
+       res[4] += (res[3] >> FLD_LIMB_BITS);
+
+       /* -1 <= (res[4] >> FLD_LIMB_BITS) <= 0, because of non-positive carry */
+       res[0] = (res[0] & FLD_LIMB_MASK) + 19*(res[4] >> FLD_LIMB_BITS);
+
+       res[1] &= FLD_LIMB_MASK;
+       res[2] &= FLD_LIMB_MASK;
+       res[3] &= FLD_LIMB_MASK;
+       res[4] &= FLD_LIMB_MASK;
+
+
+       /* if res[0] was negative before this round we had an negative carry and
+        * have now
+        *   2^51 - 38 - 19 <= res[0] <= 2^51 - 1.
+        *
+        * so in any case it is
+        *   0 <= res[0] <= 2^51 - 1
+        * and
+        *   0 <= res[i] <= 2^51 - 1 for 1 <= i <= 4
+        * as wished.
+        *
+        * moreover res is the smallest non-negative representant of x modulo q.
+        */
+}
+
+/*
+ * fld_import - import an 256bit, unsigned, little-endian integer into
+ * our signed 51-bit limb format and reduce modulo 2^255-19.
+ */
+void
+fld_import(fld_t dst, const uint8_t src[32])
+{
+       int i;
+       uint64_t tmp = 0;
+       int fill = 0;
+
+       for (i = 0; i < FLD_LIMB_NUM; i++) {
+               for (;fill < FLD_LIMB_BITS; fill += 8)
+                       tmp |= (uint64_t)*src++ << fill;
+
+               dst[i] = tmp & FLD_LIMB_MASK;
+               tmp >>= FLD_LIMB_BITS;
+               fill -= FLD_LIMB_BITS;
+       }
+       dst[0] += 19*tmp;
+
+       /* dst is now reduced and partially carried (first limb may
+        * use 52bits instead of 51).
+        */
+}
+
+/*
+ * fld_export - export our internal format to a 256bit, unsigned,
+ * little-endian packed format.
+ */
+void
+fld_export(uint8_t dst[32], const fld_t src)
+{
+       int i;
+       fld_t tmp;
+       uint64_t foo = 0;
+       int fill = 0;
+       
+       fld_reduce(tmp, src);
+
+       for (i = 0; i < FLD_LIMB_NUM; i++) {
+               foo |= (uint64_t)tmp[i] << fill;
+               for (fill += FLD_LIMB_BITS; fill >= 8; fill -= 8, foo >>= 8)
+                       *dst++ = foo & 0xff;
+       }
+       *dst++ = foo & 0xff;
+}
+
+/*
+ * fld_scale - multiply e by scalar s and reduce modulo q.
+ */
+void
+fld_scale(fld_t res, const fld_t e, limb_t s)
+{
+       llimb_t carry;
+
+       carry = (llimb_t)s*e[0];
+       res[0] = carry & FLD_LIMB_MASK;
+
+       carry = (carry >> FLD_LIMB_BITS) + (llimb_t)s*e[1];
+       res[1] = carry & FLD_LIMB_MASK;
+
+       carry = (carry >> FLD_LIMB_BITS) + (llimb_t)s*e[2];
+       res[2] = carry & FLD_LIMB_MASK;
+
+       carry = (carry >> FLD_LIMB_BITS) + (llimb_t)s*e[3];
+       res[3] = carry & FLD_LIMB_MASK;
+
+       carry = (carry >> FLD_LIMB_BITS) + (llimb_t)s*e[4];
+       res[4] = carry & FLD_LIMB_MASK;
+
+       res[0] += 19*(carry >> FLD_LIMB_BITS);
+}
+
+/*
+ * fld_mul - multiply a with b and reduce modulo q.
+ */
+void
+fld_mul(fld_t res, const fld_t a, const fld_t b)
+{
+       limb_t a19_1, a19_2, a19_3, a19_4, tmp;
+       llimb_t c[5];
+
+       a19_1 = 19*a[1];
+       a19_2 = 19*a[2];
+       a19_3 = 19*a[3];
+       a19_4 = 19*a[4];
+
+       c[0] = (llimb_t)a[0]*b[0] + (llimb_t)a19_1*b[4] + (llimb_t)a19_2*b[3]
+               + (llimb_t)a19_3*b[2] + (llimb_t)a19_4*b[1];
+       c[1] = (llimb_t)a[0]*b[1] + (llimb_t)a[1]*b[0] + (llimb_t)a19_2*b[4]
+               + (llimb_t)a19_3*b[3] + (llimb_t)a19_4*b[2];
+       c[2] = (llimb_t)a[0]*b[2] + (llimb_t)a[1]*b[1] + (llimb_t)a[2]*b[0]
+               + (llimb_t)a19_3*b[4] + (llimb_t)a19_4*b[3];
+       c[3] = (llimb_t)a[0]*b[3] + (llimb_t)a[1]*b[2] + (llimb_t)a[2]*b[1]
+               + (llimb_t)a[3]*b[0] + (llimb_t)a19_4*b[4];
+       c[4] = (llimb_t)a[0]*b[4] + (llimb_t)a[1]*b[3] + (llimb_t)a[2]*b[2]
+               + (llimb_t)a[3]*b[1] + (llimb_t)a[4]*b[0];
+
+
+       c[1] += c[0] >> FLD_LIMB_BITS;
+       c[2] += c[1] >> FLD_LIMB_BITS;
+       c[3] += c[2] >> FLD_LIMB_BITS;
+       c[4] += c[3] >> FLD_LIMB_BITS;
+
+       tmp = (c[0] & FLD_LIMB_MASK) + 19*(c[4] >> FLD_LIMB_BITS);
+       res[1] = (c[1] & FLD_LIMB_MASK) + (tmp >> FLD_LIMB_BITS);
+
+       res[0] = tmp & FLD_LIMB_MASK;
+       res[2] = c[2] & FLD_LIMB_MASK;
+       res[3] = c[3] & FLD_LIMB_MASK;
+       res[4] = c[4] & FLD_LIMB_MASK;
+}
+
+/*
+ * fld_sq - square x and reduce modulo q.
+ */
+void
+fld_sq(fld_t res, const fld_t x)
+{
+       limb_t x2_1, x2_2, x2_3, x2_4, x19_3, x19_4, tmp;
+       llimb_t c[5];
+
+       x2_1 = 2*x[1];
+       x2_2 = 2*x[2];
+       x2_3 = 2*x[3];
+       x2_4 = 2*x[4];
+       x19_3 = 19*x[3];
+       x19_4 = 19*x[4];
+
+       c[0] = (llimb_t)x[0]*x[0] + (llimb_t)x2_1*x19_4 + (llimb_t)x2_2*x19_3;
+       c[1] = (llimb_t)x[0]*x2_1 + (llimb_t)x2_2*x19_4 + (llimb_t)x19_3*x[3];
+       c[2] = (llimb_t)x[0]*x2_2 + (llimb_t)x[1]*x[1] + (llimb_t)x2_3*x19_4;
+       c[3] = (llimb_t)x[0]*x2_3 + (llimb_t)x2_1*x[2] + (llimb_t)x19_4*x[4];
+       c[4] = (llimb_t)x[0]*x2_4 + (llimb_t)x2_1*x[3] + (llimb_t)x[2]*x[2];
+
+       c[1] += c[0] >> FLD_LIMB_BITS;
+       c[2] += c[1] >> FLD_LIMB_BITS;
+       c[3] += c[2] >> FLD_LIMB_BITS;
+       c[4] += c[3] >> FLD_LIMB_BITS;
+
+       tmp = (c[0] & FLD_LIMB_MASK) + 19*(c[4] >> FLD_LIMB_BITS);
+       res[1] = (c[1] & FLD_LIMB_MASK) + (tmp >> FLD_LIMB_BITS);
+
+       res[0] = tmp & FLD_LIMB_MASK;
+       res[2] = c[2] & FLD_LIMB_MASK;
+       res[3] = c[3] & FLD_LIMB_MASK;
+       res[4] = c[4] & FLD_LIMB_MASK;
+}
+
+#else          /* USE_64BIT */
+
+
+/*
+ * 32bit implementation
+ */
+
+
+/*
+ * exported field constants
+ */
+
+/* con_d = - 121665/121666 (mod q) */
+const fld_t con_d = { 56195235, 13857412, 51736253, 6949390, 114729, 24766616,
+                     60832955, 30306712, 48412415, 21499315 };
+
+/* con_2d = 2 * con_d (mod q) */
+const fld_t con_2d = { 45281625, 27714825, 36363642, 13898781, 229458,
+                      15978800, 54557047, 27058993, 29715967, 9444199 };
+/* con_m2d = -2 * con_d (mod q) */
+const fld_t con_m2d = { 21827220, 5839606, 30745221, 19655650, 66879405,
+                       17575631, 12551816, 6495438, 37392896, 24110232 };
+/* j^2 = 1 (mod q) */
+const fld_t con_j = { 34513072, 25610706, 9377949, 3500415, 12389472, 33281959,
+                     41962654, 31548777, 326685, 11406482 };
+
+
+/*
+ * macro for doing one carry-reduce round
+ *
+ * tmp is being used as carry-register and could be of type
+ * limb_t or llimb_t.
+ *
+ * off is normally zero, but could be used to wrap-around values x
+ * with q <= x < 2^255 (see fld_reduce for an example).
+ */
+#define CARRY(dst, src, tmp, off)                                      \
+do {                                                                   \
+       int _ii;                                                        \
+       (tmp) = (off);                                                  \
+       (tmp) <<= FLD_LIMB_BITS(0);                                     \
+       for (_ii = 0; _ii < FLD_LIMB_NUM; _ii += 2) {                   \
+               (tmp) = ((tmp) >> FLD_LIMB_BITS(0)) + (src)[_ii];       \
+               (dst)[_ii] = (tmp) & FLD_LIMB_MASK(1);                  \
+               (tmp) = ((tmp) >> FLD_LIMB_BITS(1)) + (src)[_ii+1];     \
+               (dst)[_ii+1] = (tmp) & FLD_LIMB_MASK(0);                \
+       }                                                               \
+        (dst)[0] += 19*((tmp) >> FLD_LIMB_BITS(0));                    \
+} while(0)
+
+
+/*
+ * fld_reduce - returns the smallest non-negative representation of x modulo q
+ *             with 0 <= x[i] <= 2^26 - 1 for i % 2 == 0 
+ *             and  0 <= x[i] <= 2^25 - 1 for i % 2 == 1.
+ *
+ * assumes:
+ *   abs(x[i]) <= 2^31 - 2^5 = 32 * (2^26 - 1)
+ */
+void
+fld_reduce(fld_t res, const fld_t x)
+{
+       limb_t tmp;
+
+       CARRY(res, x, tmp, 19);
+       /* we have
+        *   -2^26 - 19*2^5 <= res[0] <= 2^26 - 1 + 19*(2^5 - 1)
+        * and for i >= 1:
+        *   0 <= res[i] <= 2^26-1, i % 2 == 0,
+        *   0 <= res[i] <= 2^25-1, i % 2 == 1.
+        */
+
+       CARRY(res, res, tmp, 0);
+       /* now
+        *   -2^26 - 19 <= res[0] <= 2^26 - 1 + 19
+        * holds and, as before,
+        *   0 <= res[i] <= 2^26-1, i % 2 == 0
+        *   0 <= res[i] <= 2^25-1, i % 2 == 1,
+        * for i >= 1.
+        */
+
+       /* next round we will first remove our offset resulting in
+        *   -2^26 - 38 <= res[0] <= 2^26 - 1,
+        * therefor only a negative carry could appear.
+        */
+       CARRY(res, res, tmp, -19);
+       /* now we have
+        *   0 <= res[i] <= 2^26-1, i % 2 == 0
+        *   0 <= res[i] <= 2^25-1, i % 2 == 1
+        * for all limbs as wished.
+        *
+        * if a carry had happend, we even know
+        *   2^26 - 38 - 19 <= res[0] <= 2^26 - 1.
+        */
+}
+
+/*
+ * fld_import - import an 256bit, unsigned, little-endian integer into
+ * our internal fld_t format.
+ */
+void
+fld_import(fld_t dst, const uint8_t src[32])
+{
+       int i;
+       uint32_t foo = 0;
+       int fill = 0;
+       int d = 1;
+
+       for (i = 0; i < FLD_LIMB_NUM; i++) {
+               for (; fill < FLD_LIMB_BITS(d); fill += 8)
+                       foo |= (uint32_t)*src++ << fill;
+               dst[i] = foo & FLD_LIMB_MASK(d);
+               
+               foo >>= FLD_LIMB_BITS(d);
+               fill -= FLD_LIMB_BITS(d);
+               d = 1-d;
+       }
+       dst[0] += 19*foo;
+}
+
+/*
+ * fld_export - export a field element into 256bit little-endian encoded form.
+ */
+void
+fld_export(uint8_t dst[32], const fld_t src)
+{
+       uint32_t foo;
+       fld_t tmp;
+       int fill, i;
+
+       fld_reduce(tmp, src);
+
+       for (i = 0, fill = 0, foo = 0; i < FLD_LIMB_NUM; i += 2) {
+               foo |= (tmp[i] & FLD_LIMB_MASK(1)) << fill;
+               for (fill += FLD_LIMB_BITS(1); fill >= 8; fill -= 8, foo >>= 8)
+                       *dst++ = foo & 0xff;
+
+               foo |= (tmp[i+1] & FLD_LIMB_MASK(0)) << fill;
+               for (fill += FLD_LIMB_BITS(0); fill >= 8; fill -= 8, foo >>= 8)
+                       *dst++ = foo & 0xff;
+       }
+       *dst++ = foo & 0xff;
+}
+
+/*
+ * fld_scale - multiply e by scalar s and reduce modulo q.
+ */
+void
+fld_scale(fld_t dst, const fld_t e, limb_t x)
+{
+       llimb_t tmp;
+       int i;
+
+       for (tmp = 0, i = 0; i < FLD_LIMB_NUM; i += 2) {
+               tmp = (tmp >> FLD_LIMB_BITS(0)) + (llimb_t) x*e[i];
+               dst[i] = tmp & FLD_LIMB_MASK(1);
+               tmp = (tmp >> FLD_LIMB_BITS(1)) + ((llimb_t) x*e[i+1]);
+               dst[i+1] = tmp & FLD_LIMB_MASK(0);
+       }
+       dst[0] += 19*(tmp >> FLD_LIMB_BITS(0));
+}
+
+/*
+ * fld_mul - multiply a with b and reduce modulo q.
+ */
+void
+fld_mul(fld_t dst, const fld_t a, const fld_t b)
+{
+       llimb_t tmp;
+       llimb_t c[10];
+
+       c[0] = (llimb_t)a[0]*b[0];
+       c[1] = (llimb_t)a[0]*b[1] + (llimb_t)a[1]*b[0];
+       c[2] = (llimb_t)a[0]*b[2] + (llimb_t)2*a[1]*b[1] + (llimb_t)a[2]*b[0];
+       c[3] = (llimb_t)a[0]*b[3] + (llimb_t)a[1]*b[2] + (llimb_t)a[2]*b[1]
+               + (llimb_t)a[3]*b[0];
+       c[4] = (llimb_t)a[0]*b[4] + (llimb_t)2*a[1]*b[3] + (llimb_t)a[2]*b[2]
+               + (llimb_t)2*a[3]*b[1] + (llimb_t)a[4]*b[0];
+       c[5] = (llimb_t)a[0]*b[5] + (llimb_t)a[1]*b[4] + (llimb_t)a[2]*b[3] 
+               + (llimb_t)a[3]*b[2] + (llimb_t)a[4]*b[1] + (llimb_t)a[5]*b[0];
+       c[6] = (llimb_t)a[0]*b[6] + (llimb_t)2*a[1]*b[5] + (llimb_t)a[2]*b[4]
+               + (llimb_t)2*a[3]*b[3] + (llimb_t)a[4]*b[2] + (llimb_t)2*a[5]*b[1]
+               + (llimb_t)a[6]*b[0];
+       c[7] = (llimb_t)a[0]*b[7] + (llimb_t)a[1]*b[6] + (llimb_t)a[2]*b[5]
+               + (llimb_t)a[3]*b[4] + (llimb_t)a[4]*b[3] + (llimb_t)a[5]*b[2]
+               + (llimb_t)a[6]*b[1] + (llimb_t)a[7]*b[0];
+       c[8] = (llimb_t)a[0]*b[8] + (llimb_t)2*a[1]*b[7] + (llimb_t)a[2]*b[6]
+               + (llimb_t)2*a[3]*b[5] + (llimb_t)a[4]*b[4] + (llimb_t)2*a[5]*b[3]
+               + (llimb_t)a[6]*b[2] + (llimb_t)2*a[7]*b[1] + (llimb_t)a[8]*b[0];
+       c[9] = (llimb_t)a[0]*b[9] + (llimb_t)a[1]*b[8] + (llimb_t)a[2]*b[7]
+               + (llimb_t)a[3]*b[6] + (llimb_t)a[4]*b[5] + (llimb_t)a[5]*b[4]
+               + (llimb_t)a[6]*b[3] + (llimb_t)a[7]*b[2] + (llimb_t)a[8]*b[1]
+               + (llimb_t)a[9]*b[0];
+
+       c[0] += 19 * ((llimb_t)2*a[1]*b[9] + (llimb_t)a[2]*b[8] + (llimb_t)2*a[3]*b[7]
+                     + (llimb_t)a[4]*b[6] + (llimb_t)2*a[5]*b[5] + (llimb_t)a[6]*b[4]
+                     + (llimb_t)2*a[7]*b[3] + (llimb_t)a[8]*b[2] + (llimb_t)2*a[9]*b[1]);
+       c[1] += 19 * ((llimb_t)a[2]*b[9] + (llimb_t)a[3]*b[8] + (llimb_t)a[4]*b[7]
+                     + (llimb_t)a[5]*b[6] + (llimb_t)a[6]*b[5] + (llimb_t)a[7]*b[4]
+                     + (llimb_t)a[8]*b[3] + (llimb_t)a[9]*b[2]);
+       c[2] += 19 * ((llimb_t)2*a[3]*b[9] + (llimb_t)a[4]*b[8] + (llimb_t)2*a[5]*b[7]
+                     + (llimb_t)a[6]*b[6] + (llimb_t)2*a[7]*b[5] + (llimb_t)a[8]*b[4]
+                     + (llimb_t)2*a[9]*b[3]);
+       c[3] += 19 * ((llimb_t)a[4]*b[9] + (llimb_t)a[5]*b[8] + (llimb_t)a[6]*b[7]
+                     + (llimb_t)a[7]*b[6] + (llimb_t)a[8]*b[5] + (llimb_t)a[9]*b[4]);
+       c[4] += 19 * ((llimb_t)2*a[5]*b[9] + (llimb_t)a[6]*b[8] + (llimb_t)2*a[7]*b[7]
+                     + (llimb_t)a[8]*b[6] + (llimb_t)2*a[9]*b[5]);
+       c[5] += 19 * ((llimb_t)a[6]*b[9] + (llimb_t)a[7]*b[8] + (llimb_t)a[8]*b[7]
+                     + (llimb_t)a[9]*b[6]);
+       c[6] += 19 * ((llimb_t)2*a[7]*b[9] + (llimb_t)a[8]*b[8] + (llimb_t)2*a[9]*b[7]);
+       c[7] += 19 * ((llimb_t)a[8]*b[9] + (llimb_t)a[9]*b[8]);
+       c[8] += 19 * ((llimb_t)2*a[9]*b[9]);
+
+       CARRY(c, c, tmp, 0);
+       CARRY(dst, c, tmp, 0);
+}
+
+/*
+ * fld_sq - square x and reduce modulo q.
+ */
+void
+fld_sq(fld_t dst, const fld_t a)
+{
+       llimb_t tmp;
+       llimb_t c[10];
+
+       c[0] = (llimb_t)a[0]*a[0];
+       c[1] = (llimb_t)2*a[0]*a[1];
+       c[2] = 2*((llimb_t)a[0]*a[2] + (llimb_t)a[1]*a[1]);
+       c[3] = 2*((llimb_t)a[0]*a[3] + (llimb_t)a[1]*a[2]);
+       c[4] = 2*((llimb_t)a[0]*a[4] + (llimb_t)2*a[1]*a[3]) + (llimb_t)a[2]*a[2];
+       c[5] = 2*((llimb_t)a[0]*a[5] + (llimb_t)a[1]*a[4] + (llimb_t)a[2]*a[3]);
+       c[6] = 2*((llimb_t)a[0]*a[6] + (llimb_t)2*a[1]*a[5] + (llimb_t)a[2]*a[4] + (llimb_t)a[3]*a[3]);
+       c[7] = 2*((llimb_t)a[0]*a[7] + (llimb_t)a[1]*a[6] + (llimb_t)a[2]*a[5] + (llimb_t)a[3]*a[4]);
+       c[8] = 2*((llimb_t)a[0]*a[8] + (llimb_t)2*a[1]*a[7] + (llimb_t)a[2]*a[6] + (llimb_t)2*a[3]*a[5]) + (llimb_t)a[4]*a[4];
+       c[9] = 2*((llimb_t)a[0]*a[9] + (llimb_t)a[1]*a[8] + (llimb_t)a[2]*a[7] + (llimb_t)a[3]*a[6] + (llimb_t)a[4]*a[5]);
+       
+       c[0] += 19*2*((llimb_t)2*a[1]*a[9] + (llimb_t)a[2]*a[8] + (llimb_t)2*a[3]*a[7] + (llimb_t)a[4]*a[6] + (llimb_t)a[5]*a[5]);
+       c[1] += 19*2*((llimb_t)a[2]*a[9] + (llimb_t)a[3]*a[8] + (llimb_t)a[4]*a[7] + (llimb_t)a[5]*a[6]);
+       c[2] += 19*(2*((llimb_t)2*a[3]*a[9] + (llimb_t)a[4]*a[8] + (llimb_t)2*a[5]*a[7]) + (llimb_t)a[6]*a[6]);
+       c[3] += 19*2*((llimb_t)a[4]*a[9] + (llimb_t)a[5]*a[8] + (llimb_t)a[6]*a[7]);
+       c[4] += 19*(2*((llimb_t)2*a[5]*a[9] + (llimb_t)a[6]*a[8] + (llimb_t)a[7]*a[7]));
+       c[5] += 19*2*((llimb_t)a[6]*a[9] + (llimb_t)a[7]*a[8]);
+       c[6] += 19*((llimb_t)2*2*a[7]*a[9] + (llimb_t)a[8]*a[8]);
+       c[7] += 19*2*(llimb_t)a[8]*a[9];
+       c[8] += 19*2*(llimb_t)a[9]*a[9];
+
+       CARRY(c, c, tmp, 0);
+       CARRY(dst, c, tmp, 0);
+}
+
+#endif         /* USE_64BIT */
+
+
+/*
+ * common code
+ */
+
+
+/*
+ * fld_eq - compares two field elements in a time-constant manner.
+ *
+ * returns 1 if a == b and 0 otherwise.
+ */
+int
+fld_eq(const fld_t a, const fld_t b)
+{
+       fld_t tmp;
+       limb_t res;
+       int i;
+
+       /* tmp <- a - b */
+       fld_sub(tmp, a, b);
+       fld_reduce(tmp, tmp);
+
+       /* and check tmp for zero */
+       res = tmp[0];
+       for (i = 1; i < FLD_LIMB_NUM; i++)
+               res |= tmp[i];
+       for (i = 4*sizeof(limb_t); i > 0; i >>= 1)
+                res |= res >> i;
+
+       /* now (res & 1) is zero iff tmp is zero */
+       res = ~res & 1;
+
+       return res;
+}
+
+
+/*
+ * fld_inv - inverts z modulo q.
+ *
+ * this code is taken from nacl. it works by taking z to the q-2
+ * power. by lagrange's theorem (aka 'fermat's little theorem' in this
+ * special case) this gives us z^-1 modulo q.
+ */
+void
+fld_inv(fld_t res, const fld_t z)
+{
+       fld_t z2;
+       fld_t z9;
+       fld_t z11;
+       fld_t z2_5_0;
+       fld_t z2_10_0;
+       fld_t z2_20_0;
+       fld_t z2_50_0;
+       fld_t z2_100_0;
+       fld_t t0;
+       fld_t t1;
+       int i;
+
+       /* 2 */ fld_sq(z2, z);
+       /* 4 */ fld_sq(t1, z2);
+       /* 8 */ fld_sq(t0, t1);
+       /* 9 */ fld_mul(z9,t0, z);
+       /* 11 */ fld_mul(z11, z9, z2);
+       /* 22 */ fld_sq(t0, z11);
+       /* 2^5 - 2^0 = 31 */ fld_mul(z2_5_0, t0, z9);
+
+       /* 2^6 - 2^1 */ fld_sq(t0, z2_5_0);
+       /* 2^7 - 2^2 */ fld_sq(t1, t0);
+       /* 2^8 - 2^3 */ fld_sq(t0, t1);
+       /* 2^9 - 2^4 */ fld_sq(t1, t0);
+       /* 2^10 - 2^5 */ fld_sq(t0, t1);
+       /* 2^10 - 2^0 */ fld_mul(z2_10_0, t0, z2_5_0);
+
+       /* 2^11 - 2^1 */ fld_sq(t0, z2_10_0);
+       /* 2^12 - 2^2 */ fld_sq(t1, t0);
+       /* 2^20 - 2^10 */ for (i = 2; i < 10; i += 2) { fld_sq(t0, t1); fld_sq(t1, t0); }
+       /* 2^20 - 2^0 */ fld_mul(z2_20_0, t1, z2_10_0);
+
+       /* 2^21 - 2^1 */ fld_sq(t0, z2_20_0);
+       /* 2^22 - 2^2 */ fld_sq(t1, t0);
+       /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fld_sq(t0, t1); fld_sq(t1, t0); }
+       /* 2^40 - 2^0 */ fld_mul(t0, t1, z2_20_0);
+
+       /* 2^41 - 2^1 */ fld_sq(t1, t0);
+       /* 2^42 - 2^2 */ fld_sq(t0, t1);
+       /* 2^50 - 2^10 */ for (i = 2; i < 10; i += 2) { fld_sq(t1, t0); fld_sq(t0, t1); }
+       /* 2^50 - 2^0 */ fld_mul(z2_50_0, t0, z2_10_0);
+
+       /* 2^51 - 2^1 */ fld_sq(t0, z2_50_0);
+       /* 2^52 - 2^2 */ fld_sq(t1, t0);
+       /* 2^100 - 2^50 */ for (i = 2; i < 50; i += 2) { fld_sq(t0, t1); fld_sq(t1, t0); }
+       /* 2^100 - 2^0 */ fld_mul(z2_100_0, t1, z2_50_0);
+
+       /* 2^101 - 2^1 */ fld_sq(t1, z2_100_0);
+       /* 2^102 - 2^2 */ fld_sq(t0, t1);
+       /* 2^200 - 2^100 */ for (i = 2; i < 100; i += 2) { fld_sq(t1, t0); fld_sq(t0, t1); }
+       /* 2^200 - 2^0 */ fld_mul(t1, t0, z2_100_0);
+
+       /* 2^201 - 2^1 */ fld_sq(t0, t1);
+       /* 2^202 - 2^2 */ fld_sq(t1, t0);
+       /* 2^250 - 2^50 */ for (i = 2; i < 50; i += 2) { fld_sq(t0, t1); fld_sq(t1, t0); }
+       /* 2^250 - 2^0 */ fld_mul(t0, t1, z2_50_0);
+
+       /* 2^251 - 2^1 */ fld_sq(t1, t0);
+       /* 2^252 - 2^2 */ fld_sq(t0, t1);
+       
+       /* 2^253 - 2^3 */ fld_sq(t1, t0);
+       /* 2^254 - 2^4 */ fld_sq(t0, t1);
+       /* 2^255 - 2^5 */ fld_sq(t1, t0);
+       /* 2^255 - 21 */ fld_mul(res, t1, z11);
+}
+
+
+/*
+ * fld_pow2523 - compute z^((q-5)/8) modulo q, ie (z*res)^2 is either z
+ * or -z modulo q.
+ *
+ * this function is used to mix a square-root modulo q with an invertation in
+ * ed_import. see the ed25519 paper for an explanation.
+ *
+ * this code is, like fld_inv, taken from nacl.
+ */
+void
+fld_pow2523(fld_t res, const fld_t z)
+{
+        fld_t z2;
+        fld_t z9;
+        fld_t z2_5_0;
+        fld_t z2_10_0;
+        fld_t z2_20_0;
+        fld_t z2_50_0;
+        fld_t z2_100_0;
+        fld_t t;
+        int i;
+                
+        /* 2 */ fld_sq(z2, z);
+        /* 4 */ fld_sq(t, z2);
+        /* 8 */ fld_sq(t, t);
+        /* 9 */ fld_mul(z9, t, z);
+        /* 11 */ fld_mul(t, z9, z2);
+        /* 22 */ fld_sq(t, t);
+        /* 2^5 - 2^0 = 31 */ fld_mul(z2_5_0, t, z9);
+
+        /* 2^6 - 2^1 */ fld_sq(t, z2_5_0);
+        /* 2^10 - 2^5 */ for (i = 1;i < 5;i++) { fld_sq(t, t); }
+        /* 2^10 - 2^0 */ fld_mul(z2_10_0, t, z2_5_0);
+
+        /* 2^11 - 2^1 */ fld_sq(t, z2_10_0);
+        /* 2^20 - 2^10 */ for (i = 1;i < 10;i++) { fld_sq(t, t); }
+        /* 2^20 - 2^0 */ fld_mul(z2_20_0, t, z2_10_0);
+
+        /* 2^21 - 2^1 */ fld_sq(t, z2_20_0);
+        /* 2^40 - 2^20 */ for (i = 1;i < 20;i++) { fld_sq(t, t); }
+        /* 2^40 - 2^0 */ fld_mul(t, t, z2_20_0);
+
+        /* 2^41 - 2^1 */ fld_sq(t, t);
+        /* 2^50 - 2^10 */ for (i = 1;i < 10;i++) { fld_sq(t, t); }
+        /* 2^50 - 2^0 */ fld_mul(z2_50_0, t, z2_10_0);
+
+        /* 2^51 - 2^1 */ fld_sq(t, z2_50_0);
+        /* 2^100 - 2^50 */ for (i = 1;i < 50;i++) { fld_sq(t, t); }
+        /* 2^100 - 2^0 */ fld_mul(z2_100_0, t, z2_50_0);
+
+        /* 2^101 - 2^1 */ fld_sq(t, z2_100_0);
+        /* 2^200 - 2^100 */ for (i = 1;i < 100;i++) { fld_sq(t, t); }
+        /* 2^200 - 2^0 */ fld_mul(t, t, z2_100_0);
+
+        /* 2^201 - 2^1 */ fld_sq(t, t);
+        /* 2^250 - 2^50 */ for (i = 1;i < 50;i++) { fld_sq(t, t); }
+        /* 2^250 - 2^0 */ fld_mul(t, t, z2_50_0);
+
+        /* 2^251 - 2^1 */ fld_sq(t, t);
+        /* 2^252 - 2^2 */ fld_sq(t, t);
+        /* 2^252 - 3 */ fld_mul(res, t, z);
+}
diff --git a/crypto/libeddsa/lib/fld.h b/crypto/libeddsa/lib/fld.h
new file mode 100644 (file)
index 0000000..598c6b2
--- /dev/null
@@ -0,0 +1,144 @@
+#ifndef FLD_H
+#define FLD_H
+
+#include <stdint.h>
+
+#include "bitness.h"
+#include "compat.h"
+#include "limb.h"
+
+
+#ifdef USE_64BIT
+
+/*
+ * in 64bit mode we use 5 limbs each 51 bits long
+ */
+
+#define FLD_LIMB_NUM           5
+#define FLD_LIMB_BITS          51
+
+#define FLD_LIMB_MASK          ((1L << FLD_LIMB_BITS)-1)
+
+#else
+
+/*
+ * in 32bit mode fld_t consists of 10 limbs alternating in size
+ * between 26 and 25 bits.
+ * this approach is inspired from djb's curve25519-paper, where it
+ * is explained in more detail.
+ */
+
+#define FLD_LIMB_NUM           10
+
+/* macros for alternating limb sizes: use with d=1,0,1,0,... */
+#define FLD_LIMB_BITS(d)       (25+(d))
+#define FLD_LIMB_MASK(d)       ((1 << FLD_LIMB_BITS(d))-1)
+
+#endif
+
+
+/*
+ * fld_t is our datatype for all operations modulo 2^255-19.
+ *
+ * since we typedef an array here, all parameters of type fld_t get
+ * a call-by-reference semantic!
+ */
+
+typedef limb_t fld_t[FLD_LIMB_NUM];
+
+
+
+/*
+ * exported constants
+ */
+extern const fld_t con_d;
+extern const fld_t con_2d;
+extern const fld_t con_m2d;
+extern const fld_t con_j;
+
+
+/*
+ * prototypes for 32bit/64bit specific functions 
+ */
+void   fld_reduce(fld_t dst, const fld_t x);
+void   fld_import(fld_t dst, const uint8_t src[32]);
+void   fld_export(uint8_t dst[32], const fld_t src);
+void   fld_mul(fld_t res, const fld_t a, const fld_t b);
+void   fld_scale(fld_t dst, const fld_t src, limb_t x);
+void   fld_sq(fld_t res, const fld_t a);
+
+
+/*
+ * prototypes for common code
+ */
+int    fld_eq(const fld_t a, const fld_t b);
+void   fld_inv(fld_t res, const fld_t z);
+void   fld_pow2523(fld_t res, const fld_t z);
+
+
+
+/*
+ * simple inline functions
+ */
+
+static INLINE void
+fld_set0(fld_t res, limb_t x0)
+{
+       int i;
+       res[0] = x0;
+       for (i = 1; i < FLD_LIMB_NUM; i++)
+               res[i] = 0;
+}
+
+
+static INLINE void
+fld_add(fld_t res, const fld_t a, const fld_t b)
+{
+       int i;
+       for (i = 0; i < FLD_LIMB_NUM; i++)
+               res[i] = a[i] + b[i];
+}
+
+static INLINE void
+fld_sub(fld_t res, const fld_t a, const fld_t b)
+{
+       int i;
+       for (i = 0; i < FLD_LIMB_NUM; i++)
+               res[i] = a[i] - b[i];
+}
+
+/*
+ * fld_tinyscale scales an element a without reducing it. this could
+ * be used for conditionally change sign of an element.
+ */
+static INLINE void
+fld_tinyscale(fld_t res, const fld_t a, limb_t x)
+{
+       int i;
+       for (i = 0; i < FLD_LIMB_NUM; i++)
+               res[i] = x * a[i];
+}
+
+/*
+ * fld_scale2 is a special case of fld_tinyscale with x = 2.
+ */
+static INLINE void
+fld_scale2(fld_t res, const fld_t a)
+{
+       int i;
+       for (i = 0; i < FLD_LIMB_NUM; i++)
+               res[i] = a[i] << 1;
+}
+
+/*
+ * fld_neg is a special case of fld_tinyscale with x = -1.
+ */
+static INLINE void
+fld_neg(fld_t res, const fld_t a)
+{
+       int i;
+       for (i = 0; i < FLD_LIMB_NUM; i++)
+               res[i] = -a[i];
+}
+
+#endif
diff --git a/crypto/libeddsa/lib/limb.h b/crypto/libeddsa/lib/limb.h
new file mode 100644 (file)
index 0000000..5404ebb
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef LIMB_H
+#define LIMB_H
+
+#include <stdint.h>
+
+#include "bitness.h"
+
+#ifdef USE_64BIT
+
+typedef int64_t limb_t;
+typedef __int128_t llimb_t;
+
+#else
+
+typedef int32_t limb_t;
+typedef int64_t llimb_t;
+
+#endif
+
+
+#endif
diff --git a/crypto/libeddsa/lib/sc.c b/crypto/libeddsa/lib/sc.c
new file mode 100644 (file)
index 0000000..b58d790
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * Implementation of the ring Z/mZ for
+ *   m := 2^252 + 27742317777372353535851937790883648493.
+ *
+ * We use this ring (which is actually a field, but we are not
+ * interested in dividing here) as scalar ring for our base point
+ * B. Since B has order m the operation of Z/mZ on { xB | x in Z } is
+ * well defined.
+ *
+ * This code is public domain.
+ *
+ * Philipp Lay <philipp.lay@illunis.net>.
+ */
+
+#include <stdint.h>
+
+#include "bitness.h"
+#include "compat.h"
+#include "sc.h"
+
+
+#define K      SC_LIMB_NUM
+#define MSK    SC_LIMB_MASK
+#define LB     SC_LIMB_BITS
+
+
+
+#ifdef USE_64BIT
+
+static const limb_t con_m[K+1] = {
+       671914833335277, 3916664325105025, 1367801, 0, 17592186044416, 0 };
+
+/* mu = floor(b^(2*k) / m) */
+static const limb_t con_mu[K+1] = {
+       1586638968003385, 147551898491342, 4503509987107165, 4503599627370495,
+       4503599627370495, 255 };
+
+
+/* off = 8 * (16^64 - 1) / 15 mod m */
+const sc_t con_off = { 1530200761952544, 2593802592017535, 2401919790321849,
+                     2401919801264264, 9382499223688 };
+
+#else
+
+static const limb_t con_m[K+1] = {
+       16110573, 10012311, 30238081, 58362846, 1367801, 0, 0, 0, 0,
+       262144, 0 };
+
+static const limb_t con_mu[K+1] = {
+       1252153, 23642763, 41867726, 2198694, 17178973, 67107528, 67108863,
+       67108863, 67108863, 67108863, 255 };
+
+/* off = 8 * (16^64 - 1) / 15 mod m */
+const sc_t con_off = { 14280992, 22801768, 35478655, 38650670, 65114297,
+                      35791393, 8947848, 35791394, 8947848, 139810 };
+
+#endif
+
+
+
+
+/*
+ * sc_barrett - reduce x modulo m using barrett reduction (HAC 14.42):
+ * with the notation of (14.42) we use k = K limbs and b = 2^LB as
+ * (actual) limb size.
+ *
+ * NOTE: x must be carried and non negative.
+ *
+ * as long as x <= b^(k-1) * (b^(k+1) - mu), res will be fully
+ * reduced. this is normally true since we have (for our choices of k
+ * and b)
+ *             x < m^2 < b^(k-1) * (b^(k+1) - mu)
+ * if x is the result of a multiplication x = a * b with a, b < m.
+ *
+ * in the case of b^(k-1) * (b^(k+1) - mu) < x < b^(2k) the caller must
+ * conditionally subtract m from the result.
+ *
+ */
+static void
+sc_barrett(sc_t res, const lsc_t x)
+{
+       llimb_t carry;
+       limb_t q[K+1], r[K+1];
+       limb_t mask;
+
+       int i, j;
+
+       /* 
+        * step 1: q <- floor( floor(x/b^(k-1)) * mu / b^(k+1) )
+        */
+
+       /* calculate carry from the (k-1)-th and k-th position of floor(x/b^(k-1))*mu */
+       carry = 0;
+       for (i = 0; i <= K-1; i++)
+               carry += (llimb_t)x[K-1+i] * con_mu[K-1-i];
+       carry >>= LB;
+       for (i = 0; i <= K; i++)
+               carry += (llimb_t)x[K-1+i] * con_mu[K-i];
+
+       
+       for (j = K+1; j <= 2*K; j++) {
+               carry >>= LB;
+               for (i = j-K; i <= K; i++)
+                       carry += (llimb_t)x[K-1+i] * con_mu[j-i];
+               
+               q[j-K-1] = carry & MSK;
+       }
+       q[j-K-1] = carry >> LB;
+       
+
+       /*
+        * step 2: r <- (x - q * m) mod b^(k+1)
+        */
+
+       /* r <- q*m mod b^(k+1) */
+       for (j = 0, carry = 0; j <= K; j++) {
+               carry >>= LB;
+               
+               for (i = 0; i <= j; i++)
+                       carry += (llimb_t) q[i]*con_m[j-i];
+               
+               r[j] = carry & MSK;
+       }
+
+       /* r <- x - r mod b^(k+1) */
+       for (i = 0, carry = 0; i <= K; i++) {
+               carry = (carry >> LB) + x[i] - r[i];
+               r[i] = carry & MSK;
+       }
+
+
+       /*
+        * step 3: if (r < 0) r += b^(k+1);
+        */
+
+       /* done by ignoring the coefficient of b^(k+1) (= carry >> LB)
+        * after the last loop above.
+        */
+
+       /*
+        * step 4: if (r > m) r -= m;
+        */
+       q[0] = r[0] - con_m[0];
+       for (i = 1; i <= K; i++) {
+               q[i] = (q[i-1] >> LB) + r[i] - con_m[i];
+               q[i-1] &= MSK;
+       }
+
+       mask = ~(q[K] >> (8*sizeof(limb_t)-1));
+       for (i = 0; i <= K; i++)
+               r[i] ^= (r[i] ^ q[i]) & mask;
+
+       /*
+        * step 5: copy out and clean up
+        */
+       for (i = 0; i < K; i++)
+               res[i] = r[i];
+}
+
+
+/*
+ * sc_reduce - completely carry and reduce element e.
+ */
+void
+sc_reduce(sc_t dst, const sc_t e)
+{
+       lsc_t tmp;
+       limb_t carry;
+       int i;
+
+       /* carry e */
+       for (carry = 0, i = 0; i < K; i++) {
+               carry = (carry >> LB) + e[i];
+               tmp[i] = carry & MSK;
+       }
+       tmp[K] = carry >> LB;
+       for (i = K+1; i < 2*K; i++)
+               tmp[i] = 0;
+       
+       /* reduce modulo m */
+       sc_barrett(dst, tmp);
+}
+
+/*
+ * sc_import - import packed 256bit/512bit little-endian encoded integer
+ * to our internal sc_t format.
+ *
+ * assumes:
+ *   len <= 64
+ */
+void
+sc_import(sc_t dst, const uint8_t *src, size_t len)
+{
+       const uint8_t *endp = src + len;
+       lsc_t tmp;
+       uint64_t foo;
+       int i, fill;
+
+       fill = 0;
+       foo = 0;
+       for (i = 0; i < 2*K; i++) {
+               while (src < endp && fill < LB) {
+                       foo |= (uint64_t)*src++ << fill;
+                       fill += 8;
+               }
+               
+               tmp[i] = foo & MSK;
+
+               foo >>= LB;
+               fill -= LB;
+       }
+
+       sc_barrett(dst, tmp);
+}
+
+
+/*
+ * sc_export - export internal sc_t format to an unsigned, 256bit
+ * little-endian integer.
+ */
+void
+sc_export(uint8_t dst[32], const sc_t x)
+{
+       const uint8_t *endp = dst+32;
+       sc_t tmp;
+       uint64_t foo;
+       int fill, i;
+
+       sc_reduce(tmp, x);
+
+       for (i = 0, foo = 0, fill = 0; i < K; i++) {
+               foo |= (uint64_t)tmp[i] << fill;
+               for (fill += LB; fill >= 8 && dst < endp; fill -= 8, foo >>= 8)
+                       *dst++ = foo & 0xff;
+       }
+}
+
+/*
+ * sc_mul - multiply a with b and reduce modulo m
+ */
+void
+sc_mul(sc_t res, const sc_t a, const sc_t b)
+{
+       int i, k;
+       lsc_t tmp;
+       llimb_t carry;
+
+       carry = 0;
+
+       for (k = 0; k < K; k++) {
+               carry >>= LB;
+               for (i = 0; i <= k; i++)
+                       carry += (llimb_t) a[i] * b[k-i];
+               tmp[k] = carry & MSK;
+       }
+       
+       for (k = K; k < 2*K-1; k++) {
+               carry >>= LB;
+               for (i = k-K+1; i <= K-1; i++)
+                       carry += (llimb_t) a[i] * b[k-i];
+               tmp[k] = carry & MSK;
+       }
+       tmp[k] = carry >>= LB;
+
+       sc_barrett(res, tmp);
+}
+
+
+/*
+ * jsfdigit - helper for sc_jsf (vartime)
+ */
+static int
+jsfdigit(unsigned int a, unsigned int b)
+{
+       int u = 2 - (a & 0x03);
+       if (u == 2)
+               return 0;
+       if ( ((a & 0x07) == 3 || (a & 0x07) == 5) && (b & 0x03) == 2 )
+               return -u;
+       return u;
+}
+
+
+/*
+ * sc_jsf - calculate joint sparse form of a and b. (vartime)
+ *
+ * assumes:
+ *  a and b carried and reduced
+ *
+ * NOTE: this function runs in variable time and due to the nature of
+ * the optimization JSF is needed for (see ed_dual_scale), there is
+ * no point in creating a constant-time version.
+ *
+ * returns the highest index k >= 0 with max(u0[k], u1[k]) != 0
+ * or -1 in case u0 and u1 are all zero.
+ */
+int
+sc_jsf(int u0[SC_BITS+1], int u1[SC_BITS+1], const sc_t a, const sc_t b)
+{
+       limb_t n0, n1;
+       int i, j, k;
+
+       k = n0 = n1 = 0;
+
+       for (i = 0; i < K; i++) {
+               n0 += a[i];
+               n1 += b[i];
+
+               for (j = 0; j < LB; j++, k++) {
+                       u0[k] = jsfdigit(n0, n1);
+                       u1[k] = jsfdigit(n1, n0);
+
+                       n0 = (n0 - u0[k]) >> 1;
+                       n1 = (n1 - u1[k]) >> 1;
+               }
+       }
+       u0[k] = jsfdigit(n0, n1);
+       u1[k] = jsfdigit(n1, n0);
+
+       while (k >= 0 && u0[k] == 0 && u1[k] == 0)
+               k--;
+
+       return k;
+}
diff --git a/crypto/libeddsa/lib/sc.h b/crypto/libeddsa/lib/sc.h
new file mode 100644 (file)
index 0000000..e8212d2
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef SC_H
+#define SC_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "bitness.h"
+#include "compat.h"
+#include "limb.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef USE_64BIT
+
+#define SC_LIMB_NUM    5
+#define SC_LIMB_BITS   52
+
+#define SC_LIMB_MASK   ((1L << SC_LIMB_BITS)-1)
+
+#else
+
+#define SC_LIMB_NUM    10
+#define SC_LIMB_BITS   26
+
+#define SC_LIMB_MASK   ((1 << SC_LIMB_BITS)-1)
+
+#endif
+
+
+#define SC_BITS                (SC_LIMB_NUM * SC_LIMB_BITS)
+
+
+/* sc_t holds 260bit in reduced form */
+typedef limb_t sc_t[SC_LIMB_NUM];
+
+/* lsc_t is double in size and holds up to 520bits in reduced form */
+typedef limb_t lsc_t [2*SC_LIMB_NUM];
+
+
+
+extern const sc_t con_off;
+
+
+void   sc_reduce(sc_t dst, const lsc_t src);
+void   sc_import(sc_t dst, const uint8_t *src, size_t len);
+void   sc_export(uint8_t dst[32], const sc_t x);
+void   sc_mul(sc_t res, const sc_t a, const sc_t b);
+int    sc_jsf(int u0[SC_BITS+1], int u1[SC_BITS+1], const sc_t a, const sc_t b);
+
+
+static INLINE void
+sc_add(sc_t res, const sc_t a, const sc_t b)
+{
+       int i;
+       for (i = 0; i < SC_LIMB_NUM; i++)
+               res[i] = a[i] + b[i];
+}
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/crypto/libeddsa/lib/sha512.c b/crypto/libeddsa/lib/sha512.c
new file mode 100644 (file)
index 0000000..fc9e389
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * sha512 - calculates sha512 hash
+ *
+ * Written by Philipp Lay <philipp.lay@illunis.net> using code from
+ * LibTomCrypt by Tom St Denis as reference.
+ *
+ * This code is under public domain.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "sha512.h"
+
+static const uint64_t K[80] = {
+       0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
+       0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+       0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
+       0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+       0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
+       0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+       0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
+       0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+       0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
+       0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+       0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
+       0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+       0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
+       0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+       0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
+       0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+       0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
+       0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+       0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
+       0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+       0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
+       0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+       0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
+       0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+       0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
+       0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+       0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+
+#define ROR(x, n)      ( ((x) >> (n)) | ((x) << (64-(n))) )
+#define S0(x)          (ROR(x, 28) ^ ROR(x, 34) ^ ROR(x, 39))
+#define S1(x)          (ROR(x, 14) ^ ROR(x, 18) ^ ROR(x, 41))
+#define G0(x)          (ROR(x, 1) ^ ROR(x, 8) ^ (x >> 7))
+#define G1(x)          (ROR(x, 19) ^ ROR(x, 61) ^ (x >> 6))
+
+
+#define ROUND(i, a,b,c,d,e,f,g,h)                      \
+     t = h + S1(e) + (g ^ (e & (f ^ g))) + K[i] + W[i];        \
+     d += t;                                           \
+     h  = t + S0(a) + ( ((a | b) & c) | (a & b) )
+
+
+static void
+store_be64(uint8_t *p, uint64_t x)
+{
+       p[0] = (x >> 56) & 0xff;
+       p[1] = (x >> 48) & 0xff;
+       p[2] = (x >> 40) & 0xff;
+       p[3] = (x >> 32) & 0xff;
+       p[4] = (x >> 24) & 0xff;
+       p[5] = (x >> 16) & 0xff;
+       p[6] = (x >>  8) & 0xff;
+       p[7] = (x >>  0) & 0xff;
+}
+
+static uint64_t
+load_be64(const uint8_t *p)
+{
+       return ((uint64_t)p[0] << 56) | ((uint64_t)p[1] << 48) |
+               ((uint64_t)p[2] << 40) | ((uint64_t)p[3] << 32) |
+               ((uint64_t)p[4] << 24) | ((uint64_t)p[5] << 16) |
+               ((uint64_t)p[6] << 8) | ((uint64_t)p[7]);
+}
+
+
+static void
+compress(uint64_t state[8], const uint8_t buf[SHA512_BLOCK_SIZE])
+{
+       uint64_t W[80], t;
+       uint64_t a, b, c, d, e, f, g, h;
+       int i;
+
+       a = state[0];
+       b = state[1];
+       c = state[2];
+       d = state[3];
+       e = state[4];
+       f = state[5];
+       g = state[6];
+       h = state[7];
+
+       for (i = 0; i < 16; i++)
+               W[i] = load_be64(buf+8*i);
+
+       for (i = 16; i < 80; i++)
+               W[i] = W[i-16] + G0(W[i-15]) + W[i-7] + G1(W[i-2]);
+
+       for (i = 0; i < 80; i += 8) {
+               ROUND(i+0, a,b,c,d,e,f,g,h);
+               ROUND(i+1, h,a,b,c,d,e,f,g);
+               ROUND(i+2, g,h,a,b,c,d,e,f);
+               ROUND(i+3, f,g,h,a,b,c,d,e);
+               ROUND(i+4, e,f,g,h,a,b,c,d);
+               ROUND(i+5, d,e,f,g,h,a,b,c);
+               ROUND(i+6, c,d,e,f,g,h,a,b);
+               ROUND(i+7, b,c,d,e,f,g,h,a);
+       }
+
+       state[0] += a;
+       state[1] += b;
+       state[2] += c;
+       state[3] += d;
+       state[4] += e;
+       state[5] += f;
+       state[6] += g;
+       state[7] += h;
+}
+
+
+void
+sha512_init(struct sha512 *ctx)
+{
+       ctx->fill = 0;
+       ctx->count = 0;
+
+       ctx->state[0] = 0x6a09e667f3bcc908ULL;
+       ctx->state[1] = 0xbb67ae8584caa73bULL;
+       ctx->state[2] = 0x3c6ef372fe94f82bULL;
+       ctx->state[3] = 0xa54ff53a5f1d36f1ULL;
+       ctx->state[4] = 0x510e527fade682d1ULL;
+       ctx->state[5] = 0x9b05688c2b3e6c1fULL;
+       ctx->state[6] = 0x1f83d9abfb41bd6bULL;
+       ctx->state[7] = 0x5be0cd19137e2179ULL;
+}
+
+void
+sha512_add(struct sha512 *ctx, const uint8_t *data, size_t len)
+{
+       if (ctx->fill > 0) {
+               /* fill internal buffer up and compress */
+               while (ctx->fill < SHA512_BLOCK_SIZE && len > 0) {
+                       ctx->buffer[ctx->fill++] = *data++;
+                       len--;
+               }
+               if (ctx->fill < SHA512_BLOCK_SIZE)
+                       return;
+
+               compress(ctx->state, ctx->buffer);
+               ctx->count++;
+       }
+
+       /* ctx->fill is now zero */
+
+       while (len >= SHA512_BLOCK_SIZE) {
+               compress(ctx->state, data);
+               ctx->count++;
+               
+               data += SHA512_BLOCK_SIZE;
+               len -= SHA512_BLOCK_SIZE;
+       }
+
+       /* save rest for next time */
+       memcpy(ctx->buffer, data, len);
+       ctx->fill = len;
+}
+
+
+void
+sha512_final(struct sha512 *ctx, uint8_t out[SHA512_HASH_LENGTH])
+{
+       size_t rest;
+       int i;
+
+       rest = ctx->fill;
+       
+       /* append 1-bit to signal end of data */
+       ctx->buffer[ctx->fill++] = 0x80;
+       
+       if (ctx->fill > SHA512_BLOCK_SIZE - 16) {
+               while (ctx->fill < SHA512_BLOCK_SIZE)
+                       ctx->buffer[ctx->fill++] = 0;
+
+               compress(ctx->state, ctx->buffer);
+               ctx->fill = 0;
+       }
+       while (ctx->fill < SHA512_BLOCK_SIZE - 16)
+               ctx->buffer[ctx->fill++] = 0;
+
+       /* because rest < 128 our message length is
+        * L := 128*ctx->count + rest == (ctx->count<<7)|rest,
+        * now convert L to number of bits and write out as 128bit big-endian.
+        */
+       store_be64(ctx->buffer+SHA512_BLOCK_SIZE-16,
+                       ctx->count >> 54);
+       store_be64(ctx->buffer+SHA512_BLOCK_SIZE-8,
+                       ((ctx->count << 7) | rest) << 3);
+       
+       compress(ctx->state, ctx->buffer);
+
+
+       for (i = 0; i < 8; i++)
+               store_be64(out + 8*i, ctx->state[i]);
+}
diff --git a/crypto/libeddsa/lib/sha512.h b/crypto/libeddsa/lib/sha512.h
new file mode 100644 (file)
index 0000000..a4e1dbe
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef SHA512_H
+#define SHA512_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SHA512_BLOCK_SIZE      128
+#define SHA512_HASH_LENGTH     64
+
+
+struct sha512 {
+       uint64_t        state[8];
+       uint64_t        count;
+
+       uint8_t         buffer[SHA512_BLOCK_SIZE];
+       size_t          fill;
+};
+
+void sha512_init(struct sha512 *ctx);
+void sha512_add(struct sha512 *ctx, const uint8_t *data, size_t len);
+void sha512_final(struct sha512 *ctx, uint8_t out[SHA512_HASH_LENGTH]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/crypto/libeddsa/lib/x25519.c b/crypto/libeddsa/lib/x25519.c
new file mode 100644 (file)
index 0000000..6fc6614
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * implement x25519 diffie-hellman from [1].
+ *
+ * This code is public domain.
+ *
+ * Philipp Lay <philipp.lay@illunis.net>
+ *
+ * References:
+ * [1] Curve25519: new Diffie-Hellman speed records, 2006/02/09, Bernstein.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "eddsa.h"
+
+#include "fld.h"
+#include "burnstack.h"
+
+#include "ed.h"
+
+
+/*
+ * structure for a point of the elliptic curve in montgomery form
+ * without it's y-coordinate.
+ */
+struct mg {
+       fld_t   x;
+       fld_t   z;
+};
+
+
+/*
+ * ctmemswap - helper function to conditionally swap a with b
+ */
+static void
+ctmemswap(void *a, void *b, size_t len, uint8_t mask)
+{
+       uint8_t *pa = (uint8_t*)a;
+       uint8_t *pb = (uint8_t*)b;
+       uint8_t *endp = pa + len;
+       uint8_t delta;
+
+       while (pa < endp) {
+               delta = (*pa ^ *pb) & mask;
+               *pa++ ^= delta;
+               *pb++ ^= delta;
+       }
+}
+
+
+
+/*
+ * montgomery - calculate montgomery's double-and-add formula
+ *
+ * input: A, B, C := A-B with z=1
+ * output: A <- 2*A, B <- A+B
+ *
+ */
+static void
+montgomery(struct mg *A, struct mg *B, const struct mg *C)
+{
+       fld_t sumA, subA, sqsumA, sqsubA;
+       fld_t sumB, subB;
+       fld_t T1, T2, T3;
+       
+       /* calculate 2*A */
+       fld_add(sumA, A->x, A->z);
+       fld_sq(sqsumA, sumA);
+       
+       fld_sub(subA, A->x, A->z);
+       fld_sq(sqsubA, subA);
+       
+       fld_mul(A->x, sqsubA, sqsumA);
+       
+       fld_sub(T1, sqsumA, sqsubA);
+       fld_scale(T2, T1, 121665);
+       fld_add(T2, T2, sqsumA);
+       fld_mul(A->z, T1, T2);
+
+       /* calculate A + B */
+       fld_add(sumB, B->x, B->z);
+       fld_sub(subB, B->x, B->z);
+
+       fld_mul(T1, subA, sumB);
+       fld_mul(T2, sumA, subB);
+       
+       fld_add(T3, T1, T2);
+       fld_sq(B->x, T3);
+
+       fld_sub(T3, T1, T2);
+       fld_sq(T3, T3);
+       fld_mul(B->z, T3, C->x);
+}
+
+
+/*
+ * mg_scale - calculates x * P with montgomery formula.
+ *
+ * assumes:
+ *   out != P
+ *   P->z must be 1
+ */
+static void
+mg_scale(struct mg *out, const struct mg *P, const uint8_t x[X25519_KEY_LEN])
+{
+       struct mg T;
+       int8_t foo;
+       int i, j;
+
+       fld_set0(out->x, 1);
+       fld_set0(out->z, 0);
+       memcpy(&T, P, sizeof(struct mg));
+       
+       for (i = X25519_KEY_LEN-1; i >= 0; i--) {
+               foo = x[i];
+               for (j = 8; j > 0; j--, foo <<= 1) {
+                       ctmemswap(out, &T, sizeof(struct mg), foo >> 7);
+                       montgomery(out, &T, P);
+                       ctmemswap(out, &T, sizeof(struct mg), foo >> 7);
+               }
+       }
+}
+
+
+/*
+ * do_x25519 - calculates x25519 diffie-hellman using montgomery form
+ */
+static void
+do_x25519(uint8_t out[X25519_KEY_LEN],
+            const uint8_t scalar[X25519_KEY_LEN],
+            const uint8_t point[X25519_KEY_LEN])
+{
+       struct mg res, P;
+       uint8_t s[X25519_KEY_LEN];
+
+       memcpy(s, scalar, X25519_KEY_LEN);
+       s[0] &= 0xf8;
+       s[31] &= 0x7f;
+       s[31] |= 0x40;
+       
+       fld_import(P.x, point);
+       fld_set0(P.z, 1);
+       
+       mg_scale(&res, &P, s);
+
+       fld_inv(res.z, res.z);
+       fld_mul(res.x, res.x, res.z);
+       fld_export(out, res.x);
+}
+
+
+/*
+ * do_x25519_base - calculate a x25519 diffie-hellman public value
+ *
+ */
+
+static void
+do_x25519_base(uint8_t out[X25519_KEY_LEN],
+              const uint8_t scalar[X25519_KEY_LEN])
+{
+       uint8_t tmp[X25519_KEY_LEN];
+
+       sc_t x;
+       struct ed R;
+       fld_t u, t;
+
+       /*
+        * clear bits on input and import it as x
+        */
+       memcpy(tmp, scalar, X25519_KEY_LEN);
+       tmp[0] &= 0xf8;
+       tmp[31] &= 0x7f;
+       tmp[31] |= 0x40;
+
+       sc_import(x, tmp, sizeof(tmp));
+
+
+       /*
+        * scale our base point on edwards curve
+        */
+       ed_scale_base(&R, x);
+
+
+       /*
+        * extract montgomery coordinate u from edwards point R
+        */
+
+       /* u <- (z + y) / (z - y) */
+       fld_sub(t, R.z, R.y);
+       fld_inv(t, t);
+       fld_add(u, R.z, R.y);
+       fld_mul(u, u, t);
+
+
+       fld_export(out, u);
+}
+
+
+/*
+ * x25519_base - wrapper around do_x25519_base with stack cleaning
+ */
+void
+x25519_base(uint8_t out[X25519_KEY_LEN],
+           const uint8_t scalar[X25519_KEY_LEN])
+{
+       do_x25519_base(out, scalar);
+       burnstack(2048);
+}
+
+
+
+
+/* x25519 - wrapper for do_x25519 with stack-cleanup */
+void
+x25519(uint8_t out[X25519_KEY_LEN],
+       const uint8_t scalar[X25519_KEY_LEN],
+       const uint8_t point[X25519_KEY_LEN])
+{
+       do_x25519(out, scalar, point);
+       burnstack(2048);
+}
+
+
+
+
+
+/*
+ * Obsolete Interface, this will be removed in the future.
+ */
+
+
+/*
+ * DH - stack-cleanup wrapper for do_x25519 (obsolete interface)
+ */
+void
+DH(uint8_t out[X25519_KEY_LEN],
+   const uint8_t sec[X25519_KEY_LEN],
+   const uint8_t point[X25519_KEY_LEN])
+{
+       do_x25519(out, sec, point);
+       burnstack(2048);
+}
diff --git a/crypto/libeddsa/sign.c b/crypto/libeddsa/sign.c
new file mode 100644 (file)
index 0000000..246c932
--- /dev/null
@@ -0,0 +1,477 @@
+#define _POSIX_C_SOURCE 200809L
+
+/* general zpm sign function */
+
+/* read key, export key, import key, sign, export signature, import
+ * signature, verify signature
+ */
+
+/* import and export is base64 encoded */
+
+/* -v verify
+ * -s sign
+ * -g generate key
+ * -e extract public key
+ *
+ * -o output file
+ *
+ * -p read key from file
+ * -P read public key from argument to -P
+ * -S read secret key from argument
+ * -m message from argument
+ * -h message is hex encoded
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <time.h>
+
+/* linux specific for getrandom */
+#include <sys/random.h>
+
+#include "eddsa.h"
+#include "sha512.h"
+
+#define VERIFY 1
+#define SIGN 2
+#define GENKEY 3
+#define EXTRACT 4
+#define PUBKEY 5
+
+static void hexdump(void *src, size_t len) {
+       unsigned char *b = src;
+       while (len--) {
+               printf("%02x", *b++);
+       }
+       printf("\n");
+}
+
+static char hexchars[] = "0123456789abcdefABCDEF";
+
+static void hex(char *dst, uint8_t *src, size_t len) {
+       while (len--) {
+               dst[0] = hexchars[(src[0]>>4)&0xf];
+               dst[1] = hexchars[src[0]&0xf];
+               dst+=2;
+               src++;
+       }
+}
+
+static void hexbin(uint8_t *dst, unsigned char *src, size_t len) {
+       size_t i;
+       int x;
+
+       for (i=0; i<len; i+=2) {
+               sscanf((const char *)src+i, "%02x", &x);
+               dst[i/2] = x;
+       }
+}
+
+void *map(char *file, size_t *size) {
+       int fd, rv;
+       void *m;
+       struct stat st;
+
+       fd = open(file, O_RDONLY);
+       if (fd == -1) {
+               return NULL;
+       }
+
+       rv = fstat(fd, &st);
+       if (rv == -1) {
+               close(fd);
+               return NULL;
+       }
+
+       m = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if (m == MAP_FAILED) {
+               return 0;
+       }
+
+       close(fd);
+       *size = st.st_size;
+       return m;
+}
+
+ssize_t readbytes(char *dest, char *file, size_t n) {
+       char *m;
+       size_t fs;
+
+       m = map(file, &fs);
+       if (!m) {
+               return -1;
+       }
+       if (n > fs) {
+               n = fs;
+       }
+
+       size_t pk = strspn(m, hexchars);
+       pk /= 2;
+       if (n > pk) {
+               n = pk;
+       }
+
+       hexbin(dest, m, n*2);
+       munmap(m, fs);
+       return n;
+}
+
+
+/* private key format is:
+ * "ZPMS" 4 byte magic "ZPMS"
+ * byte 0x01 = version 1
+ * byte 0x01 = private key
+ * byte 0x01 = chacha encrypted, 0x00 = plain/raw key bytes
+ * byte 0x00 reserved, probably "key usage"
+ * 32 bytes private key
+ * 24 bytes reserved
+ * sub keys, public keys?  No point to the public key, since it's
+ * always derivable.  could have 16 bytes of IV for chacha to encrypt.
+ *
+ * entire thing is then hexencoded, but 
+ */
+
+/* public key format is:
+ * "ZPMS" 4 byte magic "ZPMS"
+ * 0x01   1 byte version
+ * 0x02   1 byte "public key packet"
+ * 0x00   1 byte reserved
+ * 0x00   1 byte reserved
+ * 0x..  32 bytes public key
+ * 0x..  24 bytes reserved
+ * 0x..     revocation signatures
+ * 0x..     user id packets
+ * 0x..     certification signatures
+ * 0x..     sub key packets
+ */
+
+/* timestamps are 8 byte little endian integers of seconds since
+ * the epoch.  or unix time, or some such.  Times are a mess.
+ * Unix time is leap second unaware, and ambiguous during leap seconds.
+ * UTC requires a database of leap seconds for past time, and the
+ * specified second in the future possibly changes.
+ * TAI is good, but currently 37 seconds behind UTC, which is just weird
+ */
+
+/* signature items from openpgp */
+/* revokable flag
+ * 0-255 trust level
+ *
+ */
+
+/* signature format:
+ * "ZPMS" 4 byte magic "ZPMS"
+ * 0x01   1 byte version
+ * 0x03   1 byte "signature packet"
+ * 0x00   1 byte reserved
+ * 0x00   1 byte reserved
+ * 0x..   8 bytes timestamp of signature time
+ * 0x..   8 bytes timestamp of signature expiration, 0 if none
+ * 0x..  64 bytes of actual signature
+ * 0x..  32 bytes of public key making the signature
+ * 0x..   8 bytes reserved
+ * Total is 128 bytes.
+ */
+
+/* expires time could probably be 4 bytes as an offset from created.
+ * That would free up 4 bytes.  Sign time could probably be four
+ * bytes with an epoch of say 2019-01-01, since negative times don't
+ * really make any sense, that give more than 100 years, and frees
+ * up another 4 bytes
+ *
+ * version is zero until this proof of concept is better validated
+ */
+struct signature {
+       char magic[4]; /* magic ZPMS */
+       char info[4]; /* version = 0, type=3, 1 byte trust, 1 byte reserved */
+       uint64_t signtime; /* unix time */
+       uint64_t expires; /* unix time, 0 = none */
+       char sig[64]; 
+       char pub[32];
+       char reserved[8];
+};
+
+struct key {
+       char magic[4]; /* "ZPMS" */
+       char info[4]; /* version, type = 0x02, reserved, reserved */
+       char key[32];
+       uint64_t created;
+       uint64_t expires;
+       char reserved[8];
+       char sig[64]; /* zeroes for a private key, or fill in, doesn't matter*/
+       /* could fill in the first 32 bytes of sig with the public key
+        * if this is a private key, then you don't need another structure */
+};
+
+int create_key(struct key *sk) {
+       char info[] = { 0, 1, 0, 0 };
+       memcpy(sk->magic, "ZPMS", 4);
+       memcpy(sk->info, info, 4);
+       getrandom(sk->key, sizeof sk->key, 0);
+       ed25519_genpub(sk->sig, sk->key);
+       sk->created = time(NULL);
+       memset(sk->reserved, 0, 8);
+       memset(sk->sig+32, 0, 32);
+       return 1;
+}
+
+int derive_pubkey(struct key *pk, struct key *sk) {
+       char info[] = { 0, 2, 0, 0 };
+
+       memcpy(sk->magic, "ZPMS", 4);
+       memcpy(sk->info, info, 4);
+       ed25519_genpub(pk->key, sk->key);
+       pk->created = sk->created;
+       pk->expires = sk->expires;
+       memset(sk->reserved, 0, 8);
+
+       ed25519_sign(pk->sig, sk->key, pk->sig, sk->info, 52);
+       return 1;
+
+}
+
+/* if reserved used 16 bytes for signtime and expires, and we added
+ * 64 bytes as a signature, a public key could include it's own self
+ * signature, and a key would be 128 bytes, as would a signature.  This
+ * would make all structures 128 bytes.
+ */
+
+int read_secret_key(uint8_t *sec, uint8_t *pub, char *file) {
+       uint8_t sk[64];
+       
+       readbytes(sk, file, sizeof sk);
+       if (sk[4] != 1 || sk[5] != 1) {
+               printf("magic: ");
+               hexdump(sk, 16);
+               return 0;
+       }
+       memcpy(sec, sk+8, 32);
+       //printf("sec: ");
+       //hexdump(sec, 32);
+
+       if (pub) {
+               ed25519_genpub(pub, sec);
+       //      printf("pub: ");
+       //      hexdump(pub, 32);
+       }
+
+       return 1;
+}
+
+/* private key format is:
+ * "ZPMS" 4 byte magic "ZPMS"
+ * byte 0x01 = version 1
+ * byte 0x01 = private key
+ * byte 0x01 = chacha encrypted, 0x00 = plain/raw key bytes
+ * byte 0x00 reserved, probably "key usage"
+ * 32 bytes private key
+ * 24 bytes reserved
+ * sub keys, public keys?  No point to the public key, since it's
+ * always derivable.  could have 16 bytes of IV for chacha to encrypt.
+ *
+ * entire thing is then hexencoded, but 
+ */
+
+int write_secret_key(uint8_t *sec, int flags, int fd) {
+       uint8_t skh[128] = "5A504D5301010000"; /* ZPMS 1 1 0 0 */
+
+       if (flags & 0x01) {
+               skh[13] = '1';
+       }
+       //hexdump(sec, 32);
+       hex(skh + 16, sec, 32);
+       memset(skh + 80, '0', 48);
+       write(fd, skh, sizeof skh);
+       memset(skh, 0, sizeof skh);
+
+       return 1;
+}
+
+int main(int ac, char *av[]) {
+       int option;
+       int mode = 0;
+       char *outfile = 0;
+       uint8_t pub[ED25519_KEY_LEN];
+       /* TODO should use mlock()ed memory for the secret key */
+       uint8_t sec[ED25519_KEY_LEN];
+       uint8_t sig[ED25519_SIG_LEN];
+       void *message = 0;
+       char *messagefile = 0;
+       char *messagestring = 0;
+       char messagehash[SHA512_HASH_LENGTH];
+       char *keystring = 0, *keyfile = 0;
+       unsigned char *sigstring = 0, *sigfile = 0;
+       char *passphrase = 0;
+       size_t mlen;
+       int rawsig = 0, hexencoded = 0;
+       int debug = 0;
+
+       while ((option = getopt(ac, av, "o:vS:f:sgek:K:rm:hd")) != -1) {
+               switch (option) {
+                       case 'o': outfile = optarg; break;
+                       case 'v': mode = VERIFY; break;
+                       case 'S': sigstring = optarg; break;
+                       case 'f': sigfile = optarg; break;
+                       case 's': mode = SIGN; break;
+                       case 'g': mode = GENKEY; break;
+                       case 'e': mode = EXTRACT; break;
+                       case 'k': keystring = optarg; break;
+                       case 'K': keyfile = optarg; break;
+                       case 'p': passphrase = optarg; break;
+                       case 'm': messagestring = optarg; break;
+                       case 'h': hexencoded = 1; break;
+                       case 'r': rawsig = 1; break;
+                       case 'd': debug++; break;
+                       default:
+                                 exit(EXIT_FAILURE);
+                                 break;
+               }
+       }
+
+       if (sigfile) {
+               ssize_t r;
+               memset(sig, 0, sizeof sig);
+               r = readbytes(sig, sigfile, sizeof sig);
+               if (r == -1) {
+                       return 8;
+               }
+               if ((size_t)r < sizeof sig) {
+                       return 7;
+               }
+       } else if (sigstring) {
+               memset(sig, 0, sizeof sig);
+               hexbin(sig, sigstring, sizeof sig);
+       }
+
+       if (keystring) {
+               memset(sec, 0, sizeof sec);
+               hexbin(sec, keystring, strlen(keystring));
+               ed25519_genpub(pub, sec);
+               if (debug) {
+                       printf("sec:\n"); hexdump(sec, sizeof sec);
+               }
+       } else if (keyfile) {
+               read_secret_key(sec, pub, keyfile);
+               //hexdump(sec, sizeof sec);
+               //hexdump(pub, sizeof pub);
+       }
+
+       if (mode == PUBKEY) {
+               /* want to print the pubkey only */
+               hexdump(pub, sizeof pub);
+               exit(0);
+       }
+
+       /* need to be able to encrypt the private keys */
+       /* use chacha */
+       if (mode == GENKEY) {
+               /* a private key is just 32 random bytes */
+               getrandom(sec, sizeof sec, 0);
+               ed25519_genpub(pub, sec);
+               ed25519_sign(sig, sec, pub, sec, sizeof sec);
+               //int rv = ed25519_verify(sig, pub, sec, sizeof sec);
+               if (outfile) {
+                       int fd;
+                       fd = open(outfile, O_WRONLY|O_CREAT, 0600);
+                       if (fd == -1) {
+                               perror("can't open outfile");
+                               exit(EXIT_FAILURE);
+                       }
+                       write_secret_key(sec, 0, fd);
+                       close(fd);
+               } else {
+                       write_secret_key(sec, 0, 1);
+               }
+       }
+
+       /* set up the message data */
+       if (mode == SIGN || mode == VERIFY) {
+               messagefile = av[optind];
+               if (messagefile) {
+                       message = map(messagefile, &mlen);
+                       if (!message) {
+                               return 9;
+                       }
+               } else if (messagestring) {
+                       message = messagestring;
+                       if (hexencoded) {
+                               mlen = strlen(messagestring)/2;
+                               message = malloc(mlen);
+                               if (!message) {
+                                       return 10;
+                               }
+                               hexbin(message, messagestring, mlen*2);
+                       } else {
+                               mlen = strlen(messagestring);
+                       }
+               } else {
+                       return 2;
+               }
+               if (!message) {
+                       return 3;
+               }
+       }
+
+       if (mode == SIGN) {
+               struct signature s;
+               s.magic[0] = 'Z';
+               s.magic[1] = 'P';
+               s.magic[2] = 'M';
+               s.magic[3] = 'S';
+               s.info[0] = 1;
+               s.info[1] = 1;
+               s.info[2] = 0;
+               s.info[3] = 0;
+               s.signtime = time(NULL);
+               s.expires = 0;
+               memset(s.reserved, 0, 8);
+               if (!rawsig) {
+                       struct sha512 hash;
+                       sha512_init(&hash);
+                       sha512_add(&hash, message, mlen);
+                       sha512_add(&hash, (uint8_t *)&s.signtime, sizeof s.signtime);
+                       sha512_add(&hash, (uint8_t *)&s.expires, sizeof s.expires);
+                       sha512_add(&hash, s.info, sizeof s.info);
+                       sha512_final(&hash, messagehash);
+                       message = messagehash;
+               }
+
+               if (message == 0) {
+                       return 5;
+               }
+
+               ed25519_sign(sig, sec, pub, message, mlen);
+               memcpy(s.sig, sig, sizeof sig);
+               memcpy(s.pub, pub, sizeof pub);
+               if (rawsig) {
+                       hexdump(sig, sizeof sig);
+               } else {
+                       hexdump(&s, sizeof s);
+               }
+       }
+
+       if (mode == VERIFY) {
+               fprintf(stderr, "sig: ");
+               hexdump(sig, sizeof sig);
+               int rv = ed25519_verify(sig, pub, message, mlen);
+               if (rv) {
+                       fprintf(stderr, "verified\n");
+                       return 0;
+               } else {
+                       fprintf(stderr, "not verified\n");
+                       return 6;
+               }
+       }
+
+       if (message && messagefile) {
+               munmap(message, mlen);
+       }
+
+       return 0;
+}